#!/usr/bin/perl
################################################################################
# Backup Applet                                                                # 
#                                                                              #
# Copyright (C) 2008 Mandriva                                                  #
#                                                                              #
# Thierry Vignaud <tvignaud at mandriva dot com>                               #
#                                                                              #
# This program is free software; you can redistribute it and/or modify         #
# it under the terms of the GNU General Public License Version 2 as            #
# published by the Free Software Foundation.                                   #
#                                                                              #
# This program is distributed in the hope that it will be useful,              #
# but WITHOUT ANY WARRANTY; without even the implied warranty of               #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the                #
# GNU General Public License for more details.                                 #
#                                                                              #
# You should have received a copy of the GNU General Public License            #
# along with this program; if not, write to the Free Software                  #
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.   #
################################################################################

use strict;
use warnings;
use POSIX ":sys_wait_h";
use Config;
use lib qw(/usr/lib/libDrakX);
use standalone;                 # for explanations
use interactive;
use common;
use run_program;
use detect_devices;
use MDV::Snapshot::Hal;

BEGIN { unshift @::textdomains, 'draksnapshot' }

use mygtk3 qw(gtknew); #- do not import gtkadd which conflicts with ugtk2 version
use ugtk3 qw(:all);
use lib qw(/usr/lib/libDrakX/drakfirsttime);
use Gtk3::Notify '-init', 'draksnapshot';

if (my $pid = is_running('draksnapshot-ap')) {
    die "draksnapshot-applet already running ($pid)\n";
}

ugtk3::add_icon_path("/usr/share/draksnapshot/pixmaps/");

my $menu;

my $localfile = "$ENV{HOME}/.draksnapshot";

my $timeout = ($::testing ? 1 : 30) * 1000;

my %state = (
   
	     okay => {
		      menu => [],
 		      do_not_use_bubble => 1,
		     },
	     disk_found => {
		      menu => [ 'configure' ],
		      tt => [ N_("USB discs are available for backups") ]
		     },
	     config_in_progress => {
		      menu => [],
 		      do_not_use_bubble => 1,
		      tt => [ N_("Configurator is currently running") ]
		     },
	    );


my %actions = (
    'configure' => { name => N("Configure"), launch => \&configure }
);


# create status icon:
my $icon = Gtk3::StatusIcon->new;
$icon->signal_connect(popup_menu => sub {
                          my ($_icon, $button, $time) = @_;
                          $menu and $menu->popup(undef, undef, undef, undef, $button, $time);
                      });
$icon->signal_connect(activate => \&configure);
$icon->set_from_pixbuf(gtkcreate_pixbuf('draksnapshot'));



my $dbus = get_system_bus();
my $dbus_error = $@;



# initializing DBus/HAL:
my ($do, $con);
$do = eval { dbus_object->new($dbus, $hal_dn, $manager_path, $hal_manager) };
if ($dbus && $do) {
    
    $con = eval { $dbus->{connection} };
    my $old_time;
    $con->add_filter(sub {
                         my ($_bus, $msg) = @_; # perl_checker: Net::DBus::Binding::Message::Signal

                         # hide if needed (evals really are needed):
                         if (eval { 'DeviceRemoved' eq $msg->get_member }) {
                             firstCheck();
                             return 0;
                         }

                         return 0 if $msg->get_member ne 'DeviceAdded';
                         my $hal = $dbus->get_service($hal_dn);
                         my $bool;
                         eval {
                             my $device = $hal->get_object(($msg->get_args_list)[0], "$hal_dn.Device");
                             $bool = is_proper_device($device);
                         };
                         if ($bool) {
                             my $time = time();
                             go2State('disk_found') if 5 < abs($time - $old_time);
                         $old_time = $time;
                         }
                         0;
                     });
    $con->add_match("type='signal',interface='$hal_manager'");
} else {
    Glib::Timeout->add(
        $timeout,
        sub {
            $icon->set_visible(1);
            # make icon actually visible so that notification gots proper positionning:
            gtkflush();
            my $bubble = 
              Gtk3::Notify::Notification->new(N("Error. Service disabled."),
                                                 join("\n",
                                                      formatAlaTeX(N("Error while initializing DBus:")),
                                                      $dbus_error,
                                                      '',
                                                      N("Disabling the service."),
                                                  ),
                                                 '/usr/share/icons/draksnapshot.png');
            $bubble->set_urgency('critical');
            my $timeout_bubble = 5000;
            $bubble->set_timeout($timeout_bubble);
            eval { $bubble->show };
            Glib::Timeout->add($timeout_bubble + 100, sub { Gtk3::exit; exit(1) });
            0;
        });
    Gtk3->main;
    exit(1);
}


my ($opt) = @ARGV;
if ($opt eq '--force' || $opt eq '-f') { setAutoStart('TRUE') }

shouldStart() or die "$localfile should be set to TRUE: please use --force or -f option to launch applet\n";

go2State('okay');
gtkflush();
Glib::Timeout->add($timeout, sub { firstCheck(); 0 });


$SIG{USR1} = 'IGNORE';
$SIG{USR2} = 'IGNORE';
$SIG{CHLD} = \&harvester;

run_program::raw({ detach => 1 }, 'ionice', '-p', $$, '-n7');

$do and $do->set_gtk3_watch;
Gtk3->main;

ugtk3::exit(0);

my $config_pid;

# Signal management 
sub harvester {
    my ($_signame, $_clean) = @_;
    my ($childpid, @pids);
    do {
        $childpid = waitpid(-1, &WNOHANG);
        if ($config_pid && $config_pid == $childpid) {
            undef $config_pid;
            # we should better check it has really been configured indeed.
        }
        push @pids, $childpid;
        WIFEXITED($?) and refresh_gui(1);
    } while $childpid > 0;
    return @pids;
}

sub fork_exec {
    my $pid = run_program::raw({ detach => 1 }, @_);
    refresh_gui(1);                                                                        
    return $pid;
}

sub refresh_gui {
    my ($sens) = @_;
    #!$conf_launched and silentCheck(); $conf_launched = 0;
    my $w = $::main_window ? $::main_window->window : undef;
    $sens ? gtkset_mousecursor_normal($w) : gtkset_mousecursor_wait($w);
    gtkflush();
}

sub configure() {
    $config_pid = fork_exec('/usr/bin/draksnapshot-config');
    go2State('config_in_progress');
}

sub firstCheck() {
    # evals really are needed:
    my @discs = eval { find_removable_volumes($dbus) };

    go2State(@discs ? 'disk_found' : 'okay');
}

sub go2State {
    my $state = shift;
    $menu->destroy if $menu;
    $menu = setState($state);
}


sub shouldStart() {
    my %p = getVarsFromSh($localfile);
    to_bool($p{AUTOSTART} ne 'FALSE');
}

sub setState {
    my ($state_type) = @_;
    my $checkme;
    my $arr = $state{$state_type}{menu};
    $icon->set_tooltip_text(formatAlaTeX(translate($state{$state_type}{tt}[0])));
    $icon->set_visible($state_type ne 'okay');

    gtkflush(); # so that bubbles are displayed on right icon
    select(undef, undef, undef, 0.1);  #- hackish :-(

    if ($state{$state_type}{tt}[0] && $icon->isa('Gtk3::StatusIcon') && !$state{$state_type}{do_not_use_bubble}) {
        my $bubble = Gtk3::Notify::Notification->new(N("Info"), formatAlaTeX(translate($state{$state_type}{tt}[0])) . "\n",
                                                        '/usr/share/icons/draksnapshot.png');
        $bubble->set_timeout(5000);
        eval { $bubble->show };
    }

    my $menu = Gtk3::Menu->new;
    foreach (@$arr) { 
	$menu->append(gtksignal_connect(gtkshow(Gtk3::MenuItem->new_with_label($actions{$_}{name})), activate => $actions{$_}{launch}));
    }
    $menu->append(gtkshow(Gtk3::SeparatorMenuItem->new));
    $menu->append(
        gtksignal_connect(
            gtkshow(Gtk3::MenuItem->new_with_label(N("About..."))),
            activate => sub {
                my $ver = '0.20.3-18.mga7'; # automatically set from spec file
                my $w = gtknew('AboutDialog', name => N("DrakSnapshot %s", $ver),
                               copyright => N("Copyright (C) %s by Mandriva", '2008'),
                               license => join('', cat_('/usr/share/common-licenses/GPL')),
                               icon => '/usr/share/icons/mini/draksnapshot.png',
                               comments => N("DrakSnapshot enables to backup your machine through periodic snapshots."),
                               website => 'http://www.mandriva.com',
                               website_label => N("Mandriva WebSite"),
                               authors => 'Thierry Vignaud <vignaud@mandriva.com>',
                               translator_credits =>
                                 #-PO: put here name(s) and email(s) of translator(s) (eg: "John Smith <jsmith@nowhere.com>")
                                 N("_: Translator(s) name(s) & email(s)\n"),
                               transient_for => $::main_window, modal => 1, position_policy => 'center-on-parent',
                           );

                $w->show_all;
                $w->run;
                return 1;

            }));
    $menu->append(gtksignal_connect(gtkset_active($checkme = Gtk3::CheckMenuItem->new_with_label(N("Always launch on startup")), shouldStart()), toggled => sub { setAutoStart(uc(bool2text($checkme->get_active))) }));
    $checkme->show;
    $menu->append(gtksignal_connect(gtkshow(Gtk3::MenuItem->new_with_label(N("Quit"))), activate => sub { mainQuit() }));
    $menu;

}
sub logIt {
    my $log = shift;
    log::explanations($log);
}

sub setVar {
    my ($file, $var, $st) = @_;
    my %s = getVarsFromSh($file);
    $s{$var} = $st;
    setVarsInSh($file, \%s);
}

sub setAutoStart {
    my ($state) = @_;
    if (-f $localfile) {
	setVar($localfile, 'AUTOSTART', $state);
    } else { 
        output_p($localfile, "AUTOSTART=$state\n");
    }
}

sub mainQuit() {
    Gtk3->main_quit;
}
