/*
 * This file is part of DesktopBSD, see the README file.
 *
 * Author: Peter Hofer <ph@desktopbsd.net>
 *			(C) 2004, 2005
 *
 * Copyright: BSD, see the COPYING file included in this distribution
 *
 */

#include <dbsdglobal.h>
#include <dbsdiconloader.h>
#include <dialogs.h>
#include <size.h>
#include <translation.h>

#include <qapplication.h>
#include <qprogressdialog.h>

#define	LST_ID_COL	0


void frmDeinstallPkgs::init() {
	Translation::translateWizard(this);

	currentStep = -1;

	setHelpEnabled(pgWelcome, false);

	/* Initialize graphics */
	DBSDIconLoader  *iloader = DBSDGlobal::getIconLoader();
	pixWelcome->setPixmap(iloader->loadIcon("kappfinder", DBSDIconLoader::Size48x48));
	pixSelectPkgs->setPixmap(iloader->loadIcon("editdelete", DBSDIconLoader::Size32x32));
	pixConfirmPkgs->setPixmap(iloader->loadIcon("button_ok", DBSDIconLoader::Size32x32));
	btnCalculateSize->setIconSet(iloader->loadIcon("kcalc", DBSDIconLoader::Button));
	lblFilter->setPixmap(iloader->loadIcon("find", DBSDIconLoader::Size22x22));
	btnClearSearch->setPixmap(iloader->loadIcon("clear_left", DBSDIconLoader::Button));

	stepDisplayedPkgs.setAutoDelete(true);
	stepSelectedPkgs.setAutoDelete(true);
}


void frmDeinstallPkgs::next() {
	bool  goForward = false;
	++currentStep;

	lblStep->setText(tr("Step %1").arg(currentStep + 1));
	editSearch->setFocus();

	if(currentStep == 0) {
		QPtrList<Package>  *pkgs = new QPtrList<Package>();
		lstStepPackages->clear();

		QPtrListIterator<Package>  i(installedPkgs);
		while(*i != NULL) {
			if((*i)->getRequiredByCount() == 0) {
				pkgs->prepend(*i);

				QCheckListItem *item = new QCheckListItem(lstStepPackages,
																		(*i)->getID(),
																		QCheckListItem::CheckBox);
				item->setText(1, (*i)->getShortDescr());
			}

			++i;
		}

		stepDisplayedPkgs.append(pkgs);
		goForward = true;
	} else {
		QPtrList<Package>  *selectedPkgs = new QPtrList<Package>();
		QListViewItemIterator  i(lstStepPackages);
		while(*i != NULL) {
			QCheckListItem  *li = (QCheckListItem *) *i;

			Package  *pkg = findPackage(li->text(LST_ID_COL));
			if(li->isOn())
				selectedPkgs->prepend(pkg);

			++i;
		}

		/* Remember list of selected packages and
		 * clear the ListView.
		 */
		stepSelectedPkgs.append(selectedPkgs);
		lstStepPackages->clear();
		editSearch->clear();

		/* Previously selected packages */
		QPtrList<Package>  prevSelectedPkgs = getSum(stepSelectedPkgs);

		/* Previously displayed packages */
		QPtrList<Package>  prevDisplayedPkgs = getSum(stepDisplayedPkgs);

		/* Create new list */
		QPtrList<Package>  *displayPkgs = new QPtrList<Package>();
		QPtrListIterator<Package>  newIt(installedPkgs);
		for(;  *newIt != NULL;  ++newIt) {
			Package	*instPkg = *newIt;

			/* Was displayed in a previous step */
			if(prevDisplayedPkgs.contains(instPkg))
				continue;

			uint reqcnt = instPkg->getRequiredByCount();
			if(reqcnt <= prevSelectedPkgs.count()) {
				QPtrListIterator<Package>  prevIt(prevSelectedPkgs);
				for(;  *prevIt != NULL  &&  reqcnt > 0;  ++prevIt)
					if(instPkg->isRequiredBy(**prevIt))
						--reqcnt;

				if(reqcnt == 0) {
					QCheckListItem *item = new QCheckListItem(lstStepPackages, instPkg->getID(), QCheckListItem::CheckBox);
					item->setText(1, instPkg->getShortDescr());
					displayPkgs->prepend(instPkg);
				}
			}
		}

		if(displayPkgs->isEmpty()) {
			/* No more packages */
			delete displayPkgs;
			goForward = true;

			btnCalculateSize->show();
			lblDiskSpace->setText("");

			/* Insert all selected packages into the list */
			lstPackagesConfirm->clear();
			QPtrListIterator<Package>  i(prevSelectedPkgs);
			for(;  *i != NULL;  ++i)
				lstPackagesConfirm->insertItem((*i)->getID());
			lstPackagesConfirm->sort();

			bool  empty = prevSelectedPkgs.isEmpty();
			if(empty)
				lstPackagesConfirm->insertItem(tr("(No packages were selected)"));

			lstPackagesConfirm->setEnabled(!empty);
			lblApproxSpace->setEnabled(!empty);
			btnCalculateSize->setEnabled(!empty);
			lblConfirmPkgsHint->setEnabled(!empty);
			setFinishEnabled(pgFinish, !empty);
		} else
			stepDisplayedPkgs.append(displayPkgs);
	}

	if(goForward)
		QWizard::next();
}

void frmDeinstallPkgs::back() {
	bool  goBack = false;

	if(currentStep >= 0) {
		if(currentStep < (int) stepDisplayedPkgs.count()) {
			/* Not at the 'Finish' screen yet */
			stepDisplayedPkgs.removeLast();
		} else
			goBack = true;

		QPtrList<Package>  *disp = stepDisplayedPkgs.getLast();
		QPtrList<Package>  *sel = stepSelectedPkgs.getLast();
		if(disp != NULL) {
			lstStepPackages->clear();
			editSearch->clear();

			QPtrListIterator<Package>  i(*disp);
			for(;  *i != NULL;  ++i) {
				QCheckListItem *li = new QCheckListItem(lstStepPackages, (*i)->getID(), QCheckListItem::CheckBox);
				li->setText(1, (*i)->getShortDescr());
				
				if(sel != NULL  &&  sel->contains(*i))
					li->setState(QCheckListItem::On);
			}

			if(sel != NULL)
				stepSelectedPkgs.removeLast();
		}
	}


	if(currentStep <= 0) {
		/* Back to the introduction */
		goBack = true;
	}

	if(goBack)
		QWizard::back();

	--currentStep;

	lblStep->setText(tr("Step %1").arg(currentStep + 1));
}

/** Sets the installed packages on the system.
  *
  * Don't change or delete the objects because this
  * wizard uses the given pointers, not copies.
  */
void frmDeinstallPkgs::setInstalledPackages(const QPtrList<Package> &  pkgs) {
	installedPkgs = pkgs;
}


Package * frmDeinstallPkgs::findPackage(const QString & id) {
	QPtrListIterator<Package>  i(installedPkgs);
	while(*i != NULL) {
		if((*i)->getID() == id)
			return *i;

		++i;
	}

	return NULL;
}


void frmDeinstallPkgs::selectAll() {
	QListViewItemIterator i(lstStepPackages);
	for(;  *i != NULL;  ++i) {
		QCheckListItem *item = (QCheckListItem *) *i;
	
		if(item->isVisible())
			item->setOn(true);
	}
}


void frmDeinstallPkgs::selectNone() {
	QListViewItemIterator i(lstStepPackages);
	for(;  *i != NULL;  ++i) {
		QCheckListItem *item = (QCheckListItem *) *i;
	
		if(item->isVisible())
			item->setOn(false);
	}
}


 QPtrList<Package> frmDeinstallPkgs::getSum(QPtrList< QPtrList<Package> > list) {
	QPtrList<Package>  result;

	QPtrListIterator< QPtrList<Package> >  lstIt(list);
	for(;  *lstIt != NULL;  ++lstIt) {
		QPtrListIterator<Package>  pkgIt(**lstIt);
		for(;  *pkgIt != NULL;  ++pkgIt)
			result.prepend(*pkgIt);
	}

	return result;
}

/** Returns all selected packages if
  * the user already finished selecting
  * them (closed the dialog with "Finish").
  *
  * Otherwise, returns an empty list.
  */
QPtrList<Package> frmDeinstallPkgs::getSelectedPackages() {
	if(result() == QDialog::Accepted)
		return getSum(stepSelectedPkgs);

	return QPtrList<Package>();
}


void frmDeinstallPkgs::help() {
	if(currentPage() == pgDeinstall) {
		Dialogs::infoDlg(tr("You can select the packages you want to deinstall here.\n"
								  "\n"
								  "If the selected packages depend on other packages that\n"
								  "are probably useless otherwise, you will be asked whether\n"
								  "you want to remove them or not in the next step.\n"
								  "\n"
								  "Use the \"Select all\" and \"Deselect all\" buttons to\n"
								  "select all or none packages from the list with a single\n"
								  "click, but make sure you don't select packages you\n"
								  "want to keep."));
	} else if(currentPage() == pgFinish) {
		Dialogs::infoDlg(tr("Here you see a list of all packages that will be deinstalled\n"
								  "when you click \"Finish\". You have a last chance to look\n"
								  "through the list and check your selection.\n"
								  "\n"
								  "If you notice you selected a package that you want to keep,\n"
								  "you can use the \"Back\" button to go back to the step where\n"
								  "you selected the package and deselect it. Keep in mind that\n"
								  "afterwards, you have to go through every step again."));
	}
}


void frmDeinstallPkgs::calculateSpace() {
	QPtrList<Package>  pkgs = getSum(stepSelectedPkgs);

	QProgressDialog  dlg(tr("Calculating sizes..."), tr("Cancel"), pkgs.count(), this, NULL, true);
	dlg.setCaption(tr("DesktopBSD"));

	Size  sum(0, Size::KB);
	QPtrListIterator<Package>  i(pkgs);
	for(int n = 0;  *i != NULL;  ++i, ++n) {
		if(dlg.wasCanceled())
			return;

		dlg.setProgress(n);
		qApp->processEvents();

		sum += (*i)->getInstalledSize().get(Size::KB);
	}

	lblDiskSpace->setText(sum.toString(Size::MB));
	btnCalculateSize->hide();
}


void frmDeinstallPkgs::search(const QString & text) {
	QListViewItemIterator i(lstStepPackages);
	for(; i.current() != NULL; ++i) {
		if(text.isEmpty() || (*i)->text(0).contains(text))
			(*i)->setVisible(true);
		else
			(*i)->setVisible(false);
	}
}
