# Creating a new guest
use strict;
use warnings;
our (%gui, %signal, %sensgrp, %ETruth, %hostspec, %osfamily, %osversion, %EMediumVariant);

sub show_newguest_dialog() {
    my %IMediumHD = &get_all_media('HardDisk');
    $gui{entryNewName}->set_text('NewGuest' . int(rand(9999)));
    $gui{notebookNew}->set_current_page(0);
    $gui{spinbuttonNewMemory}->set_range(4, $hostspec{memsize});
    $gui{spinbuttonNewHDSize}->set_range(8.00, int($hostspec{maxhdsize} / 1048576));
    $gui{comboboxNewOSFam}->signal_handler_block($signal{fam}); # Block to avoid signal emission when changing
    $gui{comboboxNewOSVer}->signal_handler_block($signal{ver});
    &clr_list($gui{liststoreNewOSFam}, $gui{liststoreNewOSVer}, $gui{liststoreNewChooseHD});

    foreach my $fam (sort(keys %osfamily)) {
        my $iter = &addrow_list($gui{liststoreNewOSFam}, 0, "$osfamily{$fam}{description}", 1, $fam, 2, $osfamily{$fam}{icon});
        $gui{comboboxNewOSFam}->set_active_iter($iter) if ($fam eq 'Windows');
    }

    if (keys(%IMediumHD) > 0) {

        foreach my $hd (sort { lc($a) cmp lc($b) } (keys %IMediumHD)) {
            &addrow_list($gui{liststoreNewChooseHD}, 0, $hd, 1, $IMediumHD{$hd});
        }

        $gui{comboboxNewChooseHD}->set_active(0);
        &sensitive_on($gui{radiobuttonNewExistingHD});
    }
    else { &sensitive_off($gui{radiobuttonNewExistingHD}) };

    $gui{comboboxNewOSFam}->signal_handler_unblock($signal{fam});
    $gui{comboboxNewOSVer}->signal_handler_unblock($signal{ver});
    $gui{comboboxNewOSFam}->signal_emit('changed'); # Force update of other fields based on OS
    $gui{comboboxNewOSVer}->signal_emit('changed'); # Force update of other fields based on OS
    my $response = $gui{dialogNew}->run;
    $gui{dialogNew}->hide;

    if ($response eq 'ok') {
        my $buttongrp = $gui{radiobuttonNewNewHD}->get_group();
        my %newguest = (name   => $gui{entryNewName}->get_text(),
                        fam    => &getsel_combo($gui{comboboxNewOSFam}, 1),
                        ver    => &getsel_combo($gui{comboboxNewOSVer}, 1),
                        mem    => $gui{spinbuttonNewMemory}->get_value_as_int(),
                        hdsize => $gui{spinbuttonNewHDSize}->get_value_as_int() * 1048576);

        &show_err_msg('blankguest', $gui{messagedialogError}) if (!$newguest{name});
        return if (!$newguest{name});
        my ($IMachine, $dvdctrname, $hdctrname) = &create_new_guest(%newguest);

        if ($IMachine) {
            my ($ISession, $IMachineM) = &get_mutable_session($IMachine);
            my $IMediumHD;

            if ($$buttongrp[0]->get_active() == 1) { $IMediumHD = &getsel_combo($gui{comboboxNewChooseHD}, 1); }
            else {
                my $type = $EMediumVariant{Fixed};
                $type = $EMediumVariant{Standard} if ($gui{checkbuttonNewDynamic}->get_active());
                $IMediumHD = &create_new_hd($newguest{name}, "$hostspec{machinedir}/$newguest{name}", 'vdi', $type, $newguest{hdsize}, $gui{windowMain});
            }

            my $IStorCtrHD = IMachine_getStorageControllerByName($IMachineM, $hdctrname);
            &create_sas_sata_port($IStorCtrHD);
            my ($hddev, $hdport) = &get_free_deviceport($IMachineM, $IStorCtrHD);
            IMachine_attachDevice($IMachineM, $hdctrname, $hdport, $hddev, 'HardDisk', $IMediumHD);
            my $IStorCtrDVD = IMachine_getStorageControllerByName($IMachineM, $dvdctrname); # Attach Empty CD/DVD Device
            &create_sas_sata_port($IStorCtrDVD);
            my ($dvddev, $dvdport) = &get_free_deviceport($IMachineM, $IStorCtrDVD);
            IMachine_attachDevice($IMachineM, $dvdctrname, $dvdport, $dvddev, 'DVD', '');
            IMachine_saveSettings($IMachineM);
            ISession_unlockMachine($ISession);
        }
        else { &show_err_msg('createguest', $gui{messagedialogError}, " ($newguest{name})"); }

        &fill_list_guest();
    }
}

sub create_new_guest() {
    my %newguest = @_;
    my %os = %{ $osversion{$newguest{ver}} };
    my $dvdctrname = $os{recommendedDvdStorageBus} .  ' Controller';
    my $hdctrname = $os{recommendedHdStorageBus} . ' Controller';
    my $portnum = int(rand(15000)) + 50000; # Pick random between 50000 and 65000
    my $IMachine = IVirtualBox_createMachine($gui{websn}, '', $newguest{name}, $newguest{ver}, 'UUID 00000000-0000-0000-0000-000000000000', '');

    if ($IMachine) {
        my $IVRDEServer = IMachine_getVRDEServer($IMachine);
        my $IBIOSSettings = IMachine_getBIOSSettings($IMachine);
        IBIOSSettings_setIOAPICEnabled($IBIOSSettings, $ETruth{$os{recommendedIOAPIC}});
        IMachine_setCPUProperty($IMachine, 'PAE', $ETruth{$os{recommendedPae}});
        IMachine_setHWVirtExProperty($IMachine, 'Enabled', $ETruth{$os{recommendedVirtEx}});
        IMachine_setHpetEnabled($IMachine, $ETruth{$os{recommendedHpet}});
        IMachine_setVRAMSize($IMachine, $os{recommendedVRAM});
        IMachine_setFirmwareType($IMachine, $os{recommendedFirmware});
        IMachine_setMemorySize($IMachine, $newguest{mem});
        IMachine_setRTCUseUTC($IMachine, $ETruth{$os{recommendedRtcUseUtc}});

        if ($os{recommendedUsbHid} eq 'true') {
            my $IUSBController = IMachine_getUSBController($IMachine);
            IUSBController_setEnabled($IUSBController, 1);
            IMachine_setPointingHidType($IMachine, 'USBMouse');
        }

        if ($os{recommendedUsbTablet} eq 'true') {
            my $IUSBController = IMachine_getUSBController($IMachine);
            IUSBController_setEnabled($IUSBController, 1);
            IMachine_setPointingHidType($IMachine, 'USBTablet');
        }

        my $IStorCtrDVD = IMachine_addStorageController($IMachine, $dvdctrname, $os{recommendedDvdStorageBus});
        IStorageController_setControllerType($IStorCtrDVD, $os{recommendedDvdStorageController});

        if ($os{recommendedHdStorageBus} ne $os{recommendedDvdStorageBus}) {
            my $IStorCtrHD = IMachine_addStorageController($IMachine, $hdctrname, $os{recommendedHdStorageBus});
            IStorageController_setControllerType($IStorCtrHD, $os{recommendedHdStorageController});
        }

        foreach my $slot (0..7) {
            my $INetworkAdapter = IMachine_getNetworkAdapter($IMachine, $slot);
            INetworkAdapter_setAdapterType($INetworkAdapter, $os{adapterType});
        }

        IVRDEServer_setVRDEProperty($IVRDEServer, 'VideoChannel/Quality', 75);
        IVRDEServer_setVRDEProperty($IVRDEServer, 'TCP/Ports', $portnum);
        IVRDEServer_setEnabled($IVRDEServer, 'true');
        IMachine_saveSettings($IMachine);
        IVirtualBox_registerMachine($gui{websn}, $IMachine);
        &addrow_log("Created a new guest: $newguest{name}.");
    }

    return $IMachine, $dvdctrname, $hdctrname;
}

sub create_new_hd() {
    my ($name, $location, $format, $type, $size, $transwin) = @_;
    my $IMedium = IVirtualBox_createHardDisk($gui{websn}, $format, "$location/$name.$format");
    my $IProgress = IMedium_createBaseStorage($IMedium, $size, $type);
    &show_progress_window($IProgress, "Creating Hard Disk...", '', $transwin);
    &addrow_log("Created new hard disk: $location/$name.$format");
    return $IMedium;
}

# SATA/SAS Controllers need a port created before attachments can be made
sub create_sas_sata_port() {
    my ($IStorCtr) = @_;
    my $bus = IStorageController_getBus($IStorCtr);
    if ($bus eq 'SATA' or $bus eq 'SAS') {
        my ($pc, $mpc) = (IStorageController_getPortCount($IStorCtr), IStorageController_getMaxPortCount($IStorCtr));
        IStorageController_setPortCount($IStorCtr, $pc + 1) if ($pc < $mpc);
    }
}

sub newgen_osfam() {
    my ($combofam, $combover) = @_;
    my $fam = &getsel_combo($combofam, 1);
    $combofam->signal_handler_block($signal{fam}); # Block to avoid signal emission when changing
    $combover->signal_handler_block($signal{ver});
    &clr_list($gui{liststoreNewOSVer});

    foreach my $ver (sort(@{ $osfamily{$fam}{verids} })) {
        my $iter = &addrow_list($gui{liststoreNewOSVer}, 0, $osversion{$ver}{description}, 1, $ver, 2, $osversion{$ver}{icon});
        $combover->set_active_iter($iter) if ($ver eq 'WindowsXP' | $ver eq 'Ubuntu' | $ver eq 'Solaris');
    }

    $combover->set_active(0) if ($combover->get_active() == -1);
    $combofam->signal_handler_unblock($signal{fam});
    $combover->signal_handler_unblock($signal{ver});
    $combover->signal_emit('changed'); # Force update of other fields based on OS
}

sub newgen_osver() {
    my ($combover, $combofam) = @_;
    my $ver = &getsel_combo($combover, 1);
    $combofam->signal_handler_block($signal{fam}); # Avoid signal emission when changing
    $combover->signal_handler_block($signal{ver});
    $gui{spinbuttonNewMemory}->set_value($osversion{$ver}{recommendedRAM});
    $gui{spinbuttonNewHDSize}->set_value($osversion{$ver}{recommendedHDD} / 1048576);
    $combofam->signal_handler_unblock($signal{fam});
    $combover->signal_handler_unblock($signal{ver});
}

sub newstor_new_exist() {
    my ($widget) = @_;
    my $buttongrp = $widget->get_group();

    if ($$buttongrp[0]->get_active() == 1) {
        &sensitive_on($gui{comboboxNewChooseHD});
        &sensitive_off($gui{checkbuttonNewDynamic}, $gui{spinbuttonNewHDSize});
    }
    else {
        &sensitive_off($gui{comboboxNewChooseHD});
        &sensitive_on($gui{checkbuttonNewDynamic}, $gui{spinbuttonNewHDSize});
    }
}

1;