/***************************************************************************
 *   Copyright (C) 2004, 2005 Thomas Nagy                                  *
 *   tnagy2^8@yahoo.fr                                                     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License version 2        *
 *   as published by the Free Software Foundation (see COPYING)            *
 *                                                                         *
 *   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.                          *
 ***************************************************************************/

#include <qlabel.h>
#include <qpushbutton.h>
#include <qfileinfo.h>
#include <qdir.h>
#include <qregexp.h>

#include <ktextedit.h>
#include <kiconloader.h>
#include <klistview.h>
#include <kdebug.h>
#include <klineedit.h>
#include <kurlrequester.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <ktextbrowser.h>
#include <kconfig.h>
#include <kio/job.h>

#include <fstream>

#include "KDissertPart.h"
#include "DGenerator.h"
#include "DDataControl.h"
#include "generatorp1.h"
#include "generatorp2.h"
#include "generatorwizard.h"
#include "settings.h"

class KListViewItemGen : public KListViewItem
{
	public:
		KListViewItemGen(KListView* parent, QString s1, DGenerator*gen);
		KListViewItemGen(KListViewItem* parent, QString s1, DGenerator*gen);
		~KListViewItemGen() {}
		DGenerator *m_gen;
};

KListViewItemGen::KListViewItemGen(KListView* parent, QString s1, DGenerator*gen) : 
	KListViewItem(parent, s1)
{
	m_gen = gen;
}

KListViewItemGen::KListViewItemGen(KListViewItem* parent, QString s1, DGenerator*gen) : 
	KListViewItem(parent, s1)
{
	m_gen = gen;
}

generatorwizard::generatorwizard(KDissertPart* part) : KWizard(NULL)
{
	setCaption(i18n("kdissert Document Generator"));

	m_part = part;
	m_data=NULL;

	helpButton()->hide();
	m_page1 = new generatorp1(this);
	addPage(m_page1, i18n("General"));

	m_page2 = new generatorp2(this);
	addPage(m_page2, i18n("Finish"));

	m_page1->doclocation->setMode(KFile::LocalOnly | KFile::Directory);

	KConfig *cfg = new KConfig("kdissertpartrc");
	QString dirstart = cfg->readPathEntry( "dirstart", QDir::homeDirPath() );
	delete cfg;

	m_page1->doclocation->setURL( dirstart );

	connect(m_page1->docname, SIGNAL(textChanged(const QString &)), this, SLOT(updatelocationlabel()));
	connect(m_page1->doclocation, SIGNAL(textChanged(const QString &)), this, SLOT(updatelocationlabel()));
	connect(m_page1->doclocation, SIGNAL(urlSelected(const QString &)), this, SLOT(updatelocationlabel()));
	connect(m_page1->templatelist, SIGNAL(selectionChanged()), this, SLOT(updateselectedtemplate()) );
	connect(m_page1->templatelist, SIGNAL(currentChanged(QListViewItem*)), this, SLOT(updatecurrenttemplate(QListViewItem*)) );
	connect(m_page1->templatelist, SIGNAL(selectionChanged()), this, SLOT(updatelocationlabel()) );

	updatelocationlabel();

	connect(this, SIGNAL(selected(const QString&)), this, SLOT(checksteps()) );

	setNextEnabled( m_page1, false );
	setNextEnabled( m_page2, false );
	setFinishEnabled( m_page2, false );
	setFinishEnabled( m_page2, false );
}


generatorwizard::~generatorwizard()
{
}

void generatorwizard::accept()
{
	if ( ! isvalidlocation())
	{
		KMessageBox::sorry(this, i18n("The directory you have chosen as the location for "
		                              "the project already exists."));
		showPage(m_page1);
		m_page1->docname->setFocus();
		checksteps();
		return;
	}

	if ( m_selected.isEmpty() )
	{
		KMessageBox::sorry(this, i18n("Something really wrong happened: "
		                              "cannot find your selection :-/") );
		checksteps();
		m_page1->docname->setFocus();
		showPage(m_page1);
		return;
	}

	KConfig("kdissertpartrc").writePathEntry( "dirstart", m_page1->doclocation->url() );

	// the generation directory is created with a file .kdissert, which exists
	// to mark this directory as legal kdissert generation target directory
	// it contains the creation time that is appended to the backup upon regeneration
	QDir().mkdir(m_page1->docfinallocation->text()); // ignore if it already exists
	m_data->m_generator_lasturl = m_page1->docfinallocation->text();
	m_data->m_generator_lastgen.clear();
	m_data->docChanged(); // the selection and url are stored in document

	// read last generation date (for backup suffix) and save the actual one
	std::string hash("ERROR"); // if hash is used for backup, but not read from file, it's an error
	std::ifstream is(m_data->m_generator_lasturl+"/.kdissert");
	is>>hash;
	is.close();
	std::ofstream os(m_page1->docfinallocation->text()+"/.kdissert");
	os<<QDate::currentDate().toString(Qt::ISODate)
		<<'-'
		<<QTime::currentTime().toString(Qt::ISODate);

	for (DGenerator* item(m_selected.first()); item; item=m_selected.next())
	{
		connect(item, SIGNAL(documentGenerated(const QString&, bool)), m_part, SLOT(launchURL(const QString&, bool)) );
		QString target(m_page1->docfinallocation->text()+'/'+item->identifikation());
		if (QDir(target).exists())
			if (Settings::backupGenerated()) // backup last generation if necessary
			{
				if (!QDir().rename(target, target+'.'+hash+".old"))
				{
					KMessageBox::sorry(this, i18n("Cannot move previously generated directory %1, abort generation.").arg(target));
					return;
				}
			}
			else // remove directory
				for (QStringList todelete(QDir(target).absPath()); todelete.count()>0;)
					if (QRegExp(".*/\\.{1,2}").exactMatch(todelete.first()))
						todelete.pop_front(); // ignore . and ..
					else
						if (QFileInfo(todelete.first()).isDir()) // is a directory
							if (!QDir(target).rmdir(todelete.first())) // try to remove (works if empty), or add contents to deletion list
								todelete = QDir(todelete.front()).entryList().gres(QRegExp("^(.*)$"), todelete.front()+"/\\1") + todelete;
							else // deletion was successful
								todelete.pop_front();
						else // it is a file (or link or whatsoever)
							if (!QDir(target).remove(todelete.front())) { // removing it must work
								KMessageBox::sorry(this, i18n("Cannot delete file %1.").arg(todelete.front()));
								return;
							} else // deletion was successful
								todelete.pop_front();
		if (item->generate(target, m_data))
			m_data->m_generator_lastgen.push_back(item->identifikation());
		else
			KMessageBox::sorry(this, i18n("Generation of document type %1 failed").arg(item->fullName()));
		disconnect(item, SIGNAL(documentGenerated(const QString&, bool)), m_part, SLOT(launchURL(const QString&, bool)) );
	}

	KWizard::accept();
}

bool generatorwizard::isvalidlocation()
{
	m_page1->validlabel->setText(QString::null);

	if (m_page1->docname->text().length() < 1)
	{
		m_page1->validlabel->setText( i18n("(invalid: please specify a folder)") );
		return false;
	}
	QFileInfo fi(m_page1->doclocation->url());
	if (!fi.isDir())
	{
		m_page1->validlabel->setText( i18n("(invalid folder)") );
		return false;
	}
	if (!fi.isWritable())
	{
		m_page1->validlabel->setText( i18n("(invalid: folder is locked)") );
		return false;
	}

	QFileInfo fi2(m_page1->docfinallocation->text());

	if ( fi2.exists() && (!fi2.isDir() || !fi2.isWritable() || !QFileInfo(m_page1->docfinallocation->text()+"/.kdissert").exists()))
	{
		m_page1->validlabel->setText( i18n("(invalid: path is not a writable kdissert generation direcory)") );
		return false;
	}
	return true;
}

void generatorwizard::updatelocationlabel()
{
	QString base = m_page1->doclocation->url();
	if (!base.endsWith("/")) base.append("/");

	m_page1->docfinallocation->setText(base+m_page1->docname->text());
        if (m_data)
	{
		m_data->m_project = m_page1->docname->text();
		m_data->m_path = m_page1->doclocation->url();
	}
	checksteps();
	//isvalidlocation();
}

void generatorwizard::setgeneratorlist(QValueList<DGenerator*> & genlist)
{
	for (unsigned int i=0; i<genlist.count(); i++)
	{
		QString group = genlist[i]->group();
		QString fullname = genlist[i]->fullName();

		KListViewItem *item = (KListViewItem*) m_page1->templatelist->findItem(group, 0);
		if (item)
		{
			new KListViewItemGen(item, fullname, genlist[i]);
		}
		else
		{
			item = new KListViewItemGen(m_page1->templatelist, group, NULL);
			item->setPixmap(0, SmallIcon("folder"));
			item->setOpen(true);

			new KListViewItemGen(item, fullname, genlist[i]);
		}
	}
}

void generatorwizard::setgeneratordata(DDataControl* data)
{
	// it is important, that m_data is assigned as last step, otherwise
	// m_data->m_path is overwritten in
	// generatorwizard::updatelocationlabel
	m_page1->docname->setText(data->m_project);
	m_page1->doclocation->setURL(data->m_path);
	m_data = data;
}

void generatorwizard::updateselectedtemplate()
{
	m_selected.clear();
	for (QListViewItemIterator it(m_page1->templatelist); it.current(); ++it)
		if (m_page1->templatelist->isSelected(it.current()))
			if (KListViewItemGen* gen = (KListViewItemGen*) it.current())
				if (gen->m_gen)
					m_selected.append(gen->m_gen);
}

void generatorwizard::updatecurrenttemplate(QListViewItem* item)
{
	KListViewItemGen* gen = (KListViewItemGen*) item;
	if (gen->m_gen)
	{
		m_page1->templatedescr->setText( gen->m_gen->description() );
	}
	else
	{
		m_page1->templatedescr->setText( QString::null );
	}
}

void generatorwizard::checksteps()
{
	// more steps to come ...
	bool valid = isvalidlocation();
	if (currentPage() == m_page1)
	{
		setNextEnabled(m_page1, !m_selected.isEmpty() && valid);
	}
	else if (currentPage() == m_page2)
	{
		m_page2->url->setText(m_page1->docfinallocation->text());
		if (m_selected.count()==1)
		{ // only one item selected, show it's info
			m_page2->notes->setText(m_selected.first()->quickstart());
		} else { // show a generic hint
			QString text(i18n("<p>You selected more than one item,"
			                  "so the help text of the individual "
			                  "items is not shown. Please refere "
			                  "to the generated README files for "
			                  "details.</p>"
			                  "<p>The following will be generated in directory <code>%1</code>:</p>")
			             .arg(m_page1->docfinallocation->text())
			             +"<table><tr><th>"+i18n("Document Type:")
			             +"</th><th>"+i18n("Subdirectory Name:")+"</th></tr>");
			for (DGenerator* item(m_selected.first()); item; item=m_selected.next())
				text += "<tr><td><i>"+item->fullName()+"</i></td><td><code>"
				        +item->identifikation()+"</code></td></tr>";
			text += "</table>";
			m_page2->notes->setText(text);
		}
		setFinishEnabled(m_page2, valid);
		finishButton()->setFocus();
	}
}

#include "generatorwizard.moc"
