/*
 *  Copyright (C) 2002 Mickael Marchand <marchand@kde.org>
 *
 *  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; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  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 "kcmvim.h"
#include <kapplication.h>
#include <kconfig.h>
#include <kstandarddirs.h>
#include <kgenericfactory.h>
#include <kglobal.h>
#include <qlayout.h>
#include <qpixmap.h>
#include <qlabel.h>
#include <qcheckbox.h>
#include <kaboutdata.h>
#include <kprocess.h>
#include <kmessagebox.h>
#include <kdebug.h>
#include <qfileinfo.h>
#include <unistd.h>

typedef KGenericFactory<KCMVim, QWidget> KCMVimFactory;
K_EXPORT_COMPONENT_FACTORY( kcm_vim, KCMVimFactory("kcmvim") )

KCMVim::KCMVim(QWidget *parent, const char *name, const QStringList&)
: KCModule(KCMVimFactory::instance(), parent, name)
{
	//init values
	configurationok = haseval = hasclientserver = false;
	vimgui = NONE;

	//gui
	setButtons(Default|Apply);
	QVBoxLayout *vb = new QVBoxLayout(this);
	base = new vimbase(this);
	vb->add(base);
	config = new KConfig("vimpartrc");
	QObject::connect(base->test,SIGNAL(pressed()), this, SLOT(test()));
	QObject::connect(base->menubar,SIGNAL(stateChanged(int)), this, SLOT(setModified()));
	QObject::connect(base->toolbar,SIGNAL(stateChanged(int)), this, SLOT(setModified()));
	QObject::connect(base->executable,SIGNAL(textChanged(const QString&)),this,SLOT(checkPath(const QString&)));
	QObject::connect(base->x11comm,SIGNAL(stateChanged(int)), this, SLOT(setModified()));
	QObject::connect(base->dcopcomm,SIGNAL(stateChanged(int)), this, SLOT(setModified()));
	load();
}

KCMVim::~KCMVim()
{
	delete config;
}

void KCMVim::load()
{
	base->executable->setURL(config->readPathEntry("executable"));
	base->menubar->setChecked(config->readBoolEntry("menu"));
	base->toolbar->setChecked(config->readBoolEntry("tool"));
	base->x11comm->setChecked(!config->readBoolEntry("usedcop"));
	base->dcopcomm->setChecked(config->readBoolEntry("usedcop"));
	if ( (haseval = config->readBoolEntry("haseval")) == true ) base->evalled->setColor(QColor(green));
	else base->evalled->setColor(QColor(red));
	if ( (hasclientserver=config->readBoolEntry("hasclientserver")) == true ) base->clientserverled->setColor(QColor(green));
	else base->clientserverled->setColor(QColor(red));
	base->versionlabel->setText(config->readEntry("vimversion"));
//	base->guilabel->setText(config->readEntry("gui"));
	int guin = config->readNumEntry( "guin", 0 );
	if ( guin == 1 ) base->guilabel->setText(i18n( "KVim - Vim-KDE" ));
	if ( guin == 2 ) base->guilabel->setText(i18n( "GVim - Vim-GTK" ));
	if ( guin == 3 ) base->guilabel->setText(i18n( "GVim - Vim-GNOME" ));
	if ( guin == 4 ) base->guilabel->setText(i18n( "GVim - Vim-Other" ));
	configurationok = config->readBoolEntry("ready");

	emit changed(false);
}

void KCMVim::save()
{
	config->writePathEntry("executable",base->executable->url());
	config->writeEntry("tool",base->toolbar->isChecked());
	config->writeEntry("menu",base->menubar->isChecked());
	config->writeEntry("usedcop", base->dcopcomm->isChecked());
	config->writeEntry("haseval", haseval);
	config->writeEntry("hasclientserver", hasclientserver);
	config->writeEntry("vimversion", base->versionlabel->text());
	
	int guin=0;
	if ( base->guilabel->text()== i18n( "KVim - Vim-KDE" ) ) guin=1;
	else if ( base->guilabel->text()== i18n( "GVim - Vim-GTK" ) ) guin=2;
	else if ( base->guilabel->text()== i18n( "GVim - Vim-GNOME" ) ) guin=3;
	else if ( base->guilabel->text()== i18n( "GVim - Vim-Other" ) ) guin=4;
	config->writeEntry( "guin", guin );

//	config->writeEntry("gui", base->guilabel->text());
	config->writeEntry("ready", configurationok);

	config->sync();
	emit changed(false);
}

void KCMVim::test()
{
	QFileInfo *info = new QFileInfo(base->executable->url());
	if (info->isSymLink()) {
		KMessageBox::error(this,i18n("Please don't choose a symlink, kvim or gvim are often symlinks to 'vim'."), i18n("Invalid File"));
		return;
	}
	if (!info->exists() || !info->isExecutable()) {
		KMessageBox::error(this,i18n("The chosen file cannot be executed!"), i18n("Invalid File"));
		return;
	}
	reset();

	myProc = new KProcess();
	myProc->setUseShell(true);
	(*myProc) << KProcess::quote(base->executable->url()) << "-X" << "-U NONE" << "-i NONE" << "-v" << "--version";
	kdDebug() << "Executing : " << KProcess::quote( base->executable->url() ) << endl;
	connect (myProc, SIGNAL(processExited(KProcess*)), this, SLOT(testExited(KProcess*)));
	connect (myProc, SIGNAL(receivedStdout(KProcess *, char *, int)), this, SLOT(Out(KProcess*,char*,int)));
	connect (myProc, SIGNAL(receivedStderr(KProcess*,char*,int)), this, SLOT(Err(KProcess*,char*,int)));
	myProc->start(KProcess::NotifyOnExit, KProcess::AllOutput);
}

void KCMVim::testExited(KProcess*)
{
	emit changed(true);
	QString message;
	//check the results
	switch (vimgui) {
		case KVIM:
			base->guilabel->setText(i18n("KVim - Vim-KDE"));
			if (base->versionlabel->text().startsWith("6.") && (base->versionlabel->text().mid(2,1)).toInt()>=1) {
				base->dcopcomm->setChecked(true);
				message+=i18n("KVim has been detected. DCOP support has been activated but it will only work with KVim >= 6.1.141rc2. If you have an earlier version, please select the X11 Communication system.");
			} else {
				base->x11comm->setChecked(true);
			}
			configurationok=true;
			break;
		case GTK:
			base->guilabel->setText(i18n("GVim - Vim-GTK"));
			if (hasclientserver) {
				base->x11comm->setChecked(true);
				configurationok=true;
			} else message += i18n("Your Vim cannot be used with the Vim KPart, it lacks the Client-Server feature which is required to use a GUI Vim (except KVim).");
			break;
		case GNOME:
			base->guilabel->setText(i18n("GVim - Vim-GNOME"));
			hasclientserver=true;
			base->x11comm->setChecked(true);
			configurationok=true;
			message += i18n("Warning: Your Vim uses GNOME as a GUI; it should probably work with the Vim KPart but it cannot be tested due to a bug in Vim's GNOME GUI.\nYou will therefore have to try it yourself. Choose X11 Communication and try the component in Konqueror, for example. If it fails then you will have to update your Vim's version.");
			break;
		case OTHER:
			base->guilabel->setText(i18n("GVim - Vim-Other"));
			if (hasclientserver) {
				base->x11comm->setChecked(true);
				configurationok=true;
			} else message += i18n("Your Vim cannot be used with the Vim KPart; it lacks the Client-Server feature which is required for GTK/GNOME support.");
			break;
		default:
		case NONE:
			base->guilabel->setText(i18n("No GUI supported"));
			configurationok=false;
			message+=i18n("Your Vim does not provide any GUI support. A GUI is required to use this component. Upgrade your Vim's version or install GVim/KVim.");
	}

	if (hasclientserver) base->clientserverled->setColor(QColor(green));
	if (haseval) {
		base->evalled->setColor(QColor(green));
	} else message+=i18n("\nYour Vim lacks the Eval feature; it is highly recommended to have this feature enabled. You may encounter problems without it.");
	if (configurationok) {
		KMessageBox::information(this,i18n("Test Successful\n")+message, i18n("Vim Component Test"));
	} else {
		KMessageBox::information(this,i18n("Test Failed!\n")+message, i18n("Vim Component Test"));
	}
}

void KCMVim::Out(KProcess *, char *buf, int len)
{
	QString b = QString::fromLatin1(buf, len);

	kdDebug() << " ########################################################## " << endl;
	kdDebug() << b << endl;
	kdDebug() << " ########################################################## " << endl;

	if (b.contains("KDE")) {
		vimgui=KVIM;
		kdDebug() << " KVim detected " << endl;
	}
	if (b.contains("GTK") && vimgui==NONE) { //some gnome version also outputs "GTK"
		vimgui=GTK;
		kdDebug() << " Vim-GTK detected " << endl;
	}
	if (b.contains("GNOME")) {
		vimgui=GNOME;
		kdDebug() << " Vim-GNOME detected " << endl;
	}
	
	//if (b.contains("GUI") && vimgui==NONE) vimgui=OTHER;

	if (b.contains("IMproved")) {
		int start = b.find("IMproved ");
		start+=9;
		QString version = b.mid(start,3);
		base->versionlabel->setText(version);
	}
	if (b.contains("+clientserver")) hasclientserver=true;
	if (b.contains("+eval")) haseval=true;
}

void KCMVim::Err(KProcess *, char *buf, int len)
{
	QString b = QString::fromLatin1(buf, len);
	kdDebug() << " ########################################################## " << endl;
	kdDebug() << b << endl;
	kdDebug() << " ########################################################## " << endl;

	if (b.contains("KDE")) {
		vimgui=KVIM;
		kdDebug() << " KVim detected " << endl;
	}
	if (b.contains("GTK") && vimgui==NONE) { //some gnome version also outputs "GTK"
		vimgui=GTK;
		kdDebug() << " Vim-GTK detected " << endl;
	}
	if (b.contains("GNOME")) {
		vimgui=GNOME;
		kdDebug() << " Vim-GNOME detected " << endl;
	}
	if (b.contains("IMproved")) {
		int start = b.find("IMproved");
		start+=9;
		QString version = b.mid(start,3);
		base->versionlabel->setText(version);
	}
	if (b.contains("+clientserver")) hasclientserver=true;
	if (b.contains("+eval")) haseval=true;
}

void KCMVim::reset()
{
	configurationok = haseval = hasclientserver = false;
	vimgui = NONE;
	base->versionlabel->setText("");
	base->guilabel->setText("");
	base->evalled->setColor(QColor(red));
	base->clientserverled->setColor(QColor(red));
}

void KCMVim::defaults()
{
	base->executable->setURL("/usr/bin/vim");
	base->menubar->setChecked(false);
	base->toolbar->setChecked(false);
	reset();
	emit changed(true);
}

void KCMVim::checkPath(const QString& p)
{
	if (p.isNull() || p.isEmpty()) base->test->setEnabled(false);
	else base->test->setEnabled(true);
	emit changed(true);
}

void KCMVim::setModified()
{
	emit changed(true);
}

const KAboutData* KCMVim::aboutData() const
{
	KAboutData *about =
		new KAboutData(I18N_NOOP("kcmvim"), I18N_NOOP("KDE Vim Embedding Control Module"),
				"1.0", I18N_NOOP("The Vim KPart is developed by the KVim Team."), KAboutData::License_GPL,
				"(c) 2002-2003 Mickael Marchand",
				0,"http://freehackers.org/kvim");

	about->addAuthor("Mickael Marchand", "http://freenux.org", "marchand@kde.org");

	return about;
}

#include "kcmvim.moc"
