/****************************************************************************
** ui.h extension file, included from the uic-generated form implementation.
**
** If you want to add, delete, or rename functions or slots, use
** Qt Designer to update this file, preserving your code.
**
** You should not define a constructor or destructor in this file.
** Instead, write your code in functions called init() and destroy().
** These will automatically be called by the form's constructor and
** destructor.
*****************************************************************************/
#include <qimage.h>
#include <qfile.h>
#include <stdlib.h>
#include <qtextstream.h>
#include <Q3ListViewItem>
#include <kio/job.h>
#include "pcinstall.h"
#include "addpartitiondialog.h"
#include "dialogkeyboard.h"
#include "editnetworkdialog.h"
#include "selectnetserver.h"
#include "ui_pcinstall.h"

void PCInstall::ProgramInit()
{
    // Check the currently running language
    if ( QFile::exists( "/PCBSDVERSION" ) )
    {
         QString Ver;

         QFile file( "/PCBSDVERSION" );
         if ( file.open( IO_ReadOnly ) ) {
             QTextStream stream( &file );
                 Ver = stream.readLine(); // line of text excluding '\n'
             file.close();
         }

         VersionLabel->setText(tr("Version:") + " " + Ver); 
    }

   

    // Set the variable to regenerate the custom slices
    regenCustomSlices = 1;

    // Default us to cd instead of DVD
    usingDVDmedia = 0;

    // Set our flag that we are not using a network install
    networkInstall = false;

    // Setup Translations
    nextButton()->setText(tr("Next"));
    backButton()->setText(tr("Back"));
    finishButton()->setText(tr("Finish"));
    cancelButton()->setText(tr("Cancel"));
    
    // Connect the Page changed Signal to the PageChangedSlot
    connect( this, SIGNAL(selected( const QString &)), this, SLOT(PageChangedSlot(const QString &)) );
    // Connect the checkLicAgree checkbox to slot for enabling next page access. 
    connect( checkLicAgree, SIGNAL( toggled(bool) ), this, SLOT( ChangeLicAgreeSlot( bool ) ) );
    
    
    // Connect the various username objects and slots to the check function
    connect( linePassword, SIGNAL( textChanged(const QString &) ), this, SLOT(passwordTextChanged() ) );
    connect( linePassword2, SIGNAL( textChanged(const QString &) ), this, SLOT(passwordTextChanged() ) );
    connect( linePassword2, SIGNAL(lostFocus()), this, SLOT(rootPasswordLineEditLostFocus()));
    
    // Connect the username fields to the enable / disable function for the pushbuttons
     connect( lineUserName, SIGNAL( textChanged(const QString &) ), this, SLOT(checkUserLinesChanged(const QString & ) ) );
     connect( lineFullName, SIGNAL( textChanged(const QString &) ), this, SLOT(checkUserLinesChanged(const QString & ) ) );
     connect( lineUserPassword, SIGNAL( textChanged(const QString &) ), this, SLOT(checkUserLinesChanged(const QString & ) ) );
     connect( lineUserPassword2, SIGNAL( textChanged(const QString &) ), this, SLOT(checkUserLinesChanged(const QString & ) ) );
     connect( lineUserPassword2, SIGNAL(lostFocus()), this, SLOT(userPasswordLineEditLostFocus()));
     connect( listBoxUsers, SIGNAL( selectionChanged ()  ), this, SLOT(listBoxUsersChanged() ) );
    
     
 
     
    // Connect the buttons for user management
    connect( pushAddUser, SIGNAL( clicked() ), this, SLOT( addUserButton() ) );
    connect( pushRemoveUser, SIGNAL( clicked() ), this, SLOT( removeUserButton() ) );
    connect( pushApplyUser, SIGNAL( clicked() ), this, SLOT(applyUserButton() ) );
    
    // Connect the drive boxes with slots that read drive info
    connect( listDriveBox, SIGNAL( selectionChanged() ), this, SLOT( readFDISKFilesSlot() ) );

    
    // Connect the use entire disk checkbox. 
    connect( checkBoxEntireDisk,  SIGNAL(clicked() ), this, SLOT( useEntireDiskSlot()  ) );

    // Connect the slice buttons
    connect( pushSliceAdd,  SIGNAL(clicked() ), this, SLOT( sliceAddSlot() ) );    
    connect( pushSliceEdit,  SIGNAL(clicked() ), this, SLOT( sliceEditSlot() ) );  
    connect( pushSliceRemove,  SIGNAL(clicked() ), this, SLOT( sliceRemoveSlot() ) );  
    
    // Enable / disable the buttons and UI for custom slice setup
    connect( checkCustomDiskSlice, SIGNAL( toggled(bool) ), this, SLOT( customDiskSliceSlot( bool ) ) );
    
    //Setup any regular expressions we will need
    passwordRegExp.setPattern("([a-z]*[A-Z]*[0-9]*[!\"�$%^&*()_+=�#'`@~:?<>|{}\\-.]*)+");
    
    // Make sure the disk slice selector is disabled by default until clicked
    customDiskSliceSlot( FALSE);
   
    // Set the default keyboard layouts
    textKBLayout->setText("us - USA");
    textKBModel->setText("pc105 - Generic 105-key PC");
    textKBVariant->setText("off - Using default layout");
	    
    // Load the Lang List
    loadLangs();
    
    // Load the TimeZone Info
    loadTZone();
    
    // List our filesystem types
    comboFileSystem->insertItem("UFS2");
    comboFileSystem->insertItem("UFS2 + Soft Updates");
    comboFileSystem->insertItem("UFS2 + Journaling");

    // Check if we booted with ZFS enabled or not
    if ( QFile::exists( "/tmp/zfsEnabled" ) )
    {
       comboFileSystem->insertItem("ZFS (Experimental)");
    }

    // Set the default FS to UFS2 + Soft Updates
    comboFileSystem->setCurrentItem(1);
    
    // Create our slot to check which FS the user has chosen
    connect( comboFileSystem,  SIGNAL( currentIndexChanged(const QString &) ), this, SLOT( checkFileSystemSlot(const QString &) ) );  

    
    // Load the HD info
    runFindDisk();
    
    // Connect the Upgrade List Box
    connect( listPartitionBoxUpgrade, SIGNAL( selectionChanged() ), this, SLOT( checkPartUpgradeBox() ) );

    
    // Set the variable indicating that we have no components ready to be installed.
    installComponents = 0;
	
    // Load our list of available components
    loadComponents();
    
   // Connection the listPartitionBox selection to a check slot
   connect( listPartitionBox, SIGNAL( selectionChanged() ), this, SLOT( checkPartitionSelectionSlot() ) );
   
    // Hide the help button for now
    helpButton()->setHidden(TRUE);
    
    // Read in the fdisk data
    readFDISKFilesSlot();
    
	
	

	// Check if VMware is running
	CheckVMware = new Q3Process( this );
	CheckVMware->addArgument( "/usr/local/pcbsd/scripts/PCBSD.CheckVMware.sh" );

	connect( CheckVMware, SIGNAL(processExited()), this, SLOT(checkVmwareSystemSlot()) );
	
	if ( !CheckVMware->start() ) {
	}
	
	//Initilise colours
	colourRed = QColor(255, 78, 78);
	colourWhite = QColor(255, 255, 255);
	
	

	

    // Connect the list box languages to the slot
    connect( listBoxLang, SIGNAL( selectionChanged () ), this, SLOT(listBoxLangChanged() ) );
    

    // Load the license text
    loadLicense();

    
}






void PCInstall::PageChangedSlot( const QString &Page )
{
    
    
    // Disable the HELP button
    setHelpEnabled(currentPage(), FALSE);
    helpButton()->setHidden(TRUE);
    
    if ( Page == tr("Select Language and Keyboard") )
    {
	//backButton()->setHidden(TRUE);
	
    }
    
     if ( Page == tr("License") )
    {
	 backButton()->setHidden(FALSE);
	 
	// Check if we need to disable the next button
	if (! checkLicAgree->isChecked() )
	{
	   setNextEnabled(currentPage(), FALSE);
                }
	
	
	   NumlockProc = new Q3Process( this );
	   NumlockProc->addArgument( "/usr/local/pcbsd/scripts/PCBSD.EnableNumlock.sh" );
	   NumlockProc->start();
    }
    
    
    if ( Page == tr("Install or Update") )
    {
       //Removed, we sometimes need to go back to this page. Especially helpful in testing.
       //setBackEnabled(currentPage(), FALSE);
    }
    
    if ( Page == tr("System Components") )
    {
	
    }
    

    
    if ( Page == tr("User Accounts") )
    {
	// Stop the user from continuing until username and passwords are setup
	CheckAccountInfo();
	
	
    }
    
      if ( Page == tr("Disk Selection") )
    {
	
	setNextEnabled(currentPage(), FALSE);
	
	// Dont let user go forward until they select a partition / drive
	  if ( checkBoxEntireDisk->isChecked() )
	  {
	   setNextEnabled(currentPage(), TRUE);
                  } else {
           // Save the status flag for the custom slice regen
           int oldstatus = regenCustomSlices;
	   checkPartitionSelectionSlot();
           regenCustomSlices = oldstatus;
	  }
               
    }
    
    
        if ( Page == tr("Advanced Disk Setup") )
    {
	
	if ( regenCustomSlices == 1) {
	   // Setup the initial slice layout
	   setupInitialSlices();
	   regenCustomSlices = 0;
                }
		
	// Display slices on GUI
	populateSlices();

    }
    
    
    if ( Page == tr("Select Update Partition") )
    {
	
	listPartitionBoxUpgrade->clear();
	
	setNextEnabled(currentPage(), FALSE);
	//setBackEnabled(currentPage(), FALSE);
	textUpdatePart->setText(tr("Please wait.. Checking for existing PC-BSD Installs"));
	
	// Run the script to get PC-BSD installs
	FindUpgradeParts = new Q3Process( this );
	FindUpgradeParts->addArgument( "/usr/local/pcbsd/scripts/PCBSD.FindUpdateParts.sh" );

	connect( FindUpgradeParts, SIGNAL(processExited()), this, SLOT(readAvailUpgradesSlot()) );
	if ( !FindUpgradeParts->start() ) {
	    // error handling
	    //QMessageBox::warning( this, "PCBSD Installer",  SelectedDrive, "Retry", "Quit", 0, 0, 1 );
	}
	

    }
    
    if ( Page == tr("Start Basic Install") )
    {

    }
    

    

  
    if ( Page == tr("Installing PC-BSD") )
    {
        // Check if we needed to regen the slices for ZFS
        if ( regenCustomSlices == 1) {
	   // Setup the initial slice layout
	   setupInitialSlices();
	   regenCustomSlices = 0;
	   populateSlices();
        }


	setBackEnabled(currentPage(), FALSE);
	setNextEnabled(currentPage(), FALSE);
	
	cancelButton()->setEnabled(TRUE);
	cancelButton()->setHidden(FALSE);
	
	// Display the promo ads
	PromoAd = 1;
        changePromoAd();
	
         // Setup the length of our progress bars
        calcProgressBarSize();

        // If we are on a network install, skip the CD mount and format the drive first
        if ( networkInstall) {
          usingDVDmedia = 1;
          
     
          // Now start the install / update 
          if ( radioFreshInstall->isChecked() )
          {
            // Skip the CD mount, will download direct from net instead
            startFreshInstall();
          } else {
            startUpdateProcess();
          }
	

        } else {
          // Using a CD / DVD / USB, so mount it first
	  startMountCD();
        }
	
    }
    
    if ( Page == tr("Installation Finished!") )
    {
	cancelButton()->setEnabled(FALSE);
	cancelButton()->setHidden(TRUE);
	finishButton()->setText(tr("&Reboot"));
    }
    
    
}


void PCInstall::ChangeLicAgreeSlot( bool clicked )
{
    
    if ( clicked)
    {
	// Enable the next button now
	setNextEnabled(page(1), TRUE);	
    } else {
	// Disable the next button
	setNextEnabled(page(1), FALSE);       
    }
    
}



void PCInstall::loadLangs()
{
    QString tmp;
    QString Langcode;
    QString Langdescr;
    QString nlang = "";
    int count = 0, found = 0;
    
    listBoxLang->clear();
    
    // Check the currently running language
    if ( QFile::exists( "/root/.langchange" ) )
    {

	     QFile file( "/root/.langchange" );
	     if ( file.open( IO_ReadOnly ) ) {
		 QTextStream stream( &file );
		     nlang = stream.readLine(); // line of text excluding '\n'
		 file.close();
	     }

    }



    QFile file( "/root/Langs" );
    if ( file.open( IO_ReadOnly ) ) {
	QTextStream stream( &file );
	QString line;
	while ( !stream.atEnd() ) {
	    line = stream.readLine(); // line of text excluding '\n'
	    tmp = line;
	    tmp.truncate(tmp.find(" ") );
	    Langcode = tmp;
	    
            
	    
	    Langdescr = line.remove(0, line.find(" ") + 1 );     
	    
	    listBoxLang->insertItem(Langdescr + " (" + Langcode + ")" );   

	    if ( nlang == Langcode ) {
		listBoxLang->setSelected(count, TRUE); 
		found = 1;
	    }

            count++;
	}
	file.close();
    }

    if (found == 0) {
	listBoxLang->setSelected(0, TRUE); 
    }

}


void PCInstall::loadTZone()
{
    
    QFile file( "/root/zones" );
    if ( file.open( IO_ReadOnly ) ) {
	QTextStream stream( &file );
	QString line;
	while ( !stream.atEnd() ) {
	    line = stream.readLine(); // line of text excluding '\n'
	    
	    comboTZone->insertItem(line);
	}
	file.close();
    }
    
    comboTZone->setCurrentItem(124);
}



void PCInstall::CheckAccountInfo()
{
    int ok = 0;
    
    if ( linePassword->text() == "" )
    {
       	textAcctNotify->setText("");
	ok = 1;
    }
    
    // Check if we hav e a username setup. 
    if ( AddUserName[0].isEmpty() )
    {
	textAcctNotify->setText(tr("You must setup at least one username to continue. "));
	ok = 1;
    }
    
    if ((linePassword->text() != linePassword2->text()) || linePassword->text().isEmpty())
    {
	ok = 1;
    }
    
    if(ok == 0)
    {
	linePassword->unsetPalette();
	linePassword2->unsetPalette();
	textAcctNotify->setText("");
	setNextEnabled(currentPage(), TRUE);	
    } else {
          setNextEnabled(currentPage(), FALSE);	
    }
    
}


void PCInstall::passwordTextChanged()
{
  CheckAccountInfo();
}


void PCInstall::reject()
{
    switch( QMessageBox::warning( this, tr("Exit Confirmation"), tr("Are you sure you want to quit? The system will be rebooted!"), tr("OK"), tr("Cancel"), 0, 0, 1 ) ) {
	     case 0: // The user clicked the OK again button or pressed Enter
		 exit(1);
		 break;
	     case 1: // The user clicked the Quit or pressed Escape
		 break;
	     }
}


void PCInstall::addUserButton()
{
    int i = 0;

    while ( i < 100)
    {

	if ( AddUserName[i] == "" )
	{
	   break;   
	}
		
	i++;
    }
    

    AddUserName[i] = lineUserName->text();
    AddRealName[i] = lineFullName->text();
    AddPassword[i]    = lineUserPassword->text();
    
    if ( comboShell->currentItem() == 0)
    {
	AddShell[i] = "/bin/csh";  
    } else if ( comboShell->currentItem() == 1) {
	AddShell[i] = "/bin/tcsh";
    } else if ( comboShell->currentItem() == 2) {
	AddShell[i] = "/bin/sh";
    } else {
	AddShell[i] = "/PCBSD/local/bin/bash";
    }
 

    
    refreshUsers();
    CheckAccountInfo();
    
    lineUserName->setText("");
    lineFullName->setText("");
    lineUserPassword->setText("");
    lineUserPassword2->setText("");
    listBoxUsers->setCurrentItem(-1);
    
    checkUserLinesChanged("");
    
    
}



void PCInstall::removeUserButton()
{
    
    int rmUser;
    int i;
    
    if ( listBoxUsers->currentItem() != -1)
    {
	rmUser = listBoxUsers->currentItem();
	i = rmUser;
	
	AddUserName[i] = "";
	i++;
	
	while ( i < 100 )
	{
	    
	    if ( AddUserName[i].isEmpty() )
	    {
		break;
	    }
	    
	     AddUserName[i-1] = AddUserName[i];
	    AddRealName[i-1] = AddRealName[i];
	    AddPassword[i-1] = AddPassword[i];
	    AddShell[i-1] = AddShell[i];
	    
	    AddUserName[i]="";
	    AddRealName[i] = "";
	    AddPassword[i]="";
	    AddShell[i]="";
	    
	    i++;
	}
    }

    refreshUsers();
    CheckAccountInfo();
    checkUserLinesChanged("");    
}



// Redraws the user box
void PCInstall::refreshUsers()
{
    
    listBoxUsers->clear();
    

        int i = 0;
    
    while ( i < 100)
    {
	
	if ( AddUserName[i] == "" )
	{
	   break;   
	}

	listBoxUsers->insertItem(AddUserName[i] + " (" + AddRealName[i] + ") - " + AddShell[i]);

	i++;
    }
    
    
    if ( i > 0 )
    {
	listBoxUsers->setCurrentItem(0);	
    }
    
    
}


void PCInstall::runFindDisk()
{
        // Start a process to get Disks from custom script output
    FindDisk = new Q3Process( this );
    FindDisk->addArgument( "/usr/local/pcbsd/scripts/PCBSD.FindDisk.sh" );

    connect( FindDisk, SIGNAL(readyReadStdout()), this, SLOT(readFindDiskSlot()) );
    if ( !FindDisk->start() ) {
	// error handling
	//QMessageBox::warning( this, "PCBSD Installer",  SelectedDrive, "Retry", "Quit", 0, 0, 1 );
    }

    
    
}


void PCInstall::readFindDiskSlot()
{
    QString Buffer;
     QString DevLabel;
    int i = 0;
    
    while ( i< 100) 
    {
	if ( Drives[i].isEmpty() )
	{
	 break;   
	}
	i++;
    }
    
        // Loop while getting input
    while (FindDisk->canReadLineStdout() )
    {
	
	
	// Read the line
	Buffer = FindDisk->readLineStdout();
	Drives[i] = Buffer;
	Drives[i].truncate(Drives[i].find(":") );
	
	if (Buffer.find(">") < 90 && Buffer.find(">") != -1)
	{
	    Buffer.truncate(Buffer.find(">") + 1);
	} else {
	    Buffer.truncate(90);
	}
	
	
	if ( Buffer.find("ad", 0) != -1 )
	{
	    DevLabel="(ATA / IDE Device)";
	} else if (Buffer.find("da", 0) != -1 ) {
	    DevLabel="(SCSI / Removable Device)";
	} else {
	    DevLabel="";
	}
	
	listDriveBox->insertItem("/dev/" + Buffer + " " + DevLabel);
	

	
	i++;
    }

}


void PCInstall::readFDISKFilesSlot()
{
    
    // Reset the list box
    listPartitionBox->clear();
    
    // Make sure to set flag to regenerate slice layout for custom partitions
    regenCustomSlices = 1;
    
    
    if ( listDriveBox->currentItem() == -1)
    {
	checkBoxEntireDisk->setEnabled(FALSE);
	return;
    } else {
	checkBoxEntireDisk->setEnabled(TRUE);
    }
   
    
    int item = listDriveBox->currentItem();
    QString device = Drives[item];
    QString Buffer;
    QString Megabytes;
    QString BlockLine;
    QString StartBlock;
    QString TotalBlocks;
    QString tmp;
   
    Q_LLONG DriveBlks = 0;
    Q_LLONG TotalDriveMB;
    Q_LLONG AvailMB;
    Q_LLONG tmpLong;
    
    int i = 1;
    int usingExtended = 0;
    
    
    
QFile file( "/tmp/" + device );
    if ( file.open( IO_ReadOnly ) ) {
	QTextStream stream( &file );
	while ( !stream.atEnd() ) {
	    Buffer = stream.readLine(); // line of text excluding '\n'
	  
	//QMessageBox::warning( this, "Msg",  "StartBlock: " + StartBlock , "Retry", "Quit", 0, 0, 1 );

	// Get the total blocks of the drive, to see if any free space available
	if(Buffer.find("cylinders=") == 0)
	{

	    // Get the cylinders
	    tmp = Buffer;
	    tmp = tmp.replace("cylinders=", "");
	    tmp.truncate(tmp.find(" "));
	    DriveBlks = tmp.toLongLong();
	    DriveCyl = tmp.toLongLong();
	    //QMessageBox::warning( this, "Msg",  "Cylinders " + tmp , "Retry", "Quit", 0, 0, 1 );

	    // Get the heads
	    tmp = Buffer;
	    tmp.remove(0, tmp.find("heads=") + 6 );
	    tmp.truncate(tmp.find(" "));
	    DriveBlks = DriveBlks * tmp.toLongLong();
	    DriveHead = tmp.toLongLong();
	    //QMessageBox::warning( this, "Msg",  "Heads " + tmp , "Retry", "Quit", 0, 0, 1 );

	    // Get the sectors / tracks
	    tmp = Buffer;
	    tmp.remove(0, tmp.find("sectors/track=") + 14);
	    tmp.truncate(tmp.find(" "));
	    DriveBlks = DriveBlks * tmp.toLongLong();
	    DriveSec = tmp.toLongLong();

	    TotalDriveBlocks.setNum(DriveBlks);

	    //QMessageBox::warning( this, "Msg",  "Sectors " + tmp , "Retry", "Quit", 0, 0, 1 );

	    //QMessageBox::warning( this, "Msg",  "TotalBlks " + tmp.setNum(DriveBlks) , "Retry", "Quit", 0, 0, 1 );
	}

	// Load the partition information
	if (Buffer.find("The data for partition " +tmp.setNum(i) + " is:") != -1 )
	{
	    // Get the next line, which has critical info
	    Buffer = stream.readLine(); // line of text excluding '\n'
	    
	    if ( Buffer.find("Extended") != -1 )
	    {
		usingExtended = 1;
	    }
	    
	    if (Buffer.find("<UNUSED>") == -1 && Buffer.find("Extended") == -1 && i < 5 )
	    {
		// Start picking apart line for information
		Buffer.remove(0, Buffer.find(",") + 1 );

		// Get the next fdisk line,  blocks and MB size
		BlockLine = stream.readLine(); // line of text excluding '\n'
		BlockLine = BlockLine.stripWhiteSpace();
		Megabytes = BlockLine.section(" ", 4, 4);
		Megabytes.remove(0, 1);

		//QMessageBox::warning( this, "Msg",  "MB: " + Megabytes, "Retry", "Quit", 0, 0, 1 );
		PartitionMB[i] = Megabytes;
		
		// Add info to partition list box.
		listPartitionBox->insertItem("/dev/" + device + "s" + tmp.setNum(i) + ": " + Megabytes + " MB "  + Buffer);

		StartBlock = BlockLine.section(" ", 1, 1);
		StartBlock.truncate(StartBlock.length() -1 );

		PartitionStartBlk[i] = StartBlock;

		//QMessageBox::warning( this, "Msg",  "StartBlock: " + StartBlock , "Retry", "Quit", 0, 0, 1 );
		TotalBlocks = BlockLine.section(" ", 3, 3);

		PartitionTotalBlk[i] = TotalBlocks;

		//QMessageBox::warning( this, "Msg",  "TotalBlock: " + TotalBlocks , "Retry", "Quit", 0, 0, 1 );

	    }


	    i++;
	}


   
	    
	    
	}
	file.close();
	
	
	// Now check for any additional free space on this drive
        // KPM 8-12-08, change method to determine size of disk
	//tmp = listDriveBox->currentText();
	//tmp.remove(0, tmp.find(" ") + 1);
	//tmp.truncate(tmp.find("MB"));
        tmp = BlocksToMB(TotalDriveBlocks);
	TotalDriveMB = tmp.toLongLong();
	//QMessageBox::warning( this, "Msg",  "Drive MB: " + tmp , "Retry", "Quit", 0, 0, 1 );
	
               AvailMB = TotalDriveMB;
	tmpLong = 63;
	
	i = 1;
	while ( ! PartitionMB[i].isEmpty() ) {
	    
	    AvailMB = AvailMB - PartitionMB[i].toLongLong();
	    tmpLong = tmpLong + PartitionTotalBlk[i].toLongLong();
	    
	    
	    i++;
	}
	
	//QMessageBox::warning( this, "Msg",  "Avail MB: " + Buffer.setNum(AvailMB) , "Retry", "Quit", 0, 0, 1 );
	
	if ( AvailMB > 1  && i <= 4 && usingExtended == 0)
	{	     
	    	PartitionMB[i] = tmp.setNum(AvailMB);
		PartitionStartBlk[i] = tmp.setNum(tmpLong);
		PartitionTotalBlk[i] = tmp.setNum(DriveBlks - tmpLong);
		// Add info to partition list box.
		listPartitionBox->insertItem("/dev/" + device + "s" + tmp.setNum(i) + ": " + PartitionMB[i] + " MB "  + "Free Space");
	}
	
	
	
    }
}



void PCInstall::useEntireDiskSlot()
{
     // Make sure to set flag to regenerate slice layout for custom partitions
    regenCustomSlices = 1;
    
    if ( checkBoxEntireDisk->isChecked() )
    {
	listPartitionBox->setEnabled(FALSE);
	setNextEnabled(currentPage(), TRUE);
    } else { 
	listPartitionBox->setEnabled(TRUE);
	setNextEnabled(currentPage(), FALSE);
	checkPartitionSelectionSlot();
    }

}


void PCInstall::checkPartitionSelectionSlot()
{
   // Make sure to set flag to regenerate slice layout for custom partitions
   regenCustomSlices = 1;
    
    textPartInfo->setText("");
    int SelPartition;
    QString tmp;
    Q_LLONG PartMB;
    
    int item = listPartitionBox->currentItem();
 
    
    if ( item == -1 )
    {
	setNextEnabled(currentPage(), FALSE);
	return;
    }
    
    	tmp= listPartitionBox->currentText();
	tmp.truncate(tmp.find(":") );
	tmp.remove(0, tmp.length() -1 );
	SelPartition = tmp.toInt();
    
    
      // item++;
     //QMessageBox::warning( this, "Msg",  "MB" + PartitionMB[SelPartition], "Retry", "Quit", 0, 0, 1 );
     PartMB = PartitionMB[SelPartition].toLongLong();
     

    if ( PartMB < 4000 )
   {
	textPartInfo->setText(tr("Error: PC-BSD needs a partition with at least 4GB of space."));
	setNextEnabled(currentPage(), FALSE);
	return;
    }

    setNextEnabled(currentPage(), TRUE);
    
}


void PCInstall::startFreshInstall()
{
    QString Geom;
    QString tmp;
    int item = listDriveBox->currentItem();
    QString device = Drives[item];
    
    // Get the current partition
    int PartNum = 1;
    

    
    // We are setting up entire drive with PC-BSD
    if (checkBoxEntireDisk->isChecked() )
    {
	    // Set the PC-BSD Partition
	   RootPartition = "/dev/" + device + "s1";
	   
	Geom = Sanitize_Bios_Geom(DriveCyl, DriveHead, DriveSec, TotalDriveBlocks);
	
	QFile file2( "/tmp/fdiskconfig" );
	if ( file2.open( IO_WriteOnly ) ) {
	    QTextStream stream2( &file2 );
	   // stream2 <<  "nonInteractive=YES\nnoWarn=YES\ndisk=" +device + "\ngeometry=" + Geom + "\npartition=all\nbootManager=boot\ndiskPartitionEditor\ndiskPartitionWrite";
	    stream2 << "g " + Geom + "\np 	1 	165 	1 	" + TotalDriveBlocks + "\na 	1";
	    file2.close();
	
	
    	textFileProgress->setText(tr("Running fdisk on /dev/") + device);
	installProgress->setProgress(2);
	FormatDrive = new Q3Process(this);
	FormatDrive->addArgument( "/usr/local/pcbsd/scripts/PCBSD.FormatDisk.sh" );
	FormatDrive->addArgument( device );
                connect( FormatDrive, SIGNAL(processExited()), this, SLOT(startCustomLabel()) );
                if ( !FormatDrive->start() ) {
	  // error handling
	//QMessageBox::warning( this, "PCBSD Installer",  SelectedDrive, "Retry", "Quit", 0, 0, 1 );
                }

	
	    } // End of File Open
	
    // Only setting up the partition with PC-BSD	
    } else {
	
	// Get the current partition
	QString PartNumText = listPartitionBox->currentText();
	PartNumText.truncate(PartNumText.find(":") );
	PartNumText.remove(0, PartNumText.length() -1 );
	PartNum = PartNumText.toInt();
    
	// Set the PC-BSD Partition
	RootPartition = "/dev/" + device + "s" + tmp.setNum(PartNum);

	
	
	    // If the partition is the first one, then set starting block to 63
	    if (PartNum == 1)
	   {
	      PartitionStartBlk[1]="63";
	   }
	    
	    
     // If we have the bootloader checkbox specified, go ahead and make the file now
    if ( checkBootloader->isChecked())
    {
	    QFile file1( "/tmp/StampBoot.sh" );
	    if ( file1.open( IO_WriteOnly ) ) {
		QTextStream stream1( &file1 );
		stream1 <<  "#!/bin/sh\nboot0cfg -B -v -o packet " + device;
		file1.close();
	    }
	
    }
	    
	    
        // Now run the FormatPartition.sh script to set this partition type to 165(FBSD)
	textFileProgress->setText(tr("Running fdisk on ") + RootPartition);
	installProgress->setProgress(2);
	FormatPartition = new Q3Process(this);
	FormatPartition->addArgument( "/usr/local/pcbsd/scripts/PCBSD.FormatPartition.sh" );
	FormatPartition->addArgument( device );
	FormatPartition->addArgument( RootPartition );
	
                connect( FormatPartition, SIGNAL(processExited()), this, SLOT(startCustomLabel()) );
                if ( !FormatPartition->start() ) {
	  // error handling
	//QMessageBox::warning( this, "PCBSD Installer",  SelectedDrive, "Retry", "Quit", 0, 0, 1 );
                }
	   
	   
    }
    
    
}




QString PCInstall::Sanitize_Bios_Geom( QString cyl, QString head, QString sec, QString block )
{
  int sane;
  sane = 1;

  Q_LLONG Cyl = cyl.toLongLong();
  Q_LLONG Head = head.toLongLong();
  Q_LLONG Sec = sec.toLongLong();
  Q_LLONG Block = block.toLongLong();

	if (Cyl > 1024)
		sane = 0;

	if (Head > 16)
		sane = 0;

	if (Sec > 63)
		sane = 0;

	if (Cyl * Head * Sec != Block)
		sane = 0;
	if (sane)
		return cyl + "/" + head + "/" + sec;

	/* First try something that IDE can handle */
	Sec = 63;
	Head = 16;
	Cyl = Block / (Sec * Head);

	if (Cyl < 1024)
	{
	    cyl.setNum(Cyl);
	    head.setNum(Head);
	    sec.setNum(Sec);

	     return cyl + "/" + head + "/" + sec;

	}

	/* Hmm, try harder... */
	/* Assume standard SCSI parameter */
	Head = 255;
	Cyl = Block / (Sec * Head);

	cyl.setNum(Cyl);
	head.setNum(Head);
	sec.setNum(Sec);

	return "c" + cyl + " h" + head + " s" + sec;
}


void PCInstall::readFormatDiskSlot()
{

}


void PCInstall::startCustomLabel()
{
    
    int i = 2;
    QString PartLetter;
    
    // Use a custom disk label if the user selected it, or if we are using ZFS since we need a seperate /boot filesystem
     if ( (checkCustomPartition->isChecked() && checkCustomDiskSlice->isChecked()) || comboFileSystem->currentItem() == 3 )
    {
	    QFile file( "/tmp/BSDLabel" );
	    if ( file.open( IO_WriteOnly ) ) {
		QTextStream stream( &file );
		stream <<  "# " << RootPartition << ":\n";
		stream << "8 partitions:\n";
		stream << "#  	size  	offset 	fstype  	bsize  	bps/cpg\n";
		stream << "a: 	" + SliceMB[0] + "M 	0  	4.2BSD 	0 	0\n";
		stream << "b: 	" + SliceMB[1] + "M  	*   	swap\n";
		stream << "c:	 *	*	unused\n";
		
	while ( i < 10) {
	    
	    if ( SliceMB[i].isEmpty() )
	    {
		break;
	    } 
		    	
		switch( i ) {
		case 2:
		    PartLetter = "d";
		    break;
		case 3:
		    PartLetter = "e";
		    break;
		case 4:
		    PartLetter = "f";
		    break;
		case 5:
		    PartLetter = "g";
		    break;
		case 6:
		    PartLetter = "h";
		    break;
		}	
		
		if ( SliceMB[i + 1].isEmpty() )
		{
		    stream << PartLetter +": 	* 	*  	4.2BSD\n";
		} else {
		    stream << PartLetter +": 	" + SliceMB[i] + "M	 	*  	4.2BSD\n";
		}
		
		i++;
	    }
		file.close();
	    }
	
	
    } else {
	

	     // Use the standard disk label for a desktop install	
	    QFile file( "/tmp/BSDLabel" );
	    if ( file.open( IO_WriteOnly ) ) {
		QTextStream stream( &file );
		stream <<  "# " << RootPartition << ":\n";
		stream << "8 partitions:\n";
		stream << "#  	size  	offset 	fstype  	bsize  	bps/cpg\n";
		stream << "a: 	* 	0  	4.2BSD 	0 	0\n";
		stream << "b: 	512M  	*   	swap\n";
		stream << "c:	 *	*	unused\n";

		file.close();
	    }
	
	
    }
    
    
        
    	    textFileProgress->setText(tr("Writing BSD Label to ") + RootPartition);
	    installProgress->setProgress(3);
	    WriteBSDLab = new Q3Process( this );
	    WriteBSDLab->addArgument( "bsdlabel" );
	    WriteBSDLab->addArgument( "-R" );
	    WriteBSDLab->addArgument( "-B" );
	    WriteBSDLab->addArgument( RootPartition );
	    WriteBSDLab->addArgument( "/tmp/BSDLabel" ); 
                    
	    connect( WriteBSDLab, SIGNAL(processExited()), this, SLOT(RunNewfsSlot() ) );
	   // QMessageBox::warning( this, "PCBSD Installer",  "running bsdlabel", "Retry", "Quit", 0, 0, 1 );
	    if ( !WriteBSDLab->start() ) {
//
	    }
    

}


void PCInstall::RunNewfsSlot()
{
    QString tmp;
     // QMessageBox::warning( this, "PCBSD Installer",  "running newfs", "Retry", "Quit", 0, 0, 1 );
    
       textFileProgress->setText(tr("Running newfs on ") + RootPartition);
       installProgress->setProgress(4);
       NewFSProc = new Q3Process( this );
       NewFSProc->addArgument( "/usr/local/pcbsd/scripts/PCBSD.NewFS.sh" );
       NewFSProc->addArgument( RootPartition );
       NewFSProc->addArgument( tmp.setNum(comboFileSystem->currentItem()) );
       
    connect( NewFSProc, SIGNAL(processExited()), this, SLOT(MountPartSlot() ) );

    if ( !NewFSProc->start() ) {

    }
       
       
}


void PCInstall::MountPartSlot()
{
    QString tmp;
    
    textFileProgress->setText(tr("Mounting drive ") + RootPartition);
    installProgress->setProgress(5);
         int i = 2;
	 
    // Check if we need to create the /tmp/encSwap file
    if (checkEncryptedSwap->isChecked() )
    {
	    QFile file( "/tmp/encSwap" );
	    if ( file.open( IO_WriteOnly ) ) {
		QTextStream stream( &file );
		stream <<  "Y";
		file.close();
	    }

    }
	 

    //Setup Process to mount the root partition
    MountDisk = new Q3Process( this );
    MountDisk->addArgument( "/usr/local/pcbsd/scripts/PCBSD.MountDisk.sh" );
    MountDisk->addArgument( RootPartition );
    MountDisk->addArgument( tmp.setNum(comboFileSystem->currentItem()) );



    while ( ! SliceMnt[i].isEmpty() )
    {
	MountDisk->addArgument( SliceMnt[i] );
	i++;
    }




    connect( MountDisk, SIGNAL(processExited()), this, SLOT(finishedMountSlot() ) );

    if ( !MountDisk->start() ) {
	QMessageBox::warning( this, "PCBSD Installer", "Failed Starting Mount", "Retry", "Quit", 0, 0, 1 );
    }
     
     
}


void PCInstall::finishedMountSlot()
{
      startTarExtractSlot();
}


void PCInstall::customDiskSliceSlot( bool ok )
{
    
    if ( ok )
    {
	listViewSlices->setEnabled(TRUE);
	pushSliceAdd->setEnabled(TRUE);
	pushSliceEdit->setEnabled(TRUE);
	pushSliceRemove->setEnabled(TRUE);
    } else {
	listViewSlices->setEnabled(FALSE);
	pushSliceAdd->setEnabled(FALSE);
	pushSliceEdit->setEnabled(FALSE);
	pushSliceRemove->setEnabled(FALSE);
    }

}


void PCInstall::FinishedMountCDSlot()
{
    if(MountCD->normalExit() && MountCD->exitStatus() == 0 )
    {
      // Check if we are using a DVD or a CD
      QFile testDVD("/tmp/foundDVD");
      if ( testDVD.exists() )
      {
        usingDVDmedia = 1;
      } else {
        usingDVDmedia = 0;
      }

      // Now start the install / update 
      if ( radioFreshInstall->isChecked() )
       {
        // Start normal install
        startFreshInstall();
       } else {
	startUpdateProcess();
       }
	
	
    } else {
	
	switch( QMessageBox::warning( this, tr("CD Mount Error"), tr("Error: Could not load the install disc. Please check that the CD/DVD is in the drive.\n Press OK to try again, or Cancel to reboot the system."), tr("OK"), tr("Cancel"), 0, 0, 1 ) ) {
	     case 0: // The user clicked the OK again button or pressed Enter
		startMountCD();
		 break;
	     case 1: // The user clicked the Quit or pressed Escape
		  exit(1);
		 break;
	     }
    }
    
    
}


// Function which calculates the total size of our progress bar, and sets it
void PCInstall::calcProgressBarSize()
{
    int totalLength = 0;

     QString line;
    
    // Get the size of the first lzma file
    QFile file( "/usr/local/pcbsd/scripts/PCBSD.ExtractSize" );
    if ( file.open( IO_ReadOnly ) ) {
	QTextStream stream( &file );
	line = stream.readLine(); // line of text excluding '\n'
	totalLength = totalLength + line.toInt();
	file.close();
    }


    // Get the lzma2 size now
    QFile file1( "/usr/local/pcbsd/scripts/PCBSD.ExtractSize2" );
    if ( file1.open( IO_ReadOnly ) ) {
	QTextStream stream1( &file1 );
	line = stream1.readLine(); // line of text excluding '\n'
	totalLength = totalLength + line.toInt();
	file1.close();
    }
       
       

    // Get the number of components we have 
    for ( int i = 0; !ComponentDir[i].isEmpty(); i++ )
    {
       if ( ComponentSelected[i] == 1 )
   	  totalLength++;
    }


    // Set our current progress variable to 0
    ExtractSize = 0;


    // Add a few extra steps for misc items, like kernel setup, etc
    totalLength = totalLength + 10;
    
    // Set our total steps to the found size
    installProgress->setTotalSteps(totalLength);
    
    // Zero out the progress bars now
    installProgress->setProgress(0);

}


void PCInstall::startMountCD()
{

    
    textFileProgress->setText(tr("Mounting CD..."));
    
      //Setup Process to mount the root partition
    MountCD = new Q3Process( this );
    MountCD->addArgument( "/usr/local/pcbsd/scripts/PCBSD.MountCD.sh" );

    connect( MountCD, SIGNAL(processExited()), this, SLOT(FinishedMountCDSlot() ) );

    if ( !MountCD->start() ) {
	QMessageBox::warning( this, "PCBSD Installer", "Failed Starting MountCD", "Retry", "Quit", 0, 0, 1 );
    }
}


void PCInstall::startTarExtractSlot()
{
  

    TarProc = new Q3Process( this );
    TarProc->addArgument( "/usr/local/pcbsd/scripts/PCBSD.InstallCD1.sh" );
    

    connect( TarProc, SIGNAL(readyReadStdout() ), this, SLOT(readTarStdoutSlot() ) );
    connect( TarProc, SIGNAL(processExited()), this, SLOT(TarFinishedSlot() ) );

    if ( !TarProc->start() ) {
	QMessageBox::warning( this, tr("PCBSD Installer"),  tr("Failed Starting PCBSD.InstallCD1.sh"), tr("Retry"), tr("Quit"), 0, 0, 1 );
    } 
}



void PCInstall::readTarStdoutSlot()
{
    QString Buffer;
    QString tmp;

    // Loop while getting input
    while (TarProc->canReadLineStdout() )
    {
	// Read the line
	Buffer = TarProc->readLineStdout();
	
	// Remove the "x" from the start
	if ( Buffer.find("x", 0) == 0)
	{
	    Buffer.remove(0, 3);
	    tmp = Buffer;
	    Buffer = tmp;
	} 
	
	
	// Set the Label to current file
	textFileProgress->setText(Buffer);
	// Get size for Progress Bar
	ExtractSize = ExtractSize + 1;
	installProgress->setProgress(ExtractSize);

    } // End while loop
}


void PCInstall::setupUsersSlot()
{

    int i = 0;
    
    textFileProgress->setText(tr("Setting up Users..."));
    ExtractSize = ExtractSize + 1;
    installProgress->setProgress(ExtractSize);
    
    QFile userList( "/mnt/tmp/users");
    if ( userList.open( IO_WriteOnly) ) {
	QTextStream userStream( &userList);
	
	
   // Save the root password
   QFile filePassRoot( "/mnt/tmp/setPass-Root" );
    if ( filePassRoot.open( IO_WriteOnly ) ) {
	QTextStream streamPassRoot( &filePassRoot );
	streamPassRoot << linePassword->text();
	filePassRoot.close();
    }
    
   // Set our variables for the user passwords
   QFile filePassUser; 
   QString fileNameUser, tmp;

   QFile file( "/mnt/tmp/setPass" );
    if ( file.open( IO_WriteOnly ) ) {
	QTextStream stream( &file );
	stream << "cat /tmp/setPass-Root | pw usermod root -h 0\n" ;
	stream << "rm /tmp/setPass-Root\n" ;
	while ( i < 100)
	{
	
	    if ( AddUserName[i] == "" )
	    {
		break;   
	    }
   
    	    // Save the password text to file
            fileNameUser = "/mnt/tmp/setPass-User" + tmp.setNum(i);
   	    filePassUser.setFileName( fileNameUser );
    	    if ( filePassUser.open( IO_WriteOnly ) ) {
		QTextStream streamPassUser( &filePassUser );
		streamPassUser << AddPassword[i];
                filePassUser.close();
            }
    
		
	    stream << "cat /tmp/setPass-User" + tmp.setNum(i) + " | pw useradd -n " << AddUserName[i] << " -G wheel,operator -h 0 -s " + AddShell[i] + " -d /home/" << AddUserName[i] << " -m -c \"" << AddRealName[i] << "\"\n";
	    stream << "rm /tmp/setPass-User" + tmp.setNum(i) + "\n";
	
	    stream << "chown -R " << AddUserName[i] << " /home/" << AddUserName[i] << "\n";
	    stream << "chgrp -R " << AddUserName[i] << " /home/" << AddUserName[i] << "\n";
	    userStream << AddUserName[i] << "\n";
    
		    i++;
	}
    


	file.close();
     }

          userList.close();
     }
    AddUserProc = new Q3Process( this );
    AddUserProc->addArgument( "/usr/local/pcbsd/scripts/PCBSD.AddUser.sh" );
    
    if ( checkAutoLogon->isChecked() ) {
	AddUserProc->addArgument( "0" );
    } else {
	AddUserProc->addArgument( "2" );
    }
    

    connect( AddUserProc, SIGNAL(processExited()), this, SLOT(setupTimeSlot() ) );


    if ( !AddUserProc->start() ) {
	QMessageBox::warning( this, tr("PCBSD Installer"),  tr("Failed Starting AddUserProc"), tr("Retry"), tr("Quit"), 0, 0, 1 );
    }
    

}


void PCInstall::slotRunLastScripts()
{
    QString tmp;
    QString tmp2;
    
    textFileProgress->setText(tr("Running System config..."));
    ExtractSize = ExtractSize + 1;
    installProgress->setProgress(ExtractSize);

    tmp = listBoxLang->currentText();
    tmp.remove(0, tmp.find("(") + 1 );
    tmp.truncate(tmp.find(")") );
    
   // Start with the update system config script
   SystemConfig= new Q3Process( this );
   SystemConfig->addArgument( "/usr/local/pcbsd/scripts/PCBSD.SysConfig.sh" );
   SystemConfig->addArgument( tmp );

   if ( checkAllowBSDSTATS->isChecked() )
   {
     SystemConfig->addArgument("1");
   } else {
     SystemConfig->addArgument("0");
   }


    connect( SystemConfig, SIGNAL(processExited()), this, SLOT(setupFinishedSlot() ) );

    if ( !SystemConfig->start() ) {
	QMessageBox::warning( this, tr("PCBSD Installer"),  tr("Failed Starting SystemConfig"), tr("Retry"), tr("Quit"), 0, 0, 1 );
    }
    
    
}




void PCInstall::setupFinishedSlot()
{
    showPage(page(10));
    setBackEnabled(currentPage(), FALSE);
    setFinishEnabled(currentPage(), TRUE);
}


void PCInstall::TarFinishedSlot()
{
    if ( ! TarProc->normalExit() || TarProc->exitStatus() != 0 )
    {
	    QMessageBox::critical( 0, "Install Error!",
        tr("An error occured while extracting the system image! Please check the install CD, or try selecting 'Safe Mode' \nwhen the installation CD begins booting. The system will now reboot.") );
	    exit(1);
     } else {
         if ( usingDVDmedia == 0 )
         {
           slotStartMountCD2();
         } else {
           // Looks like we have a DVD, lets install from it now
           slotInstallCD2();
         }
     }
}



void PCInstall::populateSlices()
{
    int i = 0;
    Q_LLONG UsedMB = 0;
    Q_LLONG AvailMB = 0;
    QString PartLetter;
    QString Device;
    QString tmp;
    QString Type;
    
    listViewSlices->clear();

    
    if ( checkBoxEntireDisk->isChecked() )
    {
	tmp= listDriveBox->currentText();
	tmp.truncate(tmp.find(":") );
	Device = tmp + "s1";        
    } else {
	tmp= listPartitionBox->currentText();
	tmp.truncate(tmp.find(":") );
	Device = tmp;    
    }
    

    
    
    while (i < 10) {
	if ( SliceMB[i].isEmpty() )
	{
	 break;   
	}
	
	UsedMB = UsedMB + SliceMB[i].toLongLong();
	
	switch( i ) {
	   case 0:
	       PartLetter = "a";
               tmp = comboFileSystem->currentText();
               if ( tmp.indexOf("ZFS") == -1)
               {
                 Type = tmp; 
               } else {
	         Type = "UFS2";
               }
	       break;
	   case 1:
	       PartLetter = "b";
	       Type = "Swap";
	       break;
	   case 2:
	       PartLetter = "d";
	       Type = comboFileSystem->currentText();
	       break;
	   case 3:
	       PartLetter = "e";
	       Type = comboFileSystem->currentText();
	       break;
	   case 4:
	       PartLetter = "f";
	       Type = comboFileSystem->currentText();
	       break;
	   case 5:
	       PartLetter = "g";
	       Type = comboFileSystem->currentText();
	       break;
	   case 6:
	       PartLetter = "h";
	       Type = comboFileSystem->currentText();
	       break;
	   }
	
	
	(void) new Q3ListViewItem( listViewSlices, Device + PartLetter, SliceMnt[i], SliceMB[i] + " MB", Type );

	
	
	i++;
    }
    
    
    AvailMB = TotalSliceMB.toLongLong() - UsedMB;
    
    textSliceAvailSpace->setText(tmp.setNum(AvailMB) + tr("MB available out of ") + TotalSliceMB + tr("MB")); 
    
    
    
}


// Converts Blocksizes to MB
QString PCInstall::BlocksToMB( QString Blocks )
{
    Q_LLONG BlockNum = Blocks.toLongLong();
    Q_LLONG MBNum;
    QString MegaByte;

    MBNum = BlockNum / 2048;
    MegaByte.setNum(MBNum);
    return MegaByte;
}


void PCInstall::setupInitialSlices()
{
    QString tmp;
    int SelPartition;
    

	tmp= listPartitionBox->currentText();
	tmp.truncate(tmp.find(":") );
	tmp.remove(0, tmp.length() -1 );
	SelPartition = tmp.toInt();
    
    
    if ( checkBoxEntireDisk->isChecked() )
    {
	TotalSliceMB = BlocksToMB(TotalDriveBlocks);
    } else {
	 
	TotalSliceMB = PartitionMB[SelPartition];	    
    }
	
    // Check if we are using ZFS and create a 100MB /bootdir slice
    if ( comboFileSystem->currentItem() == 3 )
    {
	    SliceMB[0] = "200";
	    SliceMnt[0] = "/bootdir";
	    SliceMB[1] = "512";
	    SliceMnt[1] = "SWAP";
	    SliceMB[2] = tmp.setNum((TotalSliceMB.toLongLong() - 712));
	    SliceMnt[2] = "/";
	    SliceMB[3] = "";
	    SliceMnt[3] = "";
	    SliceMB[4] = "";
	    SliceMnt[4] = "";
	    SliceMB[5] = "";
	    SliceMnt[5] = "";
    } else {
	SliceMB[0] = tmp.setNum((TotalSliceMB.toLongLong() - 512));
	SliceMnt[0] = "/";
	SliceMB[1] = "512";
	SliceMnt[1] = "SWAP";
	SliceMB[2] = "";
	SliceMnt[2] = "";
	SliceMB[3] = "";
	SliceMnt[3] = "";
	SliceMB[4] = "";
	SliceMnt[4] = "";
	SliceMB[5] = "";
	SliceMnt[5] = ""; 
   }

    
	
}


void PCInstall::sliceAddSlot()
{
    int i = 0;
    Q_LLONG UsedMB = 0;
    Q_LLONG AvailMB = 0;
    QString tmp;
    
    while ( ! SliceMB[i].isEmpty() )
    {
	UsedMB = UsedMB + SliceMB[i].toLongLong();
	i++;
    }

    // The total available blocks
    AvailMB = TotalSliceMB.toLongLong() - UsedMB;
    tmp.setNum(AvailMB);
    
    if ( AvailMB > 0 )
    {

	// Launch our AddPartitionDialog to add a new device
	AddPartDialog = new AddPartitionDialog();
	connect( AddPartDialog, SIGNAL(Saved(QString &, QString &)), this, SLOT(AddLabelSlot(QString &, QString &)) );
	AddPartDialog->ProgramInit(tmp);
	AddPartDialog->SetEditValues( "1", tr("Add Partition"), tr("Please select the size you wish to use for this new partition."), "/" );
	AddPartDialog->EnableMountBox();
	AddPartDialog->exec();

    }
}


void PCInstall::sliceEditSlot()
{
    
    int i = 0;
    Q_LLONG UsedMB = 0;
    Q_LLONG AvailMB = 0;
    QString tmp;
    int SelPart = 0;

    if ( listViewSlices->currentItem() != 0)
    {
	
	while ( ! SliceMB[i].isEmpty() )
	{
	    UsedMB = UsedMB + SliceMB[i].toLongLong();

	    if ( listViewSlices->currentItem()->text(1) == SliceMnt[i] )
	    {
		SelPart = i;
	    }

	    i++;
	}

	// The total available blocks
	AvailMB = (TotalSliceMB.toLongLong() - UsedMB) + SliceMB[SelPart].toLongLong();
	tmp.setNum(AvailMB);

	// Save the item we are working on
	CurrentEditLabel = SelPart;

	// Launch our AddPartitionDialog to edit the device
	AddPartDialog = new AddPartitionDialog();
	connect( AddPartDialog, SIGNAL(Saved(QString &)), this, SLOT(EditLabelSlot(QString &)) );
	AddPartDialog->ProgramInit(tmp);
	AddPartDialog->SetEditValues( SliceMB[SelPart], tr("Editing Partition"), tr("Please select the size you wish to allocate to this mount"), SliceMnt[SelPart] );
	AddPartDialog->exec();

    }

}


void PCInstall::sliceRemoveSlot()
{
    int i = 0;
    int copy = 0;
    QString PartLetter;

    if ( listViewSlices->currentItem() != 0)
    {
	if ( listViewSlices->currentItem()->text(1) == "/" )
	{
	    QMessageBox::information( this, tr("DiskLabel Error:"), tr("You cannot remove the '/' partition. ") );
	    return;
	}
	if (listViewSlices->currentItem()->text(1) == "SWAP" )
	{
	    QMessageBox::information( this, tr("DiskLabel Error:"), tr("You cannot remove the 'SWAP' partition. ") );
	    return;
	}
	if (listViewSlices->currentItem()->text(1) == "/bootdir" )
	{
	    QMessageBox::information( this, tr("DiskLabel Error:"), tr("You cannot remove the '/bootdir' partition. ") );
	    return;
	}

	while ( ! SliceMnt[i].isEmpty() )
	{
	    if (SliceMnt[i] == listViewSlices->currentItem()->text(1) )
	    {
		copy = 1;
	    }

	    // Start moving over saved info
	    if ( copy == 1)
	    {

		if (  SliceMB[i+1].isEmpty() ) {
		    SliceMB[i] = "";
		    SliceMnt[i] = "";
		} else {
		    SliceMnt[i] = SliceMnt[i+1];
		    SliceMB[i] = SliceMB[i+1];    
		}
	    }

	    i++;
	}

	populateSlices();

    }

}


void PCInstall::AddLabelSlot( QString &Blocks, QString &Mount )
{
    int i = 0;
    QString PartLetter;
    
    if (Mount == "/home" )
    {
	QMessageBox::information( this, tr("Invalid Partition"), tr("Warning: /home is a link to /usr/home. This entry will be adjusted.") );
	Mount = "/usr/home";
    }
    
    if (Mount == "/boot" )
    {
	QMessageBox::information( this, tr("Invalid Partition"), tr("Warning: The '/boot' directory must be on the '/' partition.") );
	return;
    }

    while ( ! SliceMB[i].isEmpty() )
    {
	// Make sure we are not adding the same partition mount-point
	if ( SliceMnt[i] == Mount)
	{
	   QMessageBox::information( this, tr("Error!"), tr("You already have a partition setup for this mount point!") );
	   return;
	}
	i++;
    }


    switch( i ) {
		   case 2:
		       PartLetter = "d";
		       break;
		   case 3:
		       PartLetter = "e";
		       break;
		   case 4:
		       PartLetter = "f";
		       break;
		   case 5:
		       PartLetter = "g";
		       break;
		   case 6:
		       PartLetter = "h";
		       break;
		   }

    if (PartLetter.isEmpty() )
    {
	QMessageBox::information( this, tr("Max Partitions:"), tr("You exceeded the max number of partitions.") );
	return;
    }

    


    SliceMnt[i] = Mount;
    SliceMB[i] = Blocks;

    populateSlices();

}


void PCInstall::EditLabelSlot( QString &Blocks )
{
    SliceMB[CurrentEditLabel] = Blocks;
    populateSlices();
}



void PCInstall::setupTimeSlot()
{
    QString tmp;
    
    textFileProgress->setText(tr("Setting up Timezone..."));
	 ExtractSize = ExtractSize + 1;
	 installProgress->setProgress(ExtractSize);

	 // Send our arguments to the timezone script
	 TimeProc= new Q3Process( this );
	 TimeProc->addArgument( "/usr/local/pcbsd/scripts/PCBSD.TimeZone.sh" );
	 if ( checkTimeSync->isChecked() )
	 {
	     TimeProc->addArgument( "0" );
	 } else {
	     TimeProc->addArgument( "1" );
	 }
	 
	 
	 tmp = comboTZone->currentText();
	 tmp.truncate(tmp.find(" "));
	 
	 TimeProc->addArgument(tmp);
	 
	  // Conect to the slot to finish up the install
          connect( TimeProc, SIGNAL(processExited()), this, SLOT(slotRunLastScripts() ) );

	 


	 if ( !TimeProc->start() ) {
	     QMessageBox::warning( this, tr("PCBSD Installer"),  tr("Failed Starting TimeZone.sh"), tr("Retry"), tr("Quit"), 0, 0, 1 );
	 }
    
    

}



void PCInstall::readAvailUpgradesSlot()
{
    listPartitionBoxUpgrade->clear();
  
    QFile file( "/tmp/AvailUpgrades" );
    if ( file.open( IO_ReadOnly ) ) 
    {
	QTextStream stream( &file );
	QString line;
	while ( !stream.atEnd() ) 
	{
	    line = stream.readLine(); // line of text excluding '\n'
	    
	    // Insert the string
	    listPartitionBoxUpgrade->insertItem(line);

	}
	file.close();
	
	textUpdatePart->setText("");
    } else {
	textUpdatePart->setText(tr("No existing PC-BSD partitions detected!"));
	setNextEnabled(currentPage(), FALSE);
    }
}


void PCInstall::checkPartUpgradeBox()
{
    int item = listPartitionBoxUpgrade->currentItem();
 
    
    if ( item == -1 )
    {
	setNextEnabled(currentPage(), FALSE);
    } else {
	setNextEnabled(currentPage(), TRUE);
    }

}


void PCInstall::startUpdateProcess()
{
    
    QString tmp;
    
    tmp= listPartitionBoxUpgrade->currentText();
    tmp.truncate(tmp.find(":") - 1);
    
// Now run our scripts to remove pkgs and start upgrade
         //Setup Process to mount the root partition
    RunUpgradeProc = new Q3Process( this );
    RunUpgradeProc->addArgument( "/usr/local/pcbsd/scripts/PCBSD.MountUpgrade.sh" );
    RunUpgradeProc->addArgument( tmp );

    connect( RunUpgradeProc, SIGNAL(processExited()), this, SLOT(startTarExtractSlot()) );

    if ( !RunUpgradeProc->start() ) {
	QMessageBox::warning( this, "PCBSD Installer", "Failed Starting MountCD", "Retry", "Quit", 0, 0, 1 );
    }
    
}

void PCInstall::slotRunFinalScriptUpgrade()
{
    textFileProgress->setText(tr("Running System config..."));
    ExtractSize = ExtractSize + 1;
    installProgress->setProgress(ExtractSize);

    // Start with the update system config script
   SystemConfig= new Q3Process( this );
   SystemConfig->addArgument( "/usr/local/pcbsd/scripts/PCBSD.SysConfig.sh" );
   SystemConfig->addArgument( "IGNORE" );
   SystemConfig->addArgument( "IGNORE" );
   SystemConfig->addArgument(tr("Start"));

   if ( checkAllowBSDSTATS->isChecked() )
   {
     SystemConfig->addArgument("1");
   } else {
     SystemConfig->addArgument("0");
   }


    


     connect( SystemConfig, SIGNAL(processExited()), this, SLOT(upgradeFinishedSlot() ) );
    if ( !SystemConfig->start() ) {
	QMessageBox::warning( this, tr("PCBSD Installer"),  tr("Failed Starting SystemConfig"), tr("Retry"), tr("Quit"), 0, 0, 1 );
    }
}


void PCInstall::upgradeFinishedSlot()
{
    
    showPage(page(10));
    setBackEnabled(currentPage(), FALSE);
    setFinishEnabled(currentPage(), TRUE);
}


void PCInstall::FinishedMountLangCDSlot()
{
    
    // If the CD mounted successfully
    if(FindLangCD->normalExit() && FindLangCD->exitStatus() == 0 )
    {

         // Looks like we have CD2, lets install from it now
         slotInstallCD2();
	
    } else {
	
	switch( QMessageBox::warning( this, tr("CD Mount Error"), tr("Error: Could not locate CD #2. Please check that the CD is in the drive. Press OK to try again, or Cancel to abort install."), tr("OK"), tr("Cancel"), 0, 0, 1 ) ) {
	     case 0: // The user clicked the OK again button or pressed Enter
		 slotStartMountCD2();
		 break;
	     case 1: // The user clicked the Quit or pressed Escape
		 
		
		 exit(5);
		 return;
		 break;
	     }
    }
}



void PCInstall::readLangInstallSlot()
{
  QString Buffer;

    // Loop while getting input
    while (AddLangFiles->canReadLineStdout() )
    {
	// Read the line
	Buffer = AddLangFiles->readLineStdout();
	// Check if we need to display the output and increment the progress bar
	if ( Buffer.find("CP:") != -1)
	{
	    Buffer.remove(0, 3 );
	    textFileProgress->setText(tr("Copying ") + Buffer);
	    // Get size for Progress Bar
	    ExtractSize = ExtractSize + 1;
	    installProgress->setProgress(ExtractSize);
	    
	}
	
	if (Buffer.find("PKG:") != -1 )
	{
	    Buffer.remove(0,4 );
	    
	    textFileProgress->setText(tr("Installing ") + Buffer);
	    // Get size for Progress Bar
	    ExtractSize = ExtractSize + 1;
	    installProgress->setProgress(ExtractSize);
	}
	
	
	


    } // End while loop
}


void PCInstall::checkUserLinesChanged( const QString & )
{
    bool ok = TRUE;
    textAcctNotify->setText("");

    lineUserName->unsetPalette();
    
            // Check if we are missing  some values
    if ( lineUserName->text().isEmpty() )
    {
	textAcctNotify->setText("");
	ok = FALSE;
    }
     
    if ( lineFullName->text().isEmpty() )
    {
	textAcctNotify->setText("");
	ok = FALSE;
    }
    
    if ( lineUserPassword->text().isEmpty() )
    {
	textAcctNotify->setText("");
	ok = FALSE;
    }
    
    
    
    //Check username contains only letters and numbers
    if ((! passwordRegExp.exactMatch(lineUserName->text())) && (lineUserName->text() != "")) {
	textAcctNotify->setText(tr("Username may contain only letters and numbers!"));
	lineUserName->setPaletteBackgroundColor(colourRed);
	ok = FALSE;
    }
    
    
    if ( (lineUserPassword->text() != lineUserPassword2->text()) || lineUserPassword->text().isEmpty())
    {
	ok = FALSE;
    }
    
    QString Username = lineUserName->text();
    
        if ( Username == "root" || Username == "toor" || Username == "daemon" || Username == "operator" || Username == "bin" || Username == "tty" || Username == "kmenu" || Username == "games" || Username == "news" || Username == "man" || Username == "sshd" || Username == "smmsp" || Username == "mailnull" || Username == "bind" || Username == "proxy" || Username == "_pflog" || Username == "_dhcp" || Username == "pop" || Username == "www" || Username == "nobody" || Username == "cyrus" || Username == "cups")
    {
	  ok = FALSE;   
	  textAcctNotify->setText( tr("Error: The username \"" + Username + "\" is reserved."));
	  lineUserName->setPaletteBackgroundColor(colourRed);
    }
    
    
    
    
    
    int i = 0;
    bool ok2 = TRUE;
    
    while ( i < 100)
    {
	
	if ( AddUserName[i] == "" )
	{
	   break;   
	}

	if(AddUserName[i] == lineUserName->text() )
	{
	    ok2 = FALSE;
	    break;
	}

	i++;
    }
    
 
    
    
    if ( ok)
    {
	if (ok2)
	{
	  pushAddUser->setEnabled(TRUE);
	  pushApplyUser->setEnabled(FALSE);
                } else {
	  pushAddUser->setEnabled(FALSE);
	  pushApplyUser->setEnabled(TRUE);
                }
	
     } else {
	 pushApplyUser->setEnabled(FALSE);
	 pushAddUser->setEnabled(FALSE);
     }
    

}


void PCInstall::listBoxUsersChanged()
{
    int i;
    
    if ( listBoxUsers->currentItem() != -1)
    {
	i = listBoxUsers->currentItem();
	lineUserName->setText(AddUserName[i]);
	lineFullName->setText(AddRealName[i]);
	lineUserPassword->setText(AddPassword[i]);	
	lineUserPassword2->setText(AddPassword[i]);
	
	if ( AddShell[i] == "/bin/csh")
	{
	    comboShell->setCurrentItem(0);
	} else if(AddShell[i] == "/bin/tcsh") {
	    comboShell->setCurrentItem(1);
	} else if(AddShell[i] == "/bin/sh") {
	    comboShell->setCurrentItem(2);
	} else if(AddShell[i] == "/PCBSD/local/bin/bash") {
	    comboShell->setCurrentItem(3);
	}
	
	
	
    }
}


void PCInstall::applyUserButton()
{
    QString Shell;
    int i;
    
    if ( listBoxUsers->currentItem() != -1)
    {
	
      i = listBoxUsers->currentItem();	
      AddUserName[i] = lineUserName->text();
      AddRealName[i] = lineFullName->text();
      AddPassword[i]    = lineUserPassword->text();
      
    if ( comboShell->currentItem() == 0)
    {
	AddShell[i] = "/bin/csh";  
    } else if ( comboShell->currentItem() == 1) {
	AddShell[i] = "/bin/tcsh";
    } else if ( comboShell->currentItem() == 2) {
	AddShell[i] = "/bin/sh";
    } else {
	AddShell[i] = "/PCBSD/local/bin/bash";
    }
      
      
    }
    
    refreshUsers();
    CheckAccountInfo();
    checkUserLinesChanged("");
    
}




void PCInstall::listBoxLangChanged()
{
    QString tmp;




    
    tmp = listBoxLang->currentText();
    tmp.remove(0, tmp.find("(") + 1 );
    tmp.truncate(tmp.find(")") );
    
    
    // Save the file
     QFile file( "/root/.langchange" );
    if ( file.open( IO_WriteOnly ) ) {
        QTextStream stream( &file );
	stream <<  tmp;
        file.close();
    }
    
    exit(3);     

}


void PCInstall::changePromoAd()
{
   QString FileName;
    
    switch ( PromoAd )
    {
	case 1:
   	    FileName = "/usr/local/pcbsd/graphics/secure.png";
	    textLabelAd->setText(tr("Secure by design"));
	    PromoAd++;
                    break;
	case 2:
	    FileName = "/usr/local/pcbsd/graphics/movies.png";
	    textLabelAd->setText(tr("Watch your favorite movies"));
	    PromoAd++;
	    break;
	case 3:
	    FileName = "/usr/local/pcbsd/graphics/music.png";	  
	    textLabelAd->setText(tr("Listen to your music"));
	    PromoAd++;
                    break;
	case 4:
	    FileName = "/usr/local/pcbsd/graphics/schools-universities.png";
	    textLabelAd->setText(tr("Ideal for schools and universities"));
	    PromoAd++;
	    break;
	case 5:
	    FileName = "/usr/local/pcbsd/graphics/developer.png";
	    textLabelAd->setText(tr("Developer-friendly platform"));
	    PromoAd++;
                    break;
	case 6:
	    FileName = "/usr/local/pcbsd/graphics/reliable.png";
	    textLabelAd->setText(tr("Enterprise-class stability"));
	    PromoAd++;
	    break;
	case 7:
	    FileName = "/usr/local/pcbsd/graphics/support.png";    
	    textLabelAd->setText(tr("Outstanding commercial support"));
	    PromoAd++;
                    break;
	case 8:
	    FileName = "/usr/local/pcbsd/graphics/docs.png";
	    textLabelAd->setText(tr("Check out the quick-guide"));
	    PromoAd++;
	    break;
	case 9:
	    FileName = "/usr/local/pcbsd/graphics/forums.png";
	    textLabelAd->setText(tr("Join the community"));
	    PromoAd++;
	    break;
	 case 10:
	    FileName = "/usr/local/pcbsd/graphics/pbis.png";
	    textLabelAd->setText(tr("Install software with a click"));
	    PromoAd = 1;
	    break;
	default:
	    PromoAd = 1;
	    return;
	    break;
    }
    
    

   frameDisplayAd->setStyleSheet(QString::fromUtf8("background-image: url(" + FileName + ");"));

    QTimer::singleShot( 15000, this, SLOT(changePromoAd()) );
    
    
}


void PCInstall::checkVmwareSystemSlot()
{
    // If we are NOT running on vmware
   if(CheckVMware->normalExit() && CheckVMware->exitStatus() == 1 )
    {
	QFont f( "Sans Serif", 11);
        //setFont( f );    
    }
   
}





void PCInstall::listBoxLayoutChanged()
{
    /*
    QString tmp;
    
    tmp = listBoxKeyLayout->currentText();
    tmp.truncate(tmp.find(" ") );
    
        // Start with the update system config script
   SetKeyboard= new Q3Process( this );
   SetKeyboard->addArgument( "/usr/local/pcbsd/scripts/PCBSD.SetKeyboard.sh" );
   SetKeyboard->addArgument( tmp );
   
    if ( !SetKeyboard->start() ) {
	QMessageBox::warning( this, tr("PCBSD Installer"),  tr("Failed Starting SetKeyboard.sh"), tr("Retry"), tr("Quit"), 0, 0, 1 );
    }
    
    */
}

void PCInstall::accept()
{
 exit(0);

}




void PCInstall::back()
{

        QString Page = title( currentPage() );
//    QMessageBox::warning( this, tr("PCBSD Installer"), Page, tr("Retry"), tr("Quit"), 0, 0, 1 );
    
    if ( Page == tr("Select Language and Keyboard") ) // Page 0
    {
	
    }
    
     if ( Page == tr("License") ) // Page 1
    {
	// Go back to the first page
	 showPage(page(0));
    }
    
    
    if ( Page == tr("Install or Update") ) // Page 2
    {
	 showPage(page(1));
    }
    

    if ( Page == tr("User Accounts") )  // Page 3
    {
	 showPage(page(2));	
    }
    
      if ( Page == tr("Disk Selection") ) // Page 4
    {
          showPage(page(3));
    }
    
    
     if ( Page == tr("Advanced Disk Setup") ) // Page 5
    {
	  showPage(page(4));
    }
    
    
    if ( Page == tr("Select Update Partition") ) // Page 6
    {
	 showPage(page(2) ); 

    }
    
     if ( Page == tr("System Components") )  // Page 7
    {
	// If the user wanted to  upgrade, jump to that screen
	if ( ! radioFreshInstall->isChecked() )
	{
	    showPage(page(6));
	    return;
	} else {
            if ( checkCustomPartition->isChecked() )
            {
	     showPage(page(5) );
            } else {
	     showPage(page(4) );
            }
	}
    }
    
    
    if ( Page == tr("Start Basic Install") ) // Page 8
    {
	showPage(page(7));
    }
    
    if ( Page == tr("Installing PC-BSD") ) // Page 9
    {
	
    }
    
    if ( Page == tr("Installation Finished!") ) // Page 10
    {

    }
    
}




void PCInstall::next()
{
    QString Page = title( currentPage() );
//    QMessageBox::warning( this, tr("PCBSD Installer"), Page, tr("Retry"), tr("Quit"), 0, 0, 1 );
    
    if ( Page == tr("Select Language and Keyboard") ) // Page 0
    {
	showPage(page(1));
    }
    
     if ( Page == tr("License") ) // Page 1
    {
	 showPage(page(2));
    }
    
    
    if ( Page == tr("Install or Update") ) // Page 2
    {
	if ( radioNetworkInstall->isChecked() )
	{
	    // Bring up the network dialog NIC selector
	    networkDialog = new EditNetworkDialog();
	    connect(networkDialog, SIGNAL(saved(QString, QString, QString, QString)), this, SLOT(nicSavedSlot(QString, QString, QString, QString)) );
	    networkDialog->ProgramInit();
	    networkDialog->exec();
	    return; 
	} else {
           // Make sure we don't have a network file tripping us up
	   system("rm /tmp/networkURL 2>/dev/null");
	}
	
	
	// If the user wanted to  upgrade, jump to that screen
	if ( ! radioFreshInstall->isChecked() )
	{
	    showPage(page(6));
	    return;
	} else {
	    showPage(page(3) );  
	}
    }
    
    if ( Page == tr("User Accounts") ) // Page 3
    {

	showPage(page(4));
    }
    
      if ( Page == tr("Disk Selection") ) // Page 4
    {
        if ( checkCustomPartition->isChecked() )
        {
           showPage( page(5) );
        } else {
           showPage( page(7) );
        }
    }
    
     if ( Page == tr("Advanced Disk Setup") ) // Page 5
    {
	showPage(page(7));
    }
    
    if ( Page == tr("Select Update Partition") ) // Page 6
    {
	showPage(page(7));
    }
    
     if ( Page == tr("System Components") ) // Page 7
    {
        showPage(page(8) );  
    }
      
    if ( Page == tr("Start Basic Install") ) // Page 8
    {
	showPage(page(9));
    }
    
    if ( Page == tr("Installing PC-BSD") ) // Page 9
    {
	
    }
   
    if ( Page == tr("Installation Finished!") ) // Page 10
    {

    }

}


void PCInstall::loadComponents()
{
       
        int found = 0;
    
        QDir d( "/usr/local/pcbsd/Components");
        QString CompFile;

        QString CurLang = listBoxLang->currentText();
        CurLang.remove(0, CurLang.find("(") + 1 );
        CurLang.truncate(CurLang.find(")") );

	
        d.setFilter( QDir::Dirs );
        d.setSorting( QDir::Name );
	
        for ( uint i = 0; i < d.count(); i++ )
        {
            CompFile="component.cfg."+CurLang;
            if (!QFile::exists("/usr/local/pcbsd/Components/" + d[i] + "/" + CompFile))
              CompFile="component.cfg";
            QFile file( "/usr/local/pcbsd/Components/" + d[i] + "/"+ CompFile );
	    if ( file.open( IO_ReadOnly ) ) {
		
		ComponentDir[found]=d[i];
		
		QTextStream stream( &file );
		stream.setCodec("UTF-8");
		QString line;
		while ( !stream.atEnd() ) {
		    line = stream.readLine(); // line of text excluding '\n'
		   
		    if ( line.find("name:") == 0)
		    {
			ComponentName[found] = line.replace("name: ", "");
		    }
		    
		    if ( line.find("description:") == 0)
		    {
			ComponentDescr[found] = line.replace("description: ", "");
		    }
		    
		    
		}
		file.close();

	        ComponentSelected[found] = 0;	
	        found++;
	    }
        }
    
	
         refreshComponents();
	
}


// Adds a selected component when the user clicks the icon
void PCInstall::selectComponentSlot()
{
    
    int foundItem = 0;
	for ( int i = 0; i < 100; i++ )
	{
	    if ( ComponentDir[i].isEmpty() )
	    {
		break;
	    }
	    
	       if ( ComponentSelected[i] == 0 )
	       {
		   // Looks for the item selected and matches it in the list
		   if (listAvailComponents->isSelected(foundItem)) {
		       ComponentSelected[i] = 1;
		   }
		   foundItem++;
	       }
	    
	}

    
    refreshComponents();
}

// Removes a selected component when the user clicks the remove icon
void PCInstall::removeComponentSlot()
{
    
    int foundItem = 0;
    
	for ( int i = 0; i < 100; i++ )
	{
	    if ( ComponentDir[i].isEmpty() )
	    {
		break;
	    }
	    
	       if ( ComponentSelected[i] == 1 )
	       {
		   // Looks for the item selected and matches it in the list
		   if (listSelectedComponents->isSelected(foundItem)) {
		       ComponentSelected[i] = 0;
		   }
		   foundItem++;
	       }
	    
	}
    
    refreshComponents();
}


// Clears the components boxes and redraws them
void PCInstall::refreshComponents()
{
    
     listAvailComponents->clear();
     listSelectedComponents->clear();
     installComponents = 0;
 	
        for ( int i = 0; i < 100; i++ )
        {
	    if ( ComponentDir[i].isEmpty() )
	    {
		break;
	    }

	       // Insert a new item here, 
	       QImage *Icon = new QImage("/usr/local/pcbsd/Components/" + ComponentDir[i] + "/component.png");
	       QPixmap PixmapIcon;
	       PixmapIcon.convertFromImage(Icon->smoothScale(40,40));
	      

	     //  listAvailComponents->insertItem(PixmapIcon, ComponentName[found] + " (" + ComponentDescr[found] + ")");
	       if ( ComponentSelected[i] == 0 )
	       {
		  listAvailComponents->insertItem(PixmapIcon, ComponentName[i] + " (" + ComponentDescr[i] + ")" );  
	       } else {
		  installComponents = 1;
		  listSelectedComponents->insertItem(PixmapIcon, ComponentName[i] + " (" + ComponentDescr[i] + ")" );
	       }

        }

 //  listAvailComponents->setCurrentItem(0);
//   listSelectedComponents->setCurrentItem(0);

}


void PCInstall::slotRunInstallComponents()
{
    textFileProgress->setText(tr("Installing additional components..."));
    
    int totalItems = 0;
    
    QFile file( "/tmp/loadComponents" );
    if ( file.open( IO_WriteOnly ) ) {
	QTextStream stream( &file );

       for ( int i = 0; i < 100; i++ )
      {
            if ( ComponentDir[i].isEmpty() )
           {
	break;
            }
	    
            if ( ComponentSelected[i] == 1 )
           {
	totalItems++;
	stream <<  ComponentDir[i] + "\n";
            }
	    
      }
       
       
       	
	file.close();
    }
       
  
      InstallComponentsProc = new Q3Process( this );
      InstallComponentsProc->addArgument( "/usr/local/pcbsd/scripts/PCBSD.InstallCD3.sh" );
      
       // connect our slots
      connect( InstallComponentsProc, SIGNAL(processExited()), this, SLOT(slotFinishedInstallCD3() ) );
      connect( InstallComponentsProc, SIGNAL(readyReadStdout()), this, SLOT(readInstallComponentSlot() ) );

         if ( !InstallComponentsProc->start() ) {
	  QMessageBox::warning( this, "PCBSD Installer", "Failed Starting InstallComponentSlot", "Retry", "Quit", 0, 0, 1 );
        }
    

    

}


void PCInstall::readInstallComponentSlot()
{
  QString Buffer;

    // Loop while getting input
    while (InstallComponentsProc->canReadLineStdout() )
    {
	// Read the line
	Buffer = InstallComponentsProc->readLineStdout();
	// Check if we need to display the output and increment the progress bar

	    textFileProgress->setText(tr("Installing ") + Buffer);
	    // Get size for Progress Bar
	    ExtractSize = ExtractSize + 1;
	    installProgress->setProgress(ExtractSize);
    } // End while loop
    
}


void PCInstall::loadLicense()
{
    QString lic;
    QString line;
    QString tmp;

    tmp = listBoxLang->currentText();
    tmp.remove(0, tmp.find("(") + 1 );
    tmp.truncate(tmp.find(")") );
    tmp="//usr/local/pcbsd/resources/license-"+tmp+".txt";
    
    if (!QFile::exists(tmp))
      tmp="//usr/local/pcbsd/resources/license-us.txt";
    QFile file(tmp); 
    if ( file.open( IO_ReadOnly ) ) {
	QTextStream stream( &file );
        stream.setCodec("UTF-8");
	QString line;
	while ( !stream.atEnd() ) {
	    line = stream.readLine(); // line of text excluding '\n'
	    lic = lic + line + "\n";

	    }
                   file.close();
     }
    
    textLicense->setText(lic);
    
}


void PCInstall::rootPasswordLineEditLostFocus()
{
    //Check if passwords match 
    if (linePassword->text() != linePassword2->text() && ! linePassword->text().isEmpty() && ! linePassword2->text().isEmpty() )
    {
	textAcctNotify->setText(tr("Root passwords must match to continue."));
	linePassword->setPaletteBackgroundColor(colourRed);
	linePassword2->setPaletteBackgroundColor(colourRed);
    }
    else
    {
	textAcctNotify->setText(tr(""));
	linePassword->unsetPalette();
	linePassword2->unsetPalette();
    }
}


void PCInstall::userPasswordLineEditLostFocus()
{
    //Check if passwords match 
    if (lineUserPassword->text() != lineUserPassword2->text() && ! lineUserPassword->text().isEmpty() && ! lineUserPassword2->text().isEmpty() )
    {
	lineUserPassword->setPaletteBackgroundColor(colourRed);
	lineUserPassword2->setPaletteBackgroundColor(colourRed);
	textAcctNotify->setText(tr("Error: User passwords do not match!"));
    }
    else
    {
	lineUserPassword->unsetPalette();
	lineUserPassword2->unsetPalette();
    }
    
}


void PCInstall::slotChangeKeyboard()
{
    
               QString layout, model, variant;
	       
	layout = textKBLayout->text();
	model = textKBModel->text();
	variant = textKBVariant->text();
    
	layout.truncate(layout.find(" "));
	model.truncate(model.find(" "));
	variant.truncate(variant.find(" "));
	
    	// Launch our AddPartitionDialog to add a new device
	keyboardDialog = new dialogKeyboard();
	connect(keyboardDialog, SIGNAL(saved(QString &, QString &, QString &)), this, SLOT(changeKeyboardSlot(QString &, QString &, QString &)) );
	keyboardDialog->programInit();
	keyboardDialog->setKeyboard( layout, model, variant);
	keyboardDialog->exec();

}


void PCInstall::changeKeyboardSlot( QString &layout, QString &model, QString &variant )
{
    QString tmp, tmp2, tmp3;
    
    // Save the new settings to the GUI
    textKBLayout->setText(layout);
    textKBModel->setText(model);
    textKBVariant->setText(variant);
    
    // Now run the SetKeyboard.sh
    tmp = textKBLayout->text();
    tmp.truncate(tmp.find(" ") );
    
    tmp2 = textKBModel->text();
    tmp2.truncate(tmp2.find(" ") );
    
    tmp3 = textKBVariant->text();
    tmp3.truncate(tmp3.find(" ") );
    

    // Start with the update system config script
   SetKeyboard= new Q3Process( this );
   SetKeyboard->addArgument( "/usr/local/pcbsd/scripts/PCBSD.SetKeyboard.sh" );
   SetKeyboard->addArgument( tmp );
   SetKeyboard->addArgument( tmp2 );
   SetKeyboard->addArgument( tmp3 );
   
    if ( !SetKeyboard->start() ) {
        QMessageBox::warning( this, tr("PCBSD Installer"),  tr("Failed Starting SetKeyboard.sh"), tr("Retry"), tr("Quit"), 0, 0, 1 );
    }

    
}


void PCInstall::slotStartMountCD2()
{
    // Slot to start the mount process for CD2 to finish the install from it     
    textFileProgress->setText(tr("Unmounting CD #1..."));
    
    EjectCD = new Q3Process( this );
    EjectCD->addArgument( "/usr/local/pcbsd/scripts/PCBSD.EjectCD.sh" );

     if ( !EjectCD->start() ) {
	QMessageBox::warning( this, "PCBSD Installer", "Failed Starting EjectCD", "Retry", "Quit", 0, 0, 1 );
    }
    
    
    
    QMessageBox::information( this, tr("Insert CD #2"), tr("Insert CD #2 and click OK to continue. ") );
	   
    
    
    textFileProgress->setText(tr("Mounting CD #2..."));
    
      //Setup Process to mount the root partition
    FindLangCD = new Q3Process( this );
    FindLangCD->addArgument( "/usr/local/pcbsd/scripts/PCBSD.MountCD2.sh" );

    connect( FindLangCD, SIGNAL(processExited()), this, SLOT(FinishedMountLangCDSlot() ) );

    if ( !FindLangCD->start() ) {
	QMessageBox::warning( this, "PCBSD Installer", "Failed Starting MountCD2", "Retry", "Quit", 0, 0, 1 );
    }

}


void PCInstall::slotInstallCD2()
{
     textFileProgress->setText(tr("Installing CD2..."));
    
     // We have mounted CD2, now lets kick off the installer for it
    installCD2proc = new Q3Process( this );
    installCD2proc->addArgument( "/usr/local/pcbsd/scripts/PCBSD.InstallCD2.sh" );
    // Additional options will be here to indicate a server / desktop install
    if ( radioDesktop->isChecked() )
    {
	installCD2proc->addArgument("DESKTOP");
    } else {
	installCD2proc->addArgument("SERVER");
    }

     connect( installCD2proc, SIGNAL(processExited()), this, SLOT(slotFinishedInstallCD2() ) );

     connect( installCD2proc, SIGNAL(readyReadStdout()), this, SLOT(slotReadCD2Status() ) );
    
    if ( !installCD2proc->start() ) {
	QMessageBox::warning( this, "PCBSD Installer", "Failed Starting PCBSD.InstallCD2.sh", "Retry", "Quit", 0, 0, 1 );
    }
    
    
    

}


void PCInstall::slotFinishedInstallCD2()
{
      // Check if we need to proceede to CD3 now and load the optional stuff
      if ( installComponents == 1 || listBoxLang->currentItem() != 0 )
      {
         if ( usingDVDmedia == 0 )
         {
	    // Run the slot to install the components
	    slotStartMountCD3();
         } else {
           // Looks like we have a DVD, lets install from it now
           slotRunInstallComponents();
         }
      } else {
	  // If no extra components, then lets finish up the install
	if ( radioFreshInstall->isChecked() )
	{
            // Run our setup scripts now, starting with the user add slot
            setupUsersSlot();
	} else {
	    slotRunFinalScriptUpgrade();
	} 
      }

}


void PCInstall::slotReadCD2Status()
{
  QString Buffer, tmp;

    // Loop while getting input
    while (installCD2proc->canReadLineStdout() )
    {
	// Read the line
	Buffer = installCD2proc->readLineStdout();
	
	if (Buffer.find("MSG:") != -1 )
	{
	    Buffer.remove(0,4 );
	    
	    textFileProgress->setText(Buffer);

	} 
	
	// Remove the "x" from the start
	if ( Buffer.find("x", 0) == 0)
	{
	    Buffer.remove(0, 3);
	    tmp = Buffer;
	    Buffer = tmp;
	    textFileProgress->setText(Buffer);
                    ExtractSize = ExtractSize + 1;  
	     // Get size for Progress Bar

	    installProgress->setProgress(ExtractSize);
	}
    } // End while loop
}


void PCInstall::slotStartMountCD3()
{
    // Slot to start the mount process for CD2 to finish the install from it     
    textFileProgress->setText(tr("Unmounting CD #2..."));
    
    EjectCD = new Q3Process( this );
    EjectCD->addArgument( "/usr/local/pcbsd/scripts/PCBSD.EjectCD.sh" );

     if ( !EjectCD->start() ) {
	QMessageBox::warning( this, "PCBSD Installer", "Failed Starting EjectCD", "Retry", "Quit", 0, 0, 1 );
    }
    
    
    
    QMessageBox::information( this, tr("Insert CD #3"), tr("Insert CD #3 and click OK to continue. ") );
	   
    
    
    textFileProgress->setText(tr("Mounting CD #3..."));
    
      //Setup Process to mount the root partition
    findCD3proc = new Q3Process( this );
    findCD3proc->addArgument( "/usr/local/pcbsd/scripts/PCBSD.MountCD3.sh" );

    connect( findCD3proc, SIGNAL(processExited()), this, SLOT(slotFinishedMountCD3() ) );

    if ( !findCD3proc->start() ) {
	QMessageBox::warning( this, "PCBSD Installer", "Failed Starting MountCD3", "Retry", "Quit", 0, 0, 1 );
    }
}


void PCInstall::slotFinishedMountCD3()
{
     // If the CD mounted successfully
    if(findCD3proc->normalExit() && findCD3proc->exitStatus() == 0 )
    {
      // We are ready to install the optional components now
      slotRunInstallComponents();
    } else {

        switch( QMessageBox::warning( this, tr("CD Mount Error"), tr("Error: Could not locate CD #3. Please check that the CD is in the drive. Press OK to try again, or Cancel to abort install."), tr("OK"), tr("Cancel"), 0, 0, 1 ) ) {
             case 0: // The user clicked the OK again button or pressed Enter
                 slotStartMountCD3();
                 break;
             case 1: // The user clicked the Quit or pressed Escape
                 exit(5);
                 return;
                 break;
             }
    }
}


void PCInstall::slotFinishedInstallCD3()
{
       // All ready to finish up the install, check the type of install we were doing, and finish it now
      if ( radioFreshInstall->isChecked() )
      {
            // Setup our users and run final scripts now
            setupUsersSlot();
      } else {
           slotRunFinalScriptUpgrade();
     } 
}


// Slot which is called when a user selects the NIC configuration he wants
// to use to install PCBSD
void PCInstall::nicSavedSlot(QString NIC, QString IP, QString NM, QString Gate)
{
   // Apply the network configuration, and display a popup letting the user know what we are
   // doing
   workDialog = new WorkingDialog();
   workDialog->setModal(true);
   workDialog->setText(tr("Enabling NIC"));
   workDialog->setTitle(tr("Network Setup"));
   workDialog->show();      

   // Create our process now and start it
   enableNICproc = new QProcess(this);
   QString program = "/usr/local/pcbsd/scripts/PCBSD.SetNic.sh";
   QStringList arguments;
   arguments << NIC << IP << NM << Gate;
   connect( enableNICproc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(nicFinishedSlot(int, QProcess::ExitStatus) ) );
   enableNICproc->start(program, arguments);

}


// Get the results from our NIC enable process
void PCInstall::nicFinishedSlot(int exitCode, QProcess::ExitStatus exitStatus)
{
  if ( exitCode != 0 )
  {
     QMessageBox::warning( this, tr("Network Setup"), tr("Failed to setup a network connection!") );
     radioCDInstall->setChecked(true);
     workDialog->doClose();
  } else {
     // Close the working dialog
     workDialog->doClose();

     // Now bring up the dialog which asks for the source media of this install
     selectNetDialog = new dialogSelectNetServer();
     selectNetDialog->setModal(true);
     selectNetDialog->programInit();
     connect( selectNetDialog, SIGNAL(saved(bool, QString)), this, SLOT(netDialogSlot(bool, QString) ) );
     selectNetDialog->show(); 
  }

}

void PCInstall::netDialogSlot(bool internet, QString ServerURL)
{
  QString tmp;
  networkServerURL = ServerURL;
  usingInternetInstall = internet;


  if ( networkServerURL.lastIndexOf("/") != networkServerURL.size() )
  {
       networkServerURL = networkServerURL + "/";
  } 

  // Save our tmp file with the URL of the images we want to use
  QFile file2( "/tmp/networkURL" );
  if ( file2.open( IO_WriteOnly ) ) {
      QTextStream stream2( &file2 );
      stream2 << networkServerURL;
      file2.close();
  }


   // Now lets go ahead and confirm that we have a valid network install path
   workDialog = new WorkingDialog();
   workDialog->setModal(true);
   workDialog->setText(tr("Confirming valid network location"));
   workDialog->setTitle(tr("Network Setup"));
   workDialog->show();

   // Create our process now and start it
   confirmNetproc = new QProcess(this);
   QString program = "/usr/local/pcbsd/scripts/PCBSD.ConfirmNetFiles.sh";
   QStringList arguments;
   connect( confirmNetproc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(netFinishedConfirmSlot(int, QProcess::ExitStatus) ) );
   confirmNetproc->start(program, arguments);

    

}

void PCInstall::netFinishedConfirmSlot(int exitCode, QProcess::ExitStatus exitStatus)
{
  
  // Close the working dialog
  workDialog->doClose();

  // Check if we found valid install data at this location
  if ( exitCode == 0)
  {

    networkInstall = true;

    // Now move us to the next wizard page, the network setup is complete.
    // If the user wanted to upgrade, jump to that screen
    if ( ! radioFreshInstall->isChecked() )
    {
       showPage(page(6));
       return;
    } else {
       showPage(page(3));
       return;
    }

  } else {
    // Looks like we have a bad network install path, PCBSD.tar.lzma and / or
    // PCBSD.tar.lzma2 could not be found
    networkInstall = false;
     
    QMessageBox::warning( this, tr("Network Setup"), tr("The specified URL does not appear to be a valid install location. Please check the network location and try again.") );

  }

}

void PCInstall::checkFileSystemSlot(const QString &text)
{
   if ( text.indexOf("ZFS") != -1)
   {
    QMessageBox::warning( this, tr("ZFS Warning"), tr("Warning: ZFS usage is primarily for high-end systems with a 64 bit processor and 4+ GB of memory. It may run on lesser hardware, but is not recommended.") );
   }
}
