/*
 * This file is part of DesktopBSD, see the README file.
 *
 * Author: Pieringer Johannes <jpieringer@desktopbsd.net>
 *         (C) 2006
 *
 * Copyright: BSD, see the COPYING file included in this distribution
 *
 */

#include <qpushbutton.h>
#include <qlistview.h>
#include <qspinbox.h>
#include <qbuttongroup.h>
#include <qapplication.h>
#include <qbuttongroup.h>
#include <qradiobutton.h>
#include <qptrdict.h>
#include <stdio.h>
#include <qfiledialog.h>
#include <qcheckbox.h>
#include <qlineedit.h>
#include <qcombobox.h>
#include <dbsdglobal.h>
#include "dbsdiconloader.h"
#include "modgrubconf.h"
#include "frmbootproperties.h"
#include "dialogs.h"
#include "qcursor.h"

/** Sets the icons and calls the connects-statements
	*/
ModGrubconf::ModGrubconf(QWidget* parent, const char* name)
		: UiModGrubconf(parent, name)
{
	//All connect statements for the uimodgrubconf
	connect(btnGenerate, SIGNAL(clicked()), this, SLOT(generateBootmenu()));
	connect(btnUp, SIGNAL(clicked()), this, SLOT(bootentryUp()));
	connect(btnDown, SIGNAL(clicked()), this, SLOT(bootentryDown()));
	connect(btnAdd, SIGNAL(clicked()), this, SLOT(bootentryAdd()));
	connect(btnProperties, SIGNAL(clicked()), this, SLOT(bootentryProperties()));
	connect(btnDelete, SIGNAL(clicked()), this, SLOT(bootentryDelete()));
	connect(rbtDefaultEntry, SIGNAL(stateChanged(int)), this, SLOT(defaultBootentry()));
	connect(rbtSavedefault, SIGNAL(stateChanged(int)), this, SLOT(defaultBootentry()));
	connect(btnSplashImageFile, SIGNAL(clicked()), this, SLOT(splashimageFileDialog()));
	connect(spnTimeout, SIGNAL(valueChanged(int)), this, SLOT(changeTimeout()));
	connect(chbSplashImage, SIGNAL(stateChanged(int)), this, SLOT(splashimageStateChanged()));
	connect(chbColor, SIGNAL(stateChanged(int)), this, SLOT(colorStateChanged()));
	connect(cmbColorForeNormal, SIGNAL(activated(int)), this, SLOT(colorStateChanged()));
	connect(cmbColorBackNormal, SIGNAL(activated(int)), this, SLOT(colorStateChanged()));
	connect(cmbColorForeHighlight, SIGNAL(activated(int)), this, SLOT(colorStateChanged()));
	connect(cmbColorBackHighlight, SIGNAL(activated(int)), this, SLOT(colorStateChanged()));
	connect(chbBlinkHighlight, SIGNAL(stateChanged(int)), this, SLOT(colorStateChanged()));
	connect(chbBlinkNormal, SIGNAL(stateChanged(int)), this, SLOT(colorStateChanged()));
	connect(lvwAdvanced, SIGNAL(currentChanged(QListViewItem*)), this, SLOT(bootentryDefault()));
	connect(btnInstallGrub, SIGNAL(clicked()), this, SLOT(installGrub()));

	DBSDIconLoader  *iloader = DBSDGlobal::getIconLoader();
	btnUp->setIconSet(iloader->loadIcon("1uparrow", DBSDIconLoader::Button));
	btnDown->setIconSet(iloader->loadIcon("1downarrow", DBSDIconLoader::Button));
	btnProperties->setIconSet(iloader->loadIcon("configure", DBSDIconLoader::Button));
	btnDelete->setIconSet(iloader->loadIcon("remove", DBSDIconLoader::Button));
	btnAdd->setIconSet(iloader->loadIcon("add", DBSDIconLoader::Button));
}

/** Initialization of the GUI by reading the GRUB menu.lst in the GUI
	*/
void ModGrubconf::initModule()
{
	if(!grubConf.isGrubSupported())
	{
		Dialogs::warnDlg("GRUB is only supported on i386 (32-bit).");
		setEnabled(false);
		return;
	}

	if (!(grubConf.isGrubInstalled()))
		if (Dialogs::question(tr("GRUB doesn't seem to be installed.\n"
										 "\n"
										 "Do you want to install it now?")))
			this->installGrub();

	//Reads the config
	grubConf.readConfiguration();
	loadData();
}

/** Adds the bootentries to the list
 	*/
void ModGrubconf::FillBootentryList()
{
	QPtrList<GrubBootentry> bootEntries = grubConf.getBootmenuEntries();

	//Inserts the bootentries in the gui
	lvwAdvanced->clear();
	lvwAdvanced->setSorting(-1, false);

	cliBootentries = new QCheckListItem(lvwAdvanced, "");
	cliBootentries->setText(1, tr("Boot entries"));
	cliBootentries->setSelectable(false);

	for (uint i = 0; i < bootEntries.count(); ++i)
	{
		QString title = (QString)((GrubBootentry*) bootEntries.at(i))->getValue();

		QCheckListItem * cliBootentry = new QCheckListItem(cliBootentries, lvwAdvanced->lastItem() , "", QCheckListItem::RadioButton);
		cliBootentry->setText(1, title);
		if (grubConf.getDefaultTitle() == i)
		{
			cliBootentry->setState(QCheckListItem::On);
		}
	}
	lvwAdvanced->setOpen(cliBootentries, true);
	defaultBootentry();
	emit(changed(false));
}

/** Applys all changes
	*/
void ModGrubconf::apply()
{
	if (rbgDefaultBootentry->selectedId() == 0)
	{
		int i = 0;
		QListViewItem *it = lvwAdvanced->firstChild()->firstChild();
		while (it)
		{
			if (((QCheckListItem*)it)->state() == QCheckListItem::On)
				grubConf.setDefaultTitle(i);

			it = it->nextSibling();
			++i;
		}
	}
	else
		grubConf.setDefaultTitle(-1);

	if (chbSplashImage->isChecked())
		grubConf.setSplashimagePath(new QString(txtSplashImage->text()));
	else
		grubConf.setSplashimagePath(NULL);

	if (chbColor->isChecked())
	{
		grubConf.setColor((GrubConfiguration::GRUBForegroundColor*)new int(cmbColorForeNormal->currentItem()),
		                  (GrubConfiguration::GRUBBackgroundColor*)new int(cmbColorBackNormal->currentItem()),
		                  new bool(chbBlinkNormal->isChecked()),
		                  (GrubConfiguration::GRUBForegroundColor*)new int(cmbColorForeHighlight->currentItem()),
		                  (GrubConfiguration::GRUBBackgroundColor*)new int(cmbColorBackHighlight->currentItem()),
		                  new bool(chbBlinkHighlight->isChecked()));
	}
	else
		grubConf.setColor(NULL, NULL, NULL, NULL, NULL, NULL);

	grubConf.writeConfiguration();
	emit changed(false);
}

/** Resets the application
	*/
void ModGrubconf::reset()
{
	initModule();
	emit changed(false);
}

/** Generates the bootmenu and reads it in the GUI
	*/
void ModGrubconf::generateBootmenu()
{
	grubConf = GrubConfiguration();
	if (grubConf.generateBootmenu())
	{
		loadData();
		emit changed(true);
	}
	else
	{
		Dialogs::critDlg(tr("Couldn't generate the boot menu!"));
	}
}

/** Moves a bootentry up
	*/
void ModGrubconf::bootentryUp()
{
	changeListPlace(true);
	emit changed(true);
}

/** Moves a bootentry down
 */
void ModGrubconf::bootentryDown()
{
	changeListPlace(false);
	emit changed(true);
}

/** Adds a bootentry and shows its properties.
 */
void ModGrubconf::bootentryAdd()
{
	GrubBootentry* gbeNewEntry = new GrubBootentry("", "", "");
	FrmBootproperties *fbp = new FrmBootproperties(gbeNewEntry, this);
	if (fbp->exec() == QDialog::Accepted)
	{
		grubConf.addBootmenuEntry(gbeNewEntry);
		FillBootentryList();
		emit changed(true);
	}
	delete fbp;
}

/** Deletes a bootentry
 */
void ModGrubconf::bootentryDelete()
{
	QPtrList<GrubBootentry> bootEntries = grubConf.getBootmenuEntries();

	int selectedIndex = getQCheckListItemPos((QListViewItem*)lvwAdvanced->selectedItem());
	if (selectedIndex < 0 || selectedIndex >= bootEntries.count())
		return;

	grubConf.removeBootmenuEntry(selectedIndex);
	FillBootentryList();
	emit changed(true);
}

/** Shows the properties of a bootentry
 */
void ModGrubconf::bootentryProperties()
{
	QPtrList<GrubBootentry> bootEntries = grubConf.getBootmenuEntries();
	int selectedIndex = getQCheckListItemPos((QListViewItem*)lvwAdvanced->selectedItem());
	if (selectedIndex < 0 || selectedIndex >= bootEntries.count())
		return;

	FrmBootproperties *fbpProperties = new FrmBootproperties(bootEntries.at(selectedIndex), this);
	if (fbpProperties->exec() == QDialog::Accepted)
	{
		FillBootentryList();
		emit changed(true);
	}
	delete fbpProperties;
}

/** Sets the default bootentry
 */
void ModGrubconf::defaultBootentry()
{
	changeDefaultBootentry();
	emit changed(true);
}

/** Returns the position of the listitem in the checklist
 */
int ModGrubconf::getQCheckListItemPos(const QListViewItem * item)
{
	int i = 0;
	QListViewItem *it = lvwAdvanced->firstChild()->firstChild();
	while (it)
	{
		if (item == it)
			return i;

		it = it->nextSibling();
		++i;
	}
	return i;
}

/** Opens the browse dialog for the splashimage
 */
void ModGrubconf::splashimageFileDialog()
{
	QString splashimage = QFileDialog::getOpenFileName("/home",
	                      "GRUB splash image (*.xpm.gz)",
	                      this,
	                      "open file dialog",
	                      tr("Choose a GRUB-compatible splash image"));

	this->txtSplashImage->setText(splashimage);
	emit changed(true);
}

ModGrubconf::~ ModGrubconf()
{}

/** Changes the place of one entry in the list one entry up or down
	*/
void ModGrubconf::changeListPlace(bool up)
{
	int diff = (up ? -1 : 0);

	QPtrList<GrubBootentry> bootEntries = grubConf.getBootmenuEntries();

	int selectedIndex = getQCheckListItemPos((QListViewItem*)lvwAdvanced->selectedItem());
	if (up)
	{
		if (selectedIndex <= 0 || selectedIndex >= bootEntries.count())
			return;
	}
	else
	{
		if (selectedIndex < 0  || selectedIndex >= bootEntries.count() - 1)
			return;
	}

	QPtrList<GrubBootentry> *newBootEntries = new QPtrList<GrubBootentry>();
	for (int i = 0; i < selectedIndex + diff; ++i)
		newBootEntries->append(bootEntries.at(i));

	if (up)
	{
		newBootEntries->append(bootEntries.at(selectedIndex));
		newBootEntries->append(bootEntries.at(selectedIndex - 1));
	}
	else
	{
		newBootEntries->append(bootEntries.at(selectedIndex + 1));
		newBootEntries->append(bootEntries.at(selectedIndex));
	}

	for (uint i = (selectedIndex + diff + 2); i < bootEntries.count(); ++i)
		newBootEntries->append(bootEntries.at(i));

	grubConf.setBootmenuEntries(*newBootEntries);

	QListViewItem *item = lvwAdvanced->selectedItem();

	if (up)
		item->itemAbove()->moveItem(item);
	else
		item->moveItem(item->itemBelow());
}

/** Shows/Hides the default bootentry column.
 	*/
void ModGrubconf::polish()
{
	changeDefaultBootentry();
}

void ModGrubconf::changeTimeout()
{
	grubConf.setTimeout(spnTimeout->value());
	emit changed(true);
}

void ModGrubconf::splashimageStateChanged()
{
	grubConf.setSplashimagePath(new QString(""));
	emit changed(true);
}

void ModGrubconf::colorStateChanged()
{
	emit changed(true);
}

void ModGrubconf::bootentryDefault()
{
	int i = 0;
	QListViewItem *it = lvwAdvanced->firstChild()->firstChild();
	while (it)
	{
		if (((QCheckListItem*)it)->state() == QCheckListItem::On)
			if (i != grubConf.getDefaultTitle())
				emit changed(true);

		it = it->nextSibling();
		++i;
	}



}

void ModGrubconf::changeDefaultBootentry()
{
	switch (rbgDefaultBootentry->selectedId())
	{
		case 0:
		{	//save [nr]
			lvwAdvanced->setColumnWidth(0, 55);
			lvwAdvanced->setResizeMode(QListView::LastColumn);
			grubConf.setDefaultTitle(0);
			break;
		}
		case 1:
		{	//save default
			lvwAdvanced->hideColumn(0);
			lvwAdvanced->setResizeMode(QListView::LastColumn);

			break;
		}
	}
}

void ModGrubconf::loadData()
{
	FillBootentryList();

	//Sets the timeout
	spnTimeout->setValue(grubConf.getTimeout());

	//Default Bootentry
	if (grubConf.getDefaultTitle() == -1)
		rbgDefaultBootentry->setButton(1);	//save default
	else
		rbgDefaultBootentry->setButton(0);	//save [nr]

	changeDefaultBootentry();

	if (grubConf.getSplashimagePath() == NULL)
		chbSplashImage->setChecked(false);
	else
	{
		txtSplashImage->setText(*grubConf.getSplashimagePath());
		chbSplashImage->setChecked(true);
	}

	if (grubConf.getColorHighlightBackground() == NULL)
		chbColor->setChecked(false);
	else
	{
		cmbColorForeNormal->setCurrentItem((grubConf.getColorNormalForeground() == NULL ? 0 : *grubConf.getColorNormalForeground()));
		cmbColorForeHighlight->setCurrentItem((grubConf.getColorHighlightForeground() == NULL ? 0 : *grubConf.getColorHighlightForeground()));
		chbBlinkNormal->setChecked((grubConf.getNormalBlink() == NULL ? 0 : *grubConf.getNormalBlink()));

		cmbColorBackNormal->setCurrentItem((grubConf.getColorNormalBackground() == NULL ? 0 : *grubConf.getColorNormalBackground()));
		cmbColorBackHighlight->setCurrentItem((grubConf.getColorHighlightBackground() == NULL ? 0 : *grubConf.getColorHighlightBackground()));
		chbBlinkHighlight->setChecked((grubConf.getHighlightBlink() == NULL ? 0 : *grubConf.getHighlightBlink()));

		chbColor->setChecked(true);
	}
}

/** Installs GRUB on the computer
	*/
void ModGrubconf::installGrub()
{
	if (grubConf.installGrub())
	{
		Dialogs::infoDlg(tr("GRUB was installed successfully."));
		if (Dialogs::question(tr("Do you want to generate a suitable\n"
										 "configuration for your computer now?")))
			this->generateBootmenu();
	}
	else
		Dialogs::critDlg(tr("Error: Couldn't install GRUB!"));
}
