/*
 * 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 <qtextedit.h>
#include <qradiobutton.h>
#include <qapplication.h>
#include <qcombobox.h>
#include <qwidgetstack.h>
#include <qlineedit.h>
#include <qpushbutton.h>
#include <qlabel.h>
#include <qstringlist.h>
#include <stdio.h>

#include "size.h"
#include "modgrubconf.h"
#include "mntdevice.h"
#include "fsdevice.h"
#include "frmbootproperties.h"
#include "grubbootentry.h"
#include "grubcommand.h"


/** Initializes a new instance of the FrmBootproperties class
	* by loading the data from the bootentry on the GUI
	*/
FrmBootproperties::FrmBootproperties(GrubBootentry* bootentry, QWidget* parent, const char* name, bool modal, WFlags fl)
		: UiFrmBootProperties(parent, name, modal, fl)
{
	connect(btnOK, SIGNAL(clicked()), this, SLOT(save()));
	connect(cmbTyp, SIGNAL(activated(int)), this, SLOT(changeType()));

	this->bootentry = bootentry;
	txtName->setText(bootentry->getValue());

	cmbTyp->setCurrentItem((int)bootentry->getOsType());
	wdsTyps->raiseWidget((int)bootentry->getOsType());
	switch (bootentry->getOsType())
	{
		case 1:	//Linux
			if (bootentry->getKernel() != NULL)
				txtKernel->setText(*bootentry->getKernel());
			if (bootentry->getInitrd() != NULL)
				txtInitrd->setText(*bootentry->getInitrd());
			break;
		case 0:	//BSD
		case 2:	//Windows
		case 3:	//Mac
			break;
		case 4:	//Other
			txtOther->setText(bootentry->getLines());
			break;
	}

	changeType();
	buildPartitionCmb();

	if (bootentry->getRoot() != NULL)
	{
		QString *root = bootentry->getRoot();
		root->lower();
		root->remove("(");
		root->remove(")");
		QStringList list = QStringList::split(QChar(','), *root);
		QString rootConverted = QString();

		for (QStringList::Iterator it = list.begin(); it != list.end(); ++it)
		{
			QString value = *it;
			value.remove(",");
			value.stripWhiteSpace();
			rootConverted += value;
			rootConverted += ",";
		}
		rootConverted.remove(rootConverted.length() - 1, 1);
		rootConverted.remove(" ");
		rootConverted = '(' + rootConverted + ')';
		int i = 0;
		QString * value;
		QPtrListIterator<QString> it(this->root);
		while ((value = it.current()) != NULL)
		{
			++it;
			if (value->compare(rootConverted) == 0)
			{
				this->cmbPartition->setCurrentItem(i);
				return;
			}
			i++;
		}
		this->cmbPartition->setCurrentItem(cmbPartition->count() - 1);
	}
}

/** Saves the changes in the bootentry
	*/
void FrmBootproperties::save()
{
	bootentry->setOsType((GrubBootentry::Ostypes)cmbTyp->currentItem());
	bootentry->setValue(txtName->text());
	QString root;
	switch (cmbTyp->currentItem())
	{
		case 1:	//Linux
			root = *this->root.at(this->cmbPartition->currentItem());
			if (root.compare("Invalid") != 0)
				bootentry->setRoot(new QString(root));
			bootentry->setKernel(new QString(txtKernel->text()));
			bootentry->setInitrd(new QString(txtInitrd->text()));
			break;
		case 0:	//BSD
		case 2:	//Windows
		case 3:	//Mac
			root = *this->root.at(this->cmbPartition->currentItem());
			if (root.compare("Invalid") != 0)
				bootentry->setRoot(new QString(root));
			break;
		case 4:	//Other
			bootentry->setLines(txtOther->text());
			break;
	}
}

/** Changes the type of the current bootentry and shows other elements on the GUI
	*/
void FrmBootproperties::changeType()
{
	switch (cmbTyp->currentItem())
	{
		case 1:	//Linux
			lblTyp->setText(cmbTyp->currentText());
			wdsTyps->raiseWidget(0);
			txtKernel->show();
			lblKernel->show();
			txtInitrd->show();
			lblInitrd->show();
			cmbPartition->show();
			lblPartition->show();
			break;
		case 0:	//BSD
		case 2:	//Windows
		case 3:	//Mac
			lblTyp->setText(cmbTyp->currentText());
			wdsTyps->raiseWidget(0);
			txtKernel->hide();
			lblKernel->hide();
			cmbPartition->show();
			lblPartition->show();
			txtInitrd->hide();
			lblInitrd->hide();
			break;
		case 4:	//Other
			lblTyp->setText(cmbTyp->currentText());
			wdsTyps->raiseWidget(1);
			bootentry->setLines(txtOther->text());
			break;
	}
}

void FrmBootproperties::buildPartitionCmb()
{
	cmbPartition->clear();
	this->root.clear();
	QPtrList<MntDevice> devices = MntDevice::getAllDevices();
	int hdCount = 0;

	for (int i = (devices.count() - 1); i >= 0; --i)
	{
		MntDevice *dev = devices.at(i);
		if ((dev->getDeviceType() == Device::ATA_Disk ||
		      dev->getDeviceType() == Device::ATA_RAID) &&
		      (dev->subdevCount() > 0))
		{
			//dev->readDescription();
			cmbPartition->insertItem(dev->getDesc());
			this->root.append(new QString(QString("(hd%1)").arg(hdCount)));

			appendPartitions(dev, hdCount);
			hdCount++;
		}
	}

	for (int i = (devices.count() - 1); i >= 0; --i)
	{
		MntDevice *dev = devices.at(i);
		if (dev->getDeviceType() == Device::SCSI_DirectAccess && dev->subdevCount() > 0)
		{
			//dev->readDescription();
			cmbPartition->insertItem(dev->getDesc());
			this->root.append(new QString(QString("(hd%1)").arg(hdCount)));

			appendPartitions(dev, hdCount);
			hdCount++;
		}
	}

	cmbPartition->insertItem(tr("Invalid"));
	this->root.append(new QString("Invalid"));
}

void FrmBootproperties::appendPartitions(MntDevice *& dev,  int & hdCount)
{
	for (uint j = 0; j < dev->subdevCount(); ++j)
	{
		MntDevice *devPartition = (*dev)[j];

		QString size = devPartition->getSize().toString(Size::GB);
		if (!size.compare("0 GB"))
			size = devPartition->getSize().toString(Size::MB);
		cmbPartition->insertItem("  " + devPartition->getDesc() + " - " + size);

		this->root.append(new QString(QString("(hd%1,%2)").arg(hdCount).arg(j)));

		for (uint k = 0; k < devPartition->subdevCount(); ++k)
		{
			MntDevice *devLogPartition = (*devPartition)[k];

			size = devLogPartition->getSize().toString(Size::GB);
			if (!size.compare("0 GB"))
				size = devLogPartition->getSize().toString(Size::MB);
			cmbPartition->insertItem("    " + devLogPartition->getDesc() + " - " + size);

			this->root.append(new QString(QString("(hd%1,%2,%3)").arg(hdCount).arg(j).arg('a' + k)));
		}
	}
}
