package MDV::Snapshot::Restore;

################################################################################
# Backup Configuration Tool                                                    # 
#                                                                              #
# 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 lib qw(/usr/lib/libDrakX);
use c;
use locale;
use MDV::Snapshot::Common;
use common;
use interactive;
use POSIX;
use run_program;
use fsedit;
use fs::type;
use fs;
use any;

sub get_fstab() {
    my $all_hds = fsedit::get_hds();
    fs::get_raw_hds('', $all_hds);
    fs::get_info_from_fstab($all_hds);
    [ fs::get::fstab($all_hds) ]; # $fstab
}

sub get_handle {
    my ($part, $o_rw) = @_;
    my $mntpnt = $part->{mntpoint};
    
    # do not bother failed to mount with ro b/c already mounted:
    $mntpnt ? { dir => $mntpnt } : any::inspect($part, $::prefix, $o_rw);
}


sub find_disks_with_rsnapshot {
    my ($fstab) = @_;

    my @true_fs = 
      grep { isTrueLocalFS($_) && 
	     !member($_->{mntpoint},
                     '/home', grep { $_ ne '/' } fs::type::directories_needed_to_boot());
	 } @$fstab;

    log::l("looking for rsnapshot.conf on partitions " . join(' ', map { $_->{device} } @true_fs));

    my @found;
    foreach my $part (@true_fs) {
        my $handle = get_handle($part);
        next if !$handle;
        next if ! -e "$handle->{dir}/etc/rsnapshot.conf";

	if (my $f = common::release_file($handle->{dir})) {
	    my $h = common::parse_release_file($handle->{dir}, $f, $part);
	    $h->{name} = $h->{release};
	    push @found, $h;
	}
    }

    return @found;
}

sub get_snapshots() {
    my %backups = 
      map {
          my $backup = $_;
          my ($type, $_number) = m!$backup_directory/([^/]*)\.([0-9]*)!;
          my $raw_date = [ stat($backup) ]->[-4];
          my $date = POSIX::strftime($type eq 'hourly' ? "%c" : "%x", localtime($raw_date));
          c::set_tagged_utf8($date);
          $backup => { raw_date => $raw_date, date => $date, backup => $backup, type => $type };
      } glob_("$backup_directory/*");
    %backups;
}

sub configure {
    my ($in) = @_;
    my $backup;
    my %backups = get_snapshots();

    if (!%backups) {
        $in->ask_warn(N("Error"), N("No backup found!"));
        return;
    }

    my %i18n = (
        'hourly'  => N("Hourly"),
        'daily'   => N("Daily"),
        'weekly'  => N("Weekly"),
        'monthly' => N("Monthly"),
    );

    $in->ask_from_(
        { 
            title => N("Backup snapshots configuration"),
        },
        [
            { title => 1, label => N("Backup snapshots configuration") },
            { label => N("Please select the backup you want to restore.") },
            { val => \$backup, sort => 0, allow_empty_list => 1,
              format => sub { 
                  #-PO: eg: "Daily snapshot done on Sun Feb 4
                  N("%s snapshot done on %s", $i18n{$backups{$_[0]}{type}}, $backups{$_[0]}{date});
              },
              list => [ sort { $backups{$a}{raw_date} cmp $backups{$b}{raw_date} } keys %backups ],
          },
        ]) or return;

    my $_wait = $in->wait_message(N("Please wait"), N("Restoring backup in progress"));
    my $backup_dir = $backups{$backup}{backup};
    # FIXME: add a progress bar
    foreach (glob_("$backup_dir/localhost/*")) {
        my $dir = $_;
        s!^$backup_dir/localhost!!;
        log::l("would run system('rsync', '-vrlpt', $dir, $::prefix$_)\n") if $::testing;
        # FIXME: should we use --delete?
        run_program::run('rsync', '-vrlpt', $dir, "$::prefix$_") if !$::testing;
    }
    undef $_wait;
    $in->ask_from_no_check(
	{
	 title => N("Congratulations"),
	 messages => N("Congratulations, restoration is complete."),
	 ok => $::isStandalone || $::local_install ? N("Quit") : N("Reboot"),
	}, []);
}


sub mount_all {
    my ($in, $fstab) = @_;
    local $::testing = 0;

    my @errs;
    foreach my $part (sort { $a->{mntpoint} cmp $b->{mntpoint} }
        grep { $_->{mntpoint} && $_->{mntpoint} ne '/' && maybeFormatted($_) && $_->{device} ne 'none'
                 && !member($_->{fs_type}, 'swap', 'nfs', if_($::isInstall, 'ntfs'));
           }
        @$fstab) {

        eval { fs::mount::part($part) };
        push @errs, $@ if $@;
    }
    $in->ask_warn(N("Warning"), N("mount failed: ") . join("\n", '', @errs)) if @errs;
}

sub main {
    my ($in) = @_;

    my ($system, $fstab, @found);
  refresh:
    $fstab = get_fstab();
    @found = find_disks_with_rsnapshot($fstab);

    $in->ask_from_({ interactive_help_id => 'configureX_chooser',
		     title => N("Restoring Backup"), 
                     messages => join("\n",
                                      N("Please select the partition of the system to restore."),
                                      N("Do not forget to plug the USB disk that contains your backups."),
                                  )
                 },
		   [
                       { label => N("System to restore"),  },
                       {
                           val => \$system, list => \@found, allow_empty_list => 1,
                           format => sub { 
                               my $dev = $_[0];
                               N("\"%s\" (on %s)", $dev->{name}, $dev->{part}{device});
                           },
                       },
                       {
                           val => N("Refresh"), clicked => sub { goto refresh },
                       },
                   ]);

    my $handle = get_handle($system->{part}, 1);
    local $::prefix = $handle->{dir};

    # reinit paths according to temp mount point:
    MDV::Snapshot::Common::init();

    my $ch_fstab;
    if (ref($handle) =~ /before_leaving/) {
        $ch_fstab = [ fs::read_fstab($::prefix, '/etc/fstab') ];
        mount_all($in, $ch_fstab);
    }

    configure($in);

    # make sure everything is umounted:
    if (ref($handle) =~ /before_leaving/) {

        # reread for {real_mountpoint}:
        $ch_fstab = [ fs::read_fstab($::prefix, '/etc/fstab') ];

        eval { fs::mount::umount_all($ch_fstab) };
    }
}

1;
