/*======================================================================================

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkPluginCreator.cxx
	Version:		$Revision: 2109 $
	Date:			$Date: 2011-11-29 13:00:15 +0100 (Di, 29 Nov 2011) $

	Copyright (c) 2010-2011
	Pattern Recognition Lab, 
    University Erlangen-Nuremberg, Germany
    All rights reserved.

	This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
	See RITKCopyright.txt for more information.

	http://www5.informatik.uni-erlangen.de/research/software/ritk

========================================================================================*/

#include "ritkManager.h"

#include "ritkPluginCreator.h"

#include <QInputDialog>
#include <QTextStream>
#include <QMessageBox>

#include <iostream>

namespace ritk
{


PluginCreator::PluginCreator()
{
	// Initialize plugin type (GUI preset) 
	m_PluginType = PluginCreator::ApplicationPlugin;

	// Set parent source directory of the RITK plugins
	SetRITKPluginDirectory();

	QDir CurrentPath = QApplication::applicationDirPath();
	CurrentPath.cdUp();
	CurrentPath.cdUp();

	// Set parent directory of the RITK plugin template files
	m_RITKPluginTemplatesDirectory.setPath(CurrentPath.absolutePath().append(QDir::separator()).append("PluginTemplates"));
}

PluginCreator::~PluginCreator()
{
}

void PluginCreator::SetRITKPluginDirectory()
{
	// Set parent source directory of the RITK plugins
	// by reading from config file that was previously created from CMake 
	QDir CurrentPath = QApplication::applicationDirPath();
	QString ConfigFileName = "config.txt";
	CurrentPath.cdUp();
	
	QString ConfigFilePath = CurrentPath.absolutePath().append(QDir::separator()).append(ConfigFileName);
	if(!QFile::exists(ConfigFilePath))
	{
		std::cerr << "Could not find file \"" << ConfigFileName.toStdString() << "\" in path " << CurrentPath.absolutePath().toStdString() << "!" << std::endl;
		std::cerr << "RITK source directory cannot be located without that file. Exit program." << std::endl;
		exit(0);
	}

	QFile ConfigFile(ConfigFilePath);
	ConfigFile.open(QIODevice::ReadOnly | QIODevice::Text);
	QTextStream InStream(&ConfigFile);
	while(!InStream.atEnd())
	{
		QString CurrentLine = InStream.readLine();
		m_RITKPluginDirectory = CurrentLine;
		break;
	}
		ConfigFile.close();
}

void PluginCreator::CreatePlugin(PluginType Type)
{
	// Check if directory of new plugin exists, if yes exit program, if not create directory
	if(!m_PluginDirectory.exists())
	{
		m_PluginDirectory.cdUp();
		m_PluginDirectory.mkpath(m_PluginName);
		m_PluginDirectory.cd(m_PluginName);

		CreateCMakeFileFromTemplate();
		switch(Type)
		{
			case FilterPlugin:
				CreateFilterPlugin();
				break;

			case ApplicationPlugin:
				CreateApplicationPlugin();
				break;
			case SourcePlugin:
				CreateSourcePlugin();
				break;
		}
		QMessageBox::information(NULL, "PluginCreator", "Plugin was created.", QMessageBox::Ok);
	}
	else
	{
		QMessageBox::warning(NULL, "PluginCreator", "Plugin directory already exists.", QMessageBox::Ok);
	}
}

void PluginCreator::CreateFilterPlugin()
{
	// Create plugin files by modifying the respective template files
	CreateFileFromTemplate("ImageFilter.h",					m_PluginName + "ImageFilter.h");
	CreateFileFromTemplate("ImageFilter.txx",				m_PluginName + "ImageFilter.txx");
	CreateFileFromTemplate("RImageFilter.h",				m_PluginName + "RImageFilter.h");
	CreateFileFromTemplate("RImageFilter.txx",				m_PluginName + "RImageFilter.txx");
	CreateFileFromTemplate("ImageFilterPlugin.h",			m_PluginName + "ImageFilterPlugin.h");
	CreateFileFromTemplate("ImageFilterPlugin.cxx",			m_PluginName + "ImageFilterPlugin.cxx");
	CreateFileFromTemplate("ImageFilterPluginFactory.h",	m_PluginName + "ImageFilterPluginFactory.h");
	CreateFileFromTemplate("ImageFilterPluginFactory.cxx",	m_PluginName + "ImageFilterPluginFactory.cxx");
	CreateFileFromTemplate("FilterWidget.h",				m_PluginName + "FilterWidget.h");
	CreateFileFromTemplate("FilterWidget.cxx",				m_PluginName + "FilterWidget.cxx");
	CreateFileFromTemplate("FilterWidget.ui",				m_PluginName + "FilterWidget.ui");
	CreateFileFromTemplate("Instantiations.cxx",			"Instantiations.cxx");

	// Add the subdirectory to the parent CMakeLists
	PropagateNewPlugin();
}

void PluginCreator::CreateApplicationPlugin()
{
	// Create plugin files by modifying the respective template files
	CreateFileFromTemplate("Plugin.cxx",				m_PluginName + "Plugin.cxx");
	CreateFileFromTemplate("Plugin.h",					m_PluginName + "Plugin.h");
	CreateFileFromTemplate("PluginFactory.cxx",			m_PluginName + "PluginFactory.cxx");
	CreateFileFromTemplate("PluginFactory.h",			m_PluginName + "PluginFactory.h");
	CreateFileFromTemplate("Widget.cxx",				m_PluginName + "Widget.cxx");
	CreateFileFromTemplate("Widget.h",					m_PluginName + "Widget.h");
	CreateFileFromTemplate("Widget.ui",					m_PluginName + "Widget.ui");

	// Add the subdirectory to the parent CMakeLists
	PropagateNewPlugin();
}


void PluginCreator::CreateSourcePlugin()
{
	// Create plugin files by modifying the respective template files
	CreateFileFromTemplate("SourcePlugin.h",					m_PluginName +	"SourcePlugin.h");
	CreateFileFromTemplate("SourcePlugin.cxx",					m_PluginName +	"SourcePlugin.cxx");
	CreateFileFromTemplate("SourcePluginFactory.h",				m_PluginName +	"SourcePluginFactory.h");
	CreateFileFromTemplate("SourcePluginFactory.cxx",			m_PluginName +	"SourcePluginFactory.cxx");
	CreateFileFromTemplate("SourcePluginWidget.h",				m_PluginName +	"SourcePluginWidget.h");
	CreateFileFromTemplate("SourcePluginWidget.cxx",			m_PluginName +	"SourcePluginWidget.cxx");
	CreateFileFromTemplate("SourcePluginWidget.ui",				m_PluginName +	"SourcePluginWidget.ui");
	CreateFileFromTemplate("SourcePluginRImageSource.h",		m_PluginName +	"SourcePluginRImageSource.h");
	CreateFileFromTemplate("SourcePluginRImageSource.txx",		m_PluginName +	"SourcePluginRImageSource.txx");
	CreateFileFromTemplate("Instantiations.cxx",				m_PluginName +	"Instantiations.cxx");

	// Add the subdirectory to the parent CMakeLists
	PropagateNewPlugin();
}

void PluginCreator::SetPluginType(PluginType Type, bool isOpenSource)
{
	m_IsOpenSource = isOpenSource;
	m_PluginType = Type;
}

void PluginCreator::SetPluginName(QString PluginName)
{
	m_PluginName = PluginName;
	
	QString distri;
	if(m_IsOpenSource)
	{
		distri = "OpenSource";
	}
	else
	{
		distri = "ClosedSource";
	}

	// Set directory for new plugin
	switch(m_PluginType)
	{
		case FilterPlugin:
			m_PluginDirectory.setPath(m_RITKPluginDirectory.absolutePath().append(QDir::separator()).append(distri).append(QDir::separator()).append("FilterPlugins").append(QDir::separator()).append(m_PluginName));
			break;
		case ApplicationPlugin:
			m_PluginDirectory.setPath(m_RITKPluginDirectory.absolutePath().append(QDir::separator()).append(distri).append(QDir::separator()).append("ApplicationPlugins").append(QDir::separator()).append(m_PluginName));
			break;
		case SourcePlugin:
			m_PluginDirectory.setPath(m_RITKPluginDirectory.absolutePath().append(QDir::separator()).append(distri).append(QDir::separator()).append("SourcePlugins").append(QDir::separator()).append(m_PluginName));
			break;
	}

	return;
}

void PluginCreator::SetPluginDescription(QString Description)
{
	m_PluginDescription = Description;

	return;
}

void PluginCreator::CreateFileFromTemplate(QString InFilename, QString OutFilename)
{	
	// Read template file, copy it, and modify the keywords
	QString read, write;

	switch(m_PluginType)
	{
		case ApplicationPlugin:
			read = m_RITKPluginTemplatesDirectory.absolutePath().append((QString)"/PluginTemplates/ApplicationPluginTemplates/").append(InFilename);
			break;

		case FilterPlugin:
			read = m_RITKPluginTemplatesDirectory.absolutePath().append((QString)"/PluginTemplates/FilterPluginTemplates/").append(InFilename);
			break;
		case SourcePlugin:
			read = m_RITKPluginTemplatesDirectory.absolutePath().append((QString)"/PluginTemplates/SourcePluginTemplates/").append(InFilename);
	}

	write = m_PluginDirectory.absolutePath().append(QDir::separator()).append(OutFilename);

	if(!QFile::exists(read))
	{
		std::cerr << "Could not find file \"" << InFilename.toStdString() << "\" for reading." << std::endl;
	}

	QFile InFile(read);
	InFile.open(QIODevice::ReadOnly | QIODevice::Text);
	QTextStream InStream(&InFile);
	
	QFile OutFile(write);
	OutFile.open(QIODevice::WriteOnly | QIODevice::Text);
	QTextStream OutStream(&OutFile);

	while(!InStream.atEnd())
	{
		QString line = InStream.readLine();

		line.replace("__PLUGIN_NAME__", m_PluginName);
		line.replace("__PLUGIN_DESCRIPTION__", m_PluginDescription);
		
		OutStream << line << endl;
	}

	InFile.close();
	OutFile.close();	

	return;
}

void PluginCreator::PropagateNewPlugin()
{
	m_PluginDirectory.cdUp();
	QString write = m_PluginDirectory.absolutePath().append(QDir::separator()).append("CMakeLists.txt");

	m_PluginDirectory.cd(m_PluginName);

	if(!QFile::exists(write))
	{
		std::cerr << "Could not find CMakeLists.txt" << std::endl;
	}
	
	QFile OutFile(write);
	OutFile.open(QIODevice::Append | QIODevice::Text);
	QTextStream OutStream(&OutFile);

	OutStream << "ADD_PLUGIN(" << m_PluginName << "			" << m_PluginName << "			" << "ON		CROSS)" << endl;

	OutFile.close();	
}

void PluginCreator::SetLibrariesCMake(QStringList libraries)
{
	m_Libraries = libraries;
}

void PluginCreator::SetFindCMake(QStringList finds)
{
	m_Finds = finds;
}


void PluginCreator::CreateCMakeFileFromTemplate()
{	
	// Read template file, copy it, and modify the keywords
	QString read, write, filename;
	filename = "CMakeLists.txt";

	switch(m_PluginType)
	{
		case ApplicationPlugin:
			read = m_RITKPluginTemplatesDirectory.absolutePath().append((QString)"/PluginTemplates/ApplicationPluginTemplates/").append(filename);
			break;

		case FilterPlugin:
			read = m_RITKPluginTemplatesDirectory.absolutePath().append((QString)"/PluginTemplates/FilterPluginTemplates/").append(filename);
			break;
		case SourcePlugin:
			read = m_RITKPluginTemplatesDirectory.absolutePath().append((QString)"/PluginTemplates/SourcePluginTemplates/").append(filename);
	}

	write = m_PluginDirectory.absolutePath().append(QDir::separator()).append(filename);

	if(!QFile::exists(read))
	{
		std::cerr << "Could not find file \"" << filename.toStdString() << "\" for reading." << std::endl;
	}

	QFile InFile(read);
	InFile.open(QIODevice::ReadOnly | QIODevice::Text);
	QTextStream InStream(&InFile);
	
	QFile OutFile(write);
	OutFile.open(QIODevice::WriteOnly | QIODevice::Text);
	QTextStream OutStream(&OutFile);

	OutStream << "cmake_minimum_required(VERSION 2.6)\n" << endl;
	for(int i=0; i<m_Finds.size(); ++i)
		OutStream << m_Finds.at(i) << endl;

	while(!InStream.atEnd())
	{
		QString line = InStream.readLine();

		line.replace("__PLUGIN_NAME__", m_PluginName);
		line.replace("__PLUGIN_DESCRIPTION__", m_PluginDescription);
		
		OutStream << line << endl;

		if(line.compare("TARGET_LINK_LIBRARIES(${" + m_PluginName + "_LIBRARY}") == 0)
		{
			for(int i=0; i<m_Libraries.size(); ++i)
				OutStream << m_Libraries.at(i);
		}
	}

	InFile.close();
	OutFile.close();	

	return;
}


}