/***************************************************************************
 *   Copyright (C) 1992-2007 Trolltech ASA								   *
 *                                                                         *
 *   Copyright (C) 2005-2007 by Tarek Saidi                                *
 *   tarek.saidi@arcor.de                                                  *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; version 2 of the License.               *
 *                                                                         *
 *   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 the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

#include "plugins/interfaces/IFileDialog.h"
#include "plugins/interfaces/IKdeInit.h"
#include "plugins/interfaces/IGnomeInit.h"


#include <QTranslator>
#include <QLibraryInfo>
#include <QPluginLoader>
#include "mainwindow.h"
#include "main.h"
#if defined(Q_WS_X11) && defined(GLOBAL_AUTOTYPE)
	#include "Application_X11.h"
#endif

using namespace std;

KpxConfig *config;
QString  AppDir;
QString HomeDir;
QString DataDir;
QString PluginLoadError;
bool TrActive;
QString DetailViewTemplate;
bool EventOccurred;
bool EventOccurredBlock = false;

QPixmap* EntryIcons;
IIconTheme* IconLoader=NULL;


int main(int argc, char **argv)
{
	QApplication* app=NULL;
	initAppPaths(argc,argv);
	CmdLineArgs args;
	if(!args.preparse(argc,argv)){ // searches only for the -cfg parameter
		qCritical(CSTR( args.error().append("\n") ));
		args.printHelp();
		return 1;
	}

	//Load Config
	QString IniFilename;
	if(args.configLocation().isEmpty()){
		if(!QDir(HomeDir).exists()){
			QDir conf(QDir::homePath());
			if(!QDir().mkpath(HomeDir))
				qWarning("Warning: Could not create directory '%s'", CSTR(HomeDir));
		}
		IniFilename=HomeDir+"/config";
	}
	else
		IniFilename=args.configLocation();

	config = new KpxConfig(IniFilename);
	fileDlgHistory.load();
	
	// PlugIns
#ifdef Q_WS_X11
	if(config->integrPlugin()!=KpxConfig::NoIntegr){
		QString LibName="libkeepassx-";
		if(config->integrPlugin()==KpxConfig::KDE)
			LibName+="kde.so";
		else if(config->integrPlugin()==KpxConfig::Gnome)
			LibName+="gnome.so";
		QString filename=findPlugin(LibName);
		if(filename!=QString()){
			QPluginLoader plugin(filename);
			if(!plugin.load()){
				PluginLoadError=plugin.errorString();
				qWarning("Could not load desktop integration plugin:");
				qWarning(CSTR(PluginLoadError));
			}
			else{
				QObject *plugininstance=plugin.instance();
				IFileDialog* fdlg=qobject_cast<IFileDialog*>(plugininstance);
				IconLoader=qobject_cast<IIconTheme*>(plugininstance);
				if(IconLoader==NULL){
					qWarning("Error: Integration Plugin: Could not initialize IconTheme interface.");
				}
				KpxFileDialogs::setPlugin(fdlg);
				if(config->integrPlugin()==KpxConfig::KDE){
					IKdeInit* kdeinit=qobject_cast<IKdeInit*>(plugin.instance());
					app=kdeinit->getMainAppObject(argc,argv);
					if(!app) PluginLoadError = "Initialization failed.";
				}
				if(config->integrPlugin()==KpxConfig::Gnome){
					IGnomeInit* ginit=qobject_cast<IGnomeInit*>(plugin.instance());
					if(!ginit->init(argc,argv)){
						KpxFileDialogs::setPlugin(NULL);
						qWarning("GtkIntegrPlugin: Gtk init failed.");
						PluginLoadError = "Initialization failed.";
					}
				}
			}
		}
		else{
			qWarning(CSTR(QString("Could not load desktop integration plugin: File '%1' not found.").arg(LibName)));
			PluginLoadError=QObject::tr("Could not locate library file.");
		}
	}
#endif
	if(!app){
		#if defined(Q_WS_X11) && defined(GLOBAL_AUTOTYPE)
			app = new KeepassApplication(argc,argv);
		#else
			app = new QApplication(argc,argv);
		#endif	
	}
	if ( !args.parse(QApplication::arguments()) ){
		qCritical(CSTR( args.error().append("\n") ));
		args.printHelp();
		return 1;
	}
	if (args.help()){
		args.printHelp();
		return 1;
	}
	
	//Internationalization
	QLocale loc;
	if(!args.language().size())
		loc=QLocale::system();
	else
		loc=QLocale(args.language());

	QTranslator* translator = new QTranslator;
	QTranslator* qtTranslator = new QTranslator;

	if(loadTranslation(translator,"keepassx-",loc.name(),QStringList()
						<< DataDir+"/i18n/"
						<< HomeDir))
	{
		QApplication::installTranslator(translator);
		TrActive=true;
	}
	else{
		if(loc.name()!="en_US")
			qWarning(CSTR(
				QString("Kpx: No Translation found for '%1 (%2)' using 'English (UnitedStates)'")
				.arg(QLocale::languageToString(loc.language()))
				.arg(QLocale::countryToString(loc.country()))
			));
		delete translator;
		TrActive=false;
	}
	
	if(TrActive){
		if(loadTranslation(qtTranslator,"qt_",loc.name(),QStringList()
							<< QLibraryInfo::location(QLibraryInfo::TranslationsPath)
							<< DataDir+"/i18n/"
							<< HomeDir))
			QApplication::installTranslator(qtTranslator);
		else{
			if(loc.name()!="en_US")
				qWarning(CSTR(
					QString("Qt: No Translation found for '%1 (%2)' using 'English (UnitedStates)'")
					.arg(QLocale::languageToString(loc.language()))
					.arg(QLocale::countryToString(loc.country()))
				));
			delete qtTranslator;
		}
	}

	DetailViewTemplate=config->detailViewTemplate();

	loadImages();
	KpxBookmarks::load();
	initYarrow(); //init random number generator
	SecString::generateSessionKey();

	EventListener* eventListener = new EventListener();
	app->installEventFilter(eventListener);

	QApplication::setQuitOnLastWindowClosed(false);
	KeepassMainWindow *mainWin = new KeepassMainWindow(args.file(), args.startMinimized(), args.startLocked());
	int r=app->exec();
	delete mainWin;
	delete eventListener;

	fileDlgHistory.save();
	delete app;
	delete config;
	return r;
}


///TODO 0.2.3 remove
void loadImages(){
	QPixmap tmpImg(getImageFile("clientic.png"));
	EntryIcons=new QPixmap[BUILTIN_ICONS];
	for(int i=0;i<BUILTIN_ICONS;i++){
		EntryIcons[i]=tmpImg.copy(i*16,0,16,16);
	}
}


bool loadTranslation(QTranslator* tr,const QString& prefix,const QString& loc,const QStringList& paths){
	for(int i=0;i<paths.size();i++)
		if(tr->load(prefix+loc+".qm",paths[i])) return true;
	
	for(int i=0;i<paths.size();i++){
		QDir dir(paths[i]);
		QStringList TrFiles=dir.entryList(QStringList()<<"*.qm",QDir::Files);
		for(int j=0;j<TrFiles.size();j++){
			if(TrFiles[j].left(prefix.length()+2)==prefix+loc.left(2)){
				if(tr->load(TrFiles[j],paths[i]))return true;
			}
		}
	}
	return false;
}


CmdLineArgs::CmdLineArgs(){
	StartMinimized=false;
	StartLocked=false;
	Help=false;
}

bool CmdLineArgs::parse(const QStringList& argv){
	for(int i=1;i<argv.size();i++){
		if(argv[i]=="-help" || argv[i]=="--help" || argv[i]=="-h"){
			Help=true;
			break; // break, because other arguments will be ignored anyway
		}
		if(argv[i]=="-lang"){
			if(argv.size()==i+1){
				Error="Missing argument for '-lang'.";
				return false;
			}
			if(argv[i+1].size() != 2 && argv[i+1].size() != 5 ){
				Error=QString("'%1' is not a valid language code.").arg(argv[i+1]);
				return false;
			}
			Language=argv[i+1];
			i++;
			continue;
		}
		if(argv[i]=="-cfg"){
			//already done in preparse() -> skip
			i++;
			continue;
		}
		if(argv[i]=="-min"){
			StartMinimized=true;
			continue;
		}
		if(argv[i]=="-lock"){
			StartLocked=true;
			continue;
		}
		if(i==1 && argv[i].left(1)!="-"){
			File=argv[1];
			continue;
		}
		Error=QString("** Unrecognized argument: '%1'").arg(argv[i]);
		return false;
	}
	return true;
}

bool CmdLineArgs::preparse(int argc,char** argv){
	for(int i=1;i<argc;i++){
		if(QString(argv[i])=="-cfg"){
			if(argc==i+1){
				Error="Missing argument for '-cfg'.";
				return false;
			}
			if(QString(argv[i+1]).left(1)=="-"){
				Error=QString("Expected a path as argument for '-cfg' but got '%1.'").arg(argv[i+1]);
				return false;
			}
			QFileInfo file(argv[i+1]);
			ConfigLocation=file.absoluteFilePath();
			i++;
			return true;
		}
	}
	return true;
}

void CmdLineArgs::printHelp(){
	cerr << "KeePassX " << APP_VERSION << endl;
	cerr << "Usage: keepassx  [Filename] [Options]" << endl;
	cerr << "  -help             This Help" << endl;
	cerr << "  -cfg <CONFIG>     Use specified file for loading/saving the configuration." << endl;
	cerr << "  -min              Start minimized." << endl;
	cerr << "  -lock             Start locked." << endl;
	cerr << "  -lang <LOCALE>    Use specified language instead of systems default." << endl;
	cerr << "                    <LOCALE> is the ISO-639 language code with or without ISO-3166 country code" << endl;
	cerr << "                    Examples: de     German" << endl;
	cerr << "                              de_CH  German(Switzerland)" << endl;
	cerr << "                              pt_BR  Portuguese(Brazil)" << endl;
}


QString findPlugin(const QString& filename){
	QFileInfo info;	
	info.setFile(AppDir+"/../lib/"+filename);
	if(info.exists() && info.isFile())
		return AppDir+"/../lib/"+filename;	
	return QString();
}


bool EventListener::eventFilter(QObject*, QEvent* event){
	if (!EventOccurred){
		int t = event->type();
		if ( t>=QEvent::MouseButtonPress&&t<=QEvent::KeyRelease || t>=QEvent::HoverEnter&&t<=QEvent::HoverMove )
			EventOccurred = true;
	}
	
	return false;
}
