# The Motherboard page of the System Settings
use strict;
use warnings;
our (%gui, %vmc, %signal);

# Sets up the initial state of the system tab of the edit settings dialog
sub init_edit_sys_mother {
    &set_pointer($gui{dialogEdit}, 'watch');
    my $vhost = &vhost();
    $gui{buttonEditSysBootUp}->set_sensitive(0);
    $gui{buttonEditSysBootDown}->set_sensitive(0);
    &clr_list_generic($gui{treeviewEditSysBoot}, $signal{treeviewEditSysBoot_cursorChanged1});

    # Secureboot requires EFI so only enable it. It may also need to be initialised ultimately
    $gui{checkbuttonEditSysSecureBoot}->signal_handler_block($signal{checkbuttonEditSysSecureBoot_toggled});

    if (IFirmwareSettings_getFirmwareType($vmc{IFirmwareSettings}) =~ m/^EFI/) {
        $gui{checkbuttonEditSysEFI}->set_active(1);
        $gui{checkbuttonEditSysSecureBoot}->set_sensitive(1);
        $gui{buttonEditSysResetBootKeys}->set_sensitive(1);
        my $INvramStore = IMachine_getNonVolatileStore($vmc{IMachine});
        my $IUefiVariableStore = INvramStore_getUefiVariableStore($INvramStore);
        if (!defined($IUefiVariableStore)) { $gui{checkbuttonEditSysSecureBoot}->set_active(0); }
        else { $gui{checkbuttonEditSysSecureBoot}->set_active(&bl(IUefiVariableStore_getSecureBootEnabled($IUefiVariableStore)));}
    }
    else {
        $gui{checkbuttonEditSysEFI}->set_active(0);
        $gui{checkbuttonEditSysSecureBoot}->set_active(0);
        $gui{checkbuttonEditSysSecureBoot}->set_sensitive(0);
        $gui{buttonEditSysResetBootKeys}->set_sensitive(0);
    }

    $gui{checkbuttonEditSysSecureBoot}->signal_handler_unblock($signal{checkbuttonEditSysSecureBoot_toggled});
    $gui{spinbuttonEditSysMem}->set_range($$vhost{minguestram}, $$vhost{memsize});
    $gui{spinbuttonEditSysMem}->set_value(IMachine_getMemorySize($vmc{IMachine}));
    $gui{checkbuttonEditSysAPIC}->set_active(&bl(IFirmwareSettings_getIOAPICEnabled($vmc{IFirmwareSettings})));
    $gui{checkbuttonEditSysUTC}->set_active(&bl(IPlatform_getRTCUseUTC($vmc{IPlatform})));
    &combobox_set_active_text($gui{comboboxEditSysChipset}, IPlatform_getChipsetType($vmc{IPlatform}), 0);
    &combobox_set_active_text($gui{comboboxEditSysPointing}, IMachine_getPointingHIDType($vmc{IMachine}), 0);
    &combobox_set_active_text($gui{comboboxEditSysKeyboard}, IMachine_getKeyboardHIDType($vmc{IMachine}), 0);

    # Default to maxbootpos+1 to mean 'not set in boot order' but this number needs to be higher than
    # true boot order numbers so the disabled devices appear at the end of the list.
    my %bootorder = (Floppy   => $$vhost{maxbootpos} + 1,
                     DVD      => $$vhost{maxbootpos} + 1,
                     HardDisk => $$vhost{maxbootpos} + 1,
                     Network  => $$vhost{maxbootpos} + 1);

    my %devdesc = (Floppy   => 'Floppy Disk',
                   DVD      => 'Optical Disc',
                   HardDisk => 'Hard Disk',
                   Network  => 'Network');

    # Find boot order and set value in hash accordingly. Empty boot slots return 'Null' so skip them
    foreach (1..$$vhost{maxbootpos}) {
        my $bootdev = IMachine_getBootOrder($vmc{IMachine}, $_);
        next if ($bootdev eq 'Null');
        $bootorder{$bootdev} = $_;
    }

    # Returns hash keys sorted by value (ie boot order). Disabled devices appear at end
    foreach my $dev (sort {$bootorder{$a} cmp $bootorder{$b}} keys %bootorder) {
        if ($bootorder{$dev} == $$vhost{maxbootpos} + 1) {
            my $iter = $gui{liststoreEditSysBoot}->append();
            $gui{liststoreEditSysBoot}->set($iter, [0, 1, 2, 3], [0, $dev, $gui{pb}{$dev}, $devdesc{$dev}]);
       }
        else {
            my $iter = $gui{liststoreEditSysBoot}->append();
            $gui{liststoreEditSysBoot}->set($iter, [0, 1, 2, 3], [1, $dev, $gui{pb}{$dev}, $devdesc{$dev}]);
        }
    }

    # Set up the TPM Section
    $gui{comboboxEditSysTPM}->signal_handler_block($signal{comboboxEditSysTPM_changed});
    $gui{liststoreEditSysTPM}->clear();
    foreach (@{$$vhost{tpmtypes}}) {
        my $name = $_;
        $name =~s /_/./;
        my $tpmiter = $gui{liststoreEditSysTPM}->append();
        $gui{liststoreEditSysTPM}->set($tpmiter, [0, 1], [$name, $_]);
    }

    my $ITrustedPlatformModule = IMachine_getTrustedPlatformModule($vmc{IMachine});
    &combobox_set_active_text($gui{comboboxEditSysTPM}, ITrustedPlatformModule_getType($ITrustedPlatformModule), 1);
    $gui{comboboxEditSysTPM}->signal_handler_unblock($signal{comboboxEditSysTPM_changed});
    &set_pointer($gui{dialogEdit});
}

# Sets the amount of main system memory
sub sys_mother_mem {
    if ($vmc{SessionType} eq 'WriteLock') { IMachine_setMemorySize($vmc{IMachine}, $gui{spinbuttonEditSysMem}->get_value_as_int()); }
}

# Sets with IO APIC should be enabled or not in the guest
sub sys_mother_ioapic {
    if ($vmc{SessionType} eq 'WriteLock') { IFirmwareSettings_setIOAPICEnabled($vmc{IFirmwareSettings}, $gui{checkbuttonEditSysAPIC}->get_active()); }
}

# Sets whether the machine should use EFI or the traditional BIOS
sub sys_mother_efi {
    if ($vmc{SessionType} eq 'WriteLock') {
        if ($gui{checkbuttonEditSysEFI}->get_active() == 1) {
            IFirmwareSettings_setFirmwareType($vmc{IFirmwareSettings}, 'EFI');
            $gui{checkbuttonEditSysSecureBoot}->set_sensitive(1);
            $gui{buttonEditSysResetBootKeys}->set_sensitive(1);
        }
        else {
            IFirmwareSettings_setFirmwareType($vmc{IFirmwareSettings}, 'BIOS');
            $gui{checkbuttonEditSysSecureBoot}->set_sensitive(0);
            $gui{buttonEditSysResetBootKeys}->set_sensitive(0);
        }
    }
}

# Sets the type of TPM connected
sub sys_mother_tpm {
    if ($vmc{SessionType} eq 'WriteLock') {
        my $ITrustedPlatformModule = IMachine_getTrustedPlatformModule($vmc{IMachine});
        ITrustedPlatformModule_setType($ITrustedPlatformModule, &getsel_combo($gui{comboboxEditSysTPM}, 1));
    }
}

# Sets whether the guest clock is UTC or local time
sub sys_mother_utc {
    if ($vmc{SessionType} eq 'WriteLock') { IPlatform_setRTCUseUTC($vmc{IPlatform}, $gui{checkbuttonEditSysUTC}->get_active()); }
}

# Sets whether secure boot is enabled
sub sys_mother_secureboot {
    if ($vmc{SessionType} eq 'WriteLock') {
        my $INvramStore = IMachine_getNonVolatileStore($vmc{IMachine});
        my $IUefiVariableStore = INvramStore_getUefiVariableStore($INvramStore);

        if (!defined($IUefiVariableStore)) {
            &show_err_msg('nouefivarfile');
            INvramStore_initUefiVariableStore($INvramStore, 0);
            $IUefiVariableStore = INvramStore_getUefiVariableStore($INvramStore);
        };

        IUefiVariableStore_setSecureBootEnabled($IUefiVariableStore, $gui{checkbuttonEditSysSecureBoot}->get_active());
    }
}

# Not actually supported by RemoteBox yet
sub sys_mother_reset_boot_keys {
    &show_err_msg('resetbootkeys');
}

# Sets the emulated pointing (eg mouse) device
sub sys_mother_pointer {
    if ($vmc{SessionType} eq 'WriteLock') { IMachine_setPointingHIDType($vmc{IMachine}, &getsel_combo($gui{comboboxEditSysPointing}, 0)); }
}

# Sets the emulatyed keyboard type
sub sys_mother_keyboard {
    if ($vmc{SessionType} eq 'WriteLock') { IMachine_setKeyboardHIDType($vmc{IMachine}, &getsel_combo($gui{comboboxEditSysKeyboard}, 0)); }
}

# Sets the emulated motherboard chipset
sub sys_mother_chipset {
    if ($vmc{SessionType} eq 'WriteLock') { IPlatform_setChipsetType($vmc{IPlatform}, &getsel_combo($gui{comboboxEditSysChipset}, 0)); }
}

# Moves the boot device to a higher priority
sub sys_mother_boot_dev_up {
    if ($vmc{SessionType} eq 'WriteLock') {
        my ($liststore, $iter) = $gui{treeviewEditSysBoot}->get_selection->get_selected();
        my $path = $liststore->get_path($iter);
        $path->prev; # Modifies path directly
        my $iter_prev = $liststore->get_iter($path);
        $liststore->move_before($iter, $iter_prev) if (defined($iter_prev) and $liststore->iter_is_valid($iter_prev));
    }
}

# Moves the boot device to a lower priority
sub sys_mother_boot_dev_down {
    if ($vmc{SessionType} eq 'WriteLock') {
        my ($liststore, $iter) = $gui{treeviewEditSysBoot}->get_selection->get_selected();
        my (undef, $iter_next) = $gui{treeviewEditSysBoot}->get_selection->get_selected();
        $liststore->iter_next($iter_next); # Modifies the iter directly - hence the above call twice
        $liststore->move_after($iter, $iter_next) if (defined($iter_next) and $liststore->iter_is_valid($iter_next));
    }
}

sub sys_mother_boot_order {
    my $liststore = $gui{treeviewEditSysBoot}->get_model();
    my $iter = $liststore->get_iter_first();
    my $i = 1;

    while (defined($iter) and $liststore->iter_is_valid($iter)) {
        my $dev = $liststore->get($iter, 1);
        $dev = 'Null' if ($liststore->get($iter, 0) == 0);
        IMachine_setBootOrder($vmc{IMachine}, $i, $dev);
        $liststore->iter_next($iter); # Modifies the iter directly
        $i++;
    }
}

# Sets the sensitivity when a boot item is selected
sub sys_mother_sens_boot_sel {
    $gui{buttonEditSysBootDown}->set_sensitive(1);
    $gui{buttonEditSysBootUp}->set_sensitive(1);
}

sub sys_mother_boot_dev_toggle {
    my ($widget, $path_str) = @_;
    my $iter = $gui{liststoreEditSysBoot}->get_iter(Gtk3::TreePath->new_from_string($path_str));
    my $val = $gui{liststoreEditSysBoot}->get($iter, 0);
    $gui{liststoreEditSysBoot}->set ($iter, 0, !$val); # Always set the opposite of val to act as a toggle
}

1;
