#!/usr/bin/perl

use lib qw(/usr/lib/libDrakX);

use strict;
use diagnostics;
use standalone;     #- warning, standalone must be loaded very first, for 'explanations'
use common;
use interactive;
use harddrake::data;
use harddrake::sound;
use modules;
use Storable qw(store retrieve);

my $invert_do_it = $ARGV[0] eq 'X11' ? 1 : 0;
my ($hw_sysconfdir, $timeout) = ("/etc/sysconfig/harddrake2", $invert_do_it ? 600 : 25);
my $last_boot_config = $hw_sysconfdir."/previous_hw";

$last_boot_config .= '_X11' if $invert_do_it;

modules::mergein_conf('/etc/modules.conf');

# first run ? if not read old hw config
my $previous_config = -f $last_boot_config && -s $last_boot_config ? Storable::retrieve($last_boot_config) : {};
$previous_config = $$previous_config if ref($previous_config) !~ /HASH/;
my (%config, $wait);
my $in;

# For each hw, class, detect device, compare and offer to reconfigure if needed
foreach (@harddrake::data::tree) {
    my ($Ident, $item, undef, $configurator, $detector, $do_it) = @$_;
    next unless $do_it ^ $invert_do_it;
    # No detector ? (should never happen but who know ?)
    ref($detector) eq 'CODE' or next;

    my %ID = map {
        my $i = $_;
        my $id = defined $i->{device} ? $i->{device} : join(':', map { $i->{$_} } qw(vendor id subvendor subid));
        $id => $i;
    } &$detector;
    $config{$Ident} = \%ID;
    next if is_empty_hash_ref $previous_config; # don't fsck on first run

    my $oldconfig = $previous_config->{$Ident};

    my $msg;
    my @was_removed = difference2([ keys %$oldconfig ], [ keys %ID ]);
    if (@was_removed) {
     $msg .= N("Some devices in the \"%s\" hardware class were removed:\n", $item) .
         "- " . join('', map { harddrake::data::custom_id($oldconfig->{$_}, $item) . " was removed\n" } @was_removed) . "\n";
    }
    my @added = difference2([ keys %ID ], [ keys %$oldconfig ]);
    $msg .= N("Some devices were added:\n", $item) if @added;
    $msg .= "- " . harddrake::data::custom_id($ID{$_}, $item) . " was added\n" foreach @added;
    modules::load('ohci1394') if $Ident eq 'FIREWIRE_CONTROLLER' && any { $_->{driver} eq 'ohci1394' } @added;
    @added || @was_removed or next;
    my @configurator_pool;
    if (harddrake::data::is_removable($Ident)) {
        foreach my $device (@ID{@added}) {
            push @configurator_pool, harddrake::data::set_removable_configurator($Ident, $device);
        };
        foreach my $device (@$oldconfig{@was_removed}) {
            push @configurator_pool, harddrake::data::set_removable_remover($Ident, $device);
        }
    } else {
        @configurator_pool = $configurator;
    }
    next unless -x first(split /\s+/, $configurator_pool[0]);
    foreach my $configurator (@configurator_pool) {
        my ($pid, $no);
        $SIG{ALRM} = sub { $no = 1; kill 15, $pid };
        unless ($pid = fork()) {
            exec("/usr/share/harddrake/confirm 'Hardware changes in $Ident class ($timeout seconds to answer)' '" . $msg . "Do you want to run the appropriate config tool ?'");
        }
        alarm($timeout);
        wait();
        my $res = $?;
        alarm(0);
        if ($no) {
            require interactive;
            undef $wait;
            $in ||= interactive->vnew;
            $wait = $in->wait_message(N("Please wait"), N("Hardware probing in progress"));
        } elsif ($res) {
            if (fork()) {
                wait();
            } else { exec("$configurator 2>/dev/null") or die "$configurator missing\n" }
        }
    }
}

# output new hw config
log::explanations("created file $last_boot_config");
Storable::store(\%config, $last_boot_config);

# automatic sound slots configuration
harddrake::sound::configure_sound_slots();
modules::write_conf();

$in->exit(0) if $in;