#include <dbsdglobal.h>
#include <dbsdiconloader.h>

#include <mntdevice.h>
#include <user.h>
#include <users.h>
#include <frmadduser.h>
#include <frmchangepasswd.h>
#include <unixprocess.h>
#include <dbsdsettings.h>
#include <translation.h>
#include <dialogs.h>
#include <executor.h>
#include <hostname.h>

#include <kapplication.h>
#include <qfileinfo.h>
#include <qfile.h>
#include <qtextstream.h>
#include <qstringlist.h>
#include <qmessagebox.h>
#include <qeventloop.h>
#include <qprogressdialog.h>
#include <qvalidator.h>
#include <qregexp.h>

#define LANG_DESC_COL 0
#define LANG_CODE_COL 1
#define LANG_FILE_COL 2

void frmInitialConfWizard::init() {
   QFileInfo fi("/usr/local/share/desktopbsd/initialconf/configured");
   if(fi.exists()) {
      Dialogs::infoDlg(tr("This system has already been configured."));
      exit(0);
   }

	Translation::translateWizard(this);

	DBSDIconLoader *iload = DBSDGlobal::getIconLoader();
	pixDesktopBSD->setPixmap(iload->loadIcon("desktopbsd", DBSDIconLoader::Size32x32));
	btnAddUser->setIconSet(iload->loadIcon("personal", DBSDIconLoader::Button));
	btnSetRootPw->setIconSet(iload->loadIcon("password", DBSDIconLoader::Button));
   pixUsers->setPixmap(iload->loadIcon("personal", DBSDIconLoader::Size48x48));
   pixLangAdd->setPixmap(iload->loadIcon("locale", DBSDIconLoader::Size32x32));
   pixLangList->setPixmap(iload->loadIcon("locale", DBSDIconLoader::Size32x32));
   pixHost->setPixmap(iload->loadIcon("network", DBSDIconLoader::Size48x48));
   pixBSDStats->setPixmap(iload->loadIcon("ktalkd", DBSDIconLoader::Size48x48));

	editHostname->setValidator(new QRegExpValidator(QRegExp("[a-zA-Z0-9]([-a-zA-Z0-9]{0,61}[a-zA-Z0-9])?(\\.[a-zA-Z0-9]([-a-zA-Z0-9]{0,61}[a-zA-Z0-9])?)*"), editHostname));

   helpButton()->hide();
   cancelButton()->hide();

	setFinishEnabled(pgBSDStats, true);

	addedUsers = 0;
	rootPasswdSet = false;
	userUpgradeInfoShown = false;
	
	/* Check "install support for addition languages" if
	 * a language other than English was selected at
	 * installation time.
	 */
	language = DBSDSettings().readEntry("/initialConf/language");
	chkLangAdd->setChecked(language != "en");
}


void frmInitialConfWizard::addUser() {
	frmAddUser dlg(this);
	if(dlg.exec() == QDialog::Accepted) {
		QString username = dlg.getUsername();
		User *u = Users::getUser(username);
		if(u != NULL && u->setGroupMemberships(QStringList::split(' ', "user mount wheel"))) {
			++addedUsers;
			checkUsersDone();
		}
	}
}


void frmInitialConfWizard::setSysPw() {
	User  *user = Users::getUser("root");
	if(user != NULL) {
		frmChangePasswd  dlg(this, NULL, true);
		dlg.setUser(*user);
		if(dlg.exec() == QDialog::Accepted)
			rootPasswdSet = true;

		checkUsersDone();
	}
}


void frmInitialConfWizard::checkUsersDone() {
	if(!nextButton()->isEnabled() && rootPasswdSet && addedUsers > 0) {
		Dialogs::infoDlg(tr("User configuration finished.\n"
								  "\n"
								  "You can click 'Next' to continue or add more users."));
		setNextEnabled(pgUsers, true);
	}
}


void frmInitialConfWizard::next() {
	if(currentPage() == pgLangAdd) {
		bool addLangs = chkLangAdd->isChecked();
		setAppropriate(pgLangList, addLangs);
		
		if(addLangs) {
			lstLanguages->clear();
			lstLanguages->header()->hide();
			
			/*
			 * Insert code here:
			 * - Mount the CD-ROM to /cdrom
			 * - Open folder (e.g. /languages)
			 * - Read index file (e.g. /languages/languages.index
			 * - Insert checkbox items into list
			 *
			 */
			 
			MntDevice cdrom("cd0");
			
			bool success = true;
			while(!cdrom.mount(MntDevice::ReadOnly, "/cdrom") || !QFileInfo("/cdrom/languages/languages.index").exists()) {
				if(cdrom.isMounted())
					cdrom.unmount();
			
				int result = QMessageBox::question(this,
															  tr("CD-ROM Error"),
															  tr("The information couldn't be read.\n"
																  "\n"
																  "Ensure the media is not damaged and inserted in the computer's\n"
																  "first CD-ROM drive, then click \"Retry\". Click \"Abort\" to skip\n"
																  "installing languages."),
															  QMessageBox::Retry,
															  QMessageBox::Abort,
															  QMessageBox::NoButton);

				if(result == QMessageBox::Abort) {
					success = false;
					break;
				}
			}
			
			if(success)
			{
				QFile f("/cdrom/languages/languages.index");
				if(f.open(IO_ReadOnly)) {
					QTextStream ts(&f);
					ts.setEncoding(QTextStream::UnicodeUTF8);
					
					QString line = ts.readLine();
					while(!ts.atEnd()) {
						QStringList sl = QStringList::split(':', line);
					
						QCheckListItem *li = new QCheckListItem(lstLanguages, sl[1], QCheckListItem::CheckBox);
						li->setText(LANG_CODE_COL, sl[0]);
						li->setText(LANG_FILE_COL, sl[2]);
						
						if(sl[0] == language)
							li->setOn(true);
						
						line = ts.readLine();
					}
					
					f.close();
				}
			}
			
			setAppropriate(pgLangList, success);
		}
	} else if(currentPage() == pgLangList) {
		QStringList files;
		
		/* Read the filename column of checked items into the "files" string list */
		for(QListViewItemIterator it(lstLanguages);  it.current() != NULL;  ++it) {
			QCheckListItem *item = (QCheckListItem *) it.current();
			if(item->isOn())
				files.append(item->text(LANG_FILE_COL));
		}
		
		QProgressDialog *pdlg = new QProgressDialog(tr("Installing languages..."), QString::null, files.count(), this);
		pdlg->setCaption("DesktopBSD");
		pdlg->setMinimumDuration(0);
		pdlg->setProgress(0);
		
		bool proceed = true;
		QEventLoop *ael = qApp->eventLoop();
		for(QStringList::Iterator it = files.begin();  proceed && it != files.end();  ++it) {
			UnixProcess p(QString("/usr/sbin/pkg_add"));
			p.addArgument("/cdrom/languages/" + *it);
			
			/* Redirect stderr to stdout, disable stdin */
			p.setCommunication(QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
			
			if(!p.start()) {
				/* Really shouldn't happen */
				Dialogs::warnDlg(tr("Cannot initialize installation!"));
				
			} else {
				while(p.isRunning())
					ael->processEvents(QEventLoop::WaitForMore);
			
				if(!p.normalExit() || p.exitStatus() != 0) {
					if(pdlg->progress() == files.count() - 1) {
						/* If this is the only or last package */
						Dialogs::warnDlg(tr("Installation of %1 failed:\n\n%2")
													.arg(*it)
													.arg(p.readStdout()));
					} else {
						int  result = QMessageBox::question(this,
																		tr("Installation failed"),
																		tr("Installation of %1 failed:\n"
																			"\n"
																			"%1\n"
																			"\n"
																			"Click 'Skip' to skip this package and proceed or 'Abort' to stop.")
																				.arg(*it)
																				.arg(p.readStdout()),
																		tr("Skip"),
																		tr("Abort"));
						proceed = !result;
					}
				}
				
				pdlg->setProgress(pdlg->progress() + 1);
			}
		}
		
		delete pdlg;
		MntDevice("cd0").unmount();
	} else if(currentPage() == pgHost)
	{
		if(!editHostname->hasAcceptableInput())
		{
			Dialogs::warnDlg(tr("The entered hostname is incorrect.\n"
									  "\n"
									  "Make sure it does not end with a hyphen."));
			return;
		}
	}
	
	QWizard::next();
	
	if(currentPage() == pgUsers)
	{
		if(!userUpgradeInfoShown)
		{
			userUpgradeInfoShown = true;
			
			/* Check if any users are members of user or mount */
			if(Executor::exec("egrep -q '^(user|mount):[^:]*:[0-9]+:[^:]+$' /etc/group") == Executor::NoError)
			{
				Dialogs::infoDlg(tr("If you're upgrading your system, you can safely\n"
										  "skip to the next step if you don't want to add\n"
										  "additional users or set a new system password."));
			} else
				setNextEnabled(pgUsers, false);
		}
	}
}


void frmInitialConfWizard::reject() {
  Dialogs::infoDlg(tr("You cannot cancel the system configuration."));
}


void frmInitialConfWizard::accept()
{
	QString hostname = editHostname->text();

	Executor::exec(QString("sed -i '' 's|HOSTNAME|%1|g' /etc/hosts").arg(hostname));
	Hostname::set(hostname);
	
	if(chkEnableBSDStats->isChecked())
	{
		QFile rc("/etc/rc.conf");
		if(rc.open(IO_WriteOnly | IO_Append))
		{
			QTextStream(&rc) << '\n' << "bsdstats_enable=\"YES\"" << '\n';
			rc.close();
		}
		
		QFile f("/etc/periodic.conf");
		if(f.open(IO_WriteOnly | IO_Append))
		{
			QTextStream stream(&f);
			
			stream << '\n' << "monthly_statistics_enable=\"YES\"" << '\n';
		
			if(chkBSDStatsIncludeHardware->isChecked())
				stream << "monthly_statistics_report_devices=\"YES\"" << '\n';

			if(chkBSDStatsIncludePorts->isChecked())
				stream << "monthly_statistics_report_ports=\"YES\"" << '\n';

			f.close();
		}
		
		/* Start a background process to report to BSDstats now */
		QProcess process(QStringList::split(' ', "/usr/local/etc/periodic/monthly/300.statistics -nodelay"));
		process.setCommunication(0);
		process.start();
	}
	
	QWizard::accept();
}

