/*
 * install.cpp
 *
 * Copyright (c) 2007 Fabian Wuertz
 *
 * 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.
 *
 * 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
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#else
#define PREFIX "/usr"
#endif

#include <kgenericfactory.h>
#include <tdelocale.h>
#include <tdefiledialog.h>
#include <kurlrequester.h>
#include <tdeaboutapplication.h>

#include <tqlistbox.h>
#include <tqfile.h>
#include <tqpushbutton.h>
#include <tqwidgetstack.h>
#include <tqlabel.h>
#include <tqlistview.h>
#include <tqregexp.h>
#include <tqradiobutton.h>
#include <tqfiledialog.h>

#include <console.h>
#include <install.h>

#include <string>
#include <stdio.h>

using namespace std;

install::install( const TQString &url, TQWidget *parent, const char *name, const TQStringList &)
:InstallDialog(parent, name)
{

	if( !url )
		path = KFileDialog::getOpenFileName( TQString(), TQString("*.deb|") + i18n("Debian Package (*.deb)"), this, i18n("Choose a Debian package file to open"));
	else
		path = url;

	this->shell = new Process();

	this->shell->setCommand("dpkg -f "+path);
	this->shell->start(true);
	fields = TQStringList::split( "\n", this->shell->getBuffer().stripWhiteSpace() );

	installPushButton->hide();
	nextPushButton1->hide();

	// Get KDE prefix
	// FIXME Is there a better way to do this???
	string prefixcommand="tde-config --prefix";
	FILE *pipe_prefix;
	char prefix_result[2048];
	int i;

	if ((pipe_prefix = popen(prefixcommand.c_str(), "r")) == NULL)
	{
		m_kdePrefix = PREFIX;
	}
	else {
		fgets(prefix_result, 2048, pipe_prefix);
		pclose(pipe_prefix);
		for (i=0;i<2048;i++) {
			if (prefix_result[i] == 0) {
				prefix_result[i-1]=0;
				i=2048;
			}
		}
		m_kdePrefix = TQString(prefix_result);
	}

	if( !checkArchitecture() )
		page2x1();
	else if( isLocked() )
		page2x2();


}

//----------------------------------------------------------------------------//
//--- next -------------------------------------------------------------------//
//----------------------------------------------------------------------------//

void install::next1()
{
	if( !isLocked() )
	{
		nextPushButton1->hide();
		nextPushButton2->show();
		widgetStack->raiseWidget(0);
	}
}


void install::next2()
{
	nextPushButton2->hide();
	if( syncRadioButton->isChecked() )
		page3();
	else
		page1();
}



//----------------------------------------------------------------------------//
//--- pages ------------------------------------------------------------------//
//----------------------------------------------------------------------------//


// page 0: skip apt-get update?
// page 1: dependencies
// page 2: warnings
// page 3: apt-get update
// page 4: install package
// page 5: process complete


void install::page1()
{
	showDependencies();

	widgetStack->raiseWidget(1);
	installPushButton->show();
	closePushButton->show();
	titleTextLabel->setText( "<b>"+i18n( "The following packages will be installed, updated or removed:" )+"</b>" );
}

void install::page2x1()
{
	errorTextLabel->setText("<b>"+i18n("The architecture of this package does not match that of your system.  You will not be able to install this package!")+"</b>");
	nextPushButton2->hide();
	widgetStack->raiseWidget(2);

}

void install::page2x2()
{
	errorTextLabel->setText("<b>"+i18n("The package database is in use by another process (e.g Synaptic). Please terminate this process and select Next to try again.")+"</b>");
	nextPushButton1->show();
	nextPushButton2->hide();
	widgetStack->raiseWidget(2);
}


void install::page3()
{
	titleTextLabel->setText( "<b>"+i18n( "Resynchronize Package Index")+"</b>" );
	closePushButton->hide();

	TQStrList run; run.append( m_kdePrefix.local8Bit() + "/share/kdpkg/sh/kdpkg-sh" );
		run.append( "update" );

	TQWidget *consoleWidget = new console(this, run );
 	widgetStack->addWidget(consoleWidget, 4);
	widgetStack->raiseWidget(4);

	connect( consoleWidget, TQT_SIGNAL( finished(bool) ), this, TQT_SLOT( page1() ));
}


void install::page4()
{
	installPushButton->hide();
	closePushButton->hide();
	titleTextLabel->setText( "<b>"+i18n( "Install New Package" )+"</b>" );


	if( !installPkg )
		installPkg = "none";
	if( !removePkg )
		removePkg = "none";

	TQStrList run; run.append( m_kdePrefix.local8Bit() + "/share/kdpkg/sh/kdpkg-sh" );
		run.append( "install" );
		run.append( path.local8Bit() );
		run.append( installPkg.local8Bit() );
		run.append( removePkg.local8Bit() );

	TQWidget *consoleWidget = new console(this, run );
	widgetStack->addWidget(consoleWidget, 5);
	widgetStack->raiseWidget(5);

	//connect( consoleWidget, TQT_SIGNAL( finished(bool) ), this, TQT_SLOT( close() ));
	connect( consoleWidget, TQT_SIGNAL( finished(bool) ), this, TQT_SLOT( page5() ));


}

void install::page5()
{
	successTextLabel->setText("<b>"+i18n("Installation process is complete!")+"</b><br>"+i18n("You may now close this window."));
	nextPushButton2->hide();
	closePushButton->show();
	widgetStack->raiseWidget(3);

}

//----------------------------------------------------------------------------//
//--- get --------------------------------------------------------------------//
//----------------------------------------------------------------------------//

TQStringList install::getVersions(TQString package)
{
	this->shell->setCommand("apt-cache policy "+package);
	this->shell->start(true);
	TQStringList input = TQStringList::split( "\n", this->shell->getBuffer().stripWhiteSpace() );

	TQString sysVersion = input[1];
	sysVersion = TQStringList::split( ":", sysVersion)[1].replace(" ","");

	if( sysVersion.contains("(") || sysVersion == "" )
		sysVersion = i18n("not installed");


	TQString repVersion = input[2];
	repVersion = TQStringList::split( ":", repVersion)[1].replace(" ","");

	if( repVersion.contains("(") || repVersion == "" )
		repVersion = i18n("not available");


	TQStringList versions;
	versions.append(sysVersion);
	versions.append(repVersion);

	return versions;
}

//----------------------------------------------------------------------------//
//--- showDependencies -------------------------------------------------------//
//----------------------------------------------------------------------------//

void install::showDependencies()
{
	int start_index;
	int stop_index;

	// show packages which will be installed

	TQString debianPkgName = fields.grep("Package:")[0].mid(9);
	TQString debianPkgVersion = fields.grep("Version:")[0].mid(9);
	TQStringList debianVersions = getVersions(fields.grep("Package:")[0].mid(9));
	TQString debianSysVersion = debianVersions[0];
	TQListViewItem * ditem = new TQListViewItem( dependenciesListView, 0 );	
	ditem->setPixmap( 0, TQPixmap( m_kdePrefix + "/share/kdpkg/icons/install.png") );
	ditem->setText( 1, debianPkgName  );
	ditem->setText( 2, debianPkgVersion );
	ditem->setText( 3, debianSysVersion );


	TQString tmpString = fields.grep( TQRegExp("^Depends:") )[0].mid(9);
	tmpString += ", "+fields.grep( "Pre-Depends:" )[0].mid(13);


	TQStringList allDepends = TQStringList::split( ", ", tmpString );

	TQString missingDepends;
	TQStringList tmp;

	for(uint i = 0; i < allDepends.count(); i++)
	{
		if( allDepends[i].contains("|") ) {
			tmp = TQStringList::split( " | ", allDepends[i] );
			uint j = 0;
			bool exit = FALSE;
			while ( !exit && j < tmp.count() ) {
				if( isInstalled(tmp[j]) )
					exit = TRUE;
				j++;
			}
			if( !exit )
				missingDepends += tmp[0]+" ";
		}
		else
		{
			if( !isInstalled( allDepends[i] ) )
				missingDepends += TQStringList::split( " ", allDepends[i] )[0]+" ";
		}
	}

	while (missingDepends.find("(") != -1) {
		start_index = missingDepends.find("(");
		stop_index = missingDepends.find(")", start_index);
		missingDepends.replace(start_index, stop_index-start_index+1, "");
	}
	this->shell->setCommand("apt-get -s install "+missingDepends);
	this->shell->start(true);
	TQStringList installList = TQStringList::split( "\n", this->shell->getBuffer().stripWhiteSpace() ).grep("Inst");


	for(uint i = 0; i < installList.count(); i++)
	{
		TQString name = TQStringList::split( " ", installList[i] )[1];
		TQString pkgVersion;
		TQString sysVersion;
		if( installList[i].contains("[") )
		{
			pkgVersion = TQStringList::split( " ", installList[i] )[3].mid(1);
			sysVersion = TQStringList::split( " ", installList[i] )[2].mid(1).replace("]", "");
		}
		else
			pkgVersion = TQStringList::split( " ", installList[i] )[2].mid(1);

		TQListViewItem * item = new TQListViewItem( dependenciesListView, 0 );	
		item->setPixmap( 0, TQPixmap( m_kdePrefix + "/share/kdpkg/icons/install.png") );
		item->setText( 1, name  );
		item->setText( 2, pkgVersion );
		item->setText( 3, sysVersion );

		installPkg += name+",";
	}

	// find rconflicts

	TQString pkgName = fields.grep("Package:")[0].mid(9);
	TQString pkgVersion = fields.grep("Version:")[0].mid(9);

	TQString rconflicts;

	this->shell->setCommand("cat /var/lib/dpkg/status | grep "+pkgName+" -B 16| grep Conflicts -B 16");
	this->shell->start(true);
	TQStringList input1 = TQStringList::split( "\n\n", this->shell->getBuffer().stripWhiteSpace() );

	for(uint i = 0; i < input1.count(); i++)
	{
		if( input1[i].contains(pkgName) )
		{
			TQStringList input2 = TQStringList::split( "\n", input1[i] );
			TQString name = TQStringList::split( " ",  input2.grep("Package:")[0] )[1];
			TQString cVersion = input2.grep("Conflicts:")[0].mid(11); // conflictVersion
			cVersion = TQStringList::split( ",",  cVersion ).grep(pkgName)[0];
			cVersion = TQStringList::split( "(",  cVersion )[1];
			cVersion = cVersion.replace(")", "");
			TQString op = TQStringList::split( " ",  cVersion )[0];
			cVersion = TQStringList::split( " ",  cVersion )[1];

			if( cVersion == "")
			{
				rconflicts += name+" ";
				printf("1");
			}
			else
			{
				printf("2");
				this->shell->setCommand("if dpkg --compare-versions "+pkgVersion+" \""+op+"\" "+cVersion+"; then echo \"TRUE\"; fi");
				this->shell->start(true);
				if( this->shell->getBuffer().stripWhiteSpace() == "TRUE" )
					rconflicts += name+" ";
			}
		}
	}


	// show packages which will be removed

	TQString conflicts = fields.grep( "Conflicts" )[0].mid(11);
	conflicts = conflicts.replace( ",", "" );
	conflicts = conflicts+" "+rconflicts;
	while (conflicts.find("(") != -1) {
		start_index = conflicts.find("(");
		stop_index = conflicts.find(")", start_index);
		conflicts.replace(start_index, stop_index-start_index+1, "");
	}

	this->shell->setCommand("apt-get -s remove "+conflicts);
	this->shell->start(true);
	TQStringList removeList = TQStringList::split( "\n", this->shell->getBuffer().stripWhiteSpace() ).grep("Remv");


	for(uint i = 0; i < removeList.count(); i++)
	{
		TQString name = TQStringList::split( " ", removeList[i] )[1];
		TQString sysVersion = TQStringList::split( " [", removeList[i] )[1].replace("]", "");

		TQListViewItem * item = new TQListViewItem( dependenciesListView, 0 );	
		item->setPixmap( 0, TQPixmap( m_kdePrefix + "/share/kdpkg/icons/remove.png") );
		item->setText( 1, name );
		item->setText( 3, sysVersion );

		removePkg += name+",";
	}
}

//----------------------------------------------------------------------------//
//--- isInstalled ------------------------------------------------------------//
//----------------------------------------------------------------------------//

bool install::isInstalled(TQString input)
{
	TQString package = TQStringList::split( " ",  input )[0];
	TQString version = TQStringList::split( " (", input )[1].replace(")", "");


	this->shell->setCommand("apt-cache policy "+package);
	this->shell->start(true);
	TQString sysVersion = TQStringList::split( "\n", this->shell->getBuffer().stripWhiteSpace() )[1];
	sysVersion = TQStringList::split( ":", sysVersion)[1].replace(" ","");


	if( sysVersion.contains("(") || sysVersion == "" )
		return FALSE;
	else if( version != "" )
	{
		TQString op         = TQStringList::split( " ", version )[0];
		TQString pkgVersion = TQStringList::split( " ", version )[1];

		this->shell->setCommand("if dpkg --compare-versions "+sysVersion+" \""+op+"\" "+pkgVersion+"; then echo \"TRUE\"; fi");
		this->shell->start(true);
		if( this->shell->getBuffer().stripWhiteSpace() == "TRUE" )
			return TRUE;
		else
			return FALSE;
	}
	else
		 return TRUE;
}

//----------------------------------------------------------------------------//
//--- about ------------------------------------------------------------------//
//----------------------------------------------------------------------------//

void install::showAbout()
{
	TDEAboutApplication* about = new TDEAboutApplication ( this );
	about->show();
}

//----------------------------------------------------------------------------//
//--- checks -----------------------------------------------------------------//
//----------------------------------------------------------------------------//

bool install::checkArchitecture()
{
	TQString arch = fields.grep("Architecture:")[0].mid(14);

	if(arch == "all")
		return TRUE;

	// get architecture
	this->shell->setCommand("dpkg --print-architecture");
	this->shell->start(true);

	if( arch == this->shell->getBuffer().stripWhiteSpace() )
		return TRUE;

	return FALSE;

}


bool install::isLocked()
{
	this->shell->setCommand("apt-get install -s" );
	this->shell->start(true);
	if( this->shell->getBuffer().stripWhiteSpace().contains("...") )
		return FALSE;
	else
		return TRUE;
}





#include "install.moc"