#!/usr/bin/perl

# Drakwizard

# Copyright (C) 2002 MandrakeSoft Mael Dodin (mdodin@mandrakesoft.com)
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# 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 lib qw(/usr/lib/libDrakX);
use strict;
use vars qw($Wizard_title $Wizard_pix_up $lib_script $perl_module %variable $in $rpm %chooser_hash $welcome $perl_module_name $verbose %description $summary $summary_func %disabled $current_page %bool);

use XML::Parser;
use standalone;
use interactive;
use common;

#- I18N.
push @::textdomains, 'drakwizard';

$::isWizard = 1;
my $in = 'interactive'->vnew('su', 'default');
$::direct = /-direct/;
$::Wizard_no_previous = 1;
$::Wizard_title = "Drakwizard";
my $standalone = 1;

# ! -r '/etc/sysconfig/network-scripts/drakconnect_conf' &&
#   ( -r '/etc/sysconfig/network-scripts/draknet_conf' || 
#     die "no drakconnect conf file found, install drakconnect and try again") &&
#   MDK::Common::cp_af('/etc/sysconfig/network-scripts/draknet_conf',
# 		     '/etc/sysconfig/network-scripts/drakconnect_conf');

if (!defined($ARGV[0])) {
    my $prefix = "/usr/share/wizards/";
    my %wiz = (
	       1 => [$prefix."web_wizard/web.wiz", "Apache"],
	       2 => [$prefix."dhcp_wizard/dhcp.wiz", "Dhcp"],
	       3 => [$prefix."dns_wizard/dns.wiz", "Dns (configuration)"],
	       4 => [$prefix."client_wizard/client.wiz", "Dns (add client)"],
	       5 => [$prefix."news_wizard/news.wiz", "News"],
	       6 => [$prefix."nfs_wizard/nfs.wiz", "NFS"],
	       7 => [$prefix."postfix_wizard/postfix.wiz", "Postfix"],
	       8 => [$prefix."ftp_wizard/ftp.wiz", "Proftpd"],
	       9 => [$prefix."samba_wizard/samba.wiz", "Samba"],
	       10 => [$prefix."proxy_wizard/proxy.wiz", "Squid"],
	       11 => [$prefix."time_wizard/time.wiz", "Time"],
	       12 => [$prefix."web_wizard/apache2.wiz", "Apache2"]
	      );
    $in->ask_from(
		  N("Drakwizard wizard selection"),
		  N("Please select a wizard"),
		  [{ val => \$ARGV[0], list => [sort { $wiz{$a}[2] cmp $wiz{$b}[2] } keys %wiz], format => sub { $wiz{$_[0]}[1] }}]
		 );
    $ARGV[0] = $wiz{$ARGV[0]}[0];
}

my $o = [];
my $o2 = [];
my $xmltree = XML::Parser->new(Style => 'Tree')->parsefile($ARGV[0]);

local $_ = join '', @ARGV;
  if (/-debug/) {
    $::verbose = 1;
}

$::isWizard = 1;

if (/-summary/) {
    $::isSummary = 1;
    get_parameter($o2, $xmltree);
    $::Wizard_finished = 1;
    get_summary($o2, $xmltree);
    is_disabled_summary($_[0], $o2->[0]);
    my $data = map_freetext($summary->{freetext});
    # workaround to get get the scrollbar
    while ($::isSummary--) {
	push @$data, '';
    }

    if ($in->ask_from(translate("summary"), translate($summary->{info}), $data)) {
	foreach (@{$summary->{freetext}}) {
	    if ($_->{main_order} eq 'bool') {
		$ENV{$variable{$_->{variableName}}} = $ENV{$variable{$_->{variableName}}} ? 1 : 0;
		$description{$ENV{$variable{$_->{variableName}}}} = $ENV{$variable{$_->{variableName}}} ? N("enabled") : N("disabled");
	    }
	    elsif ($_->{main_order} eq 'combo') {
		$ENV{$variable{$_->{variableName}}} = $chooser_hash{$ENV{$variable{$_->{variableName}}}};
	    }
	}
	$::{$perl_module_name."::"}{"$summary_func"}->();
    }
}
else {
    get_parameter($o, $xmltree);
    if (!$::verbose) {
	no warnings;
	navigation($o, $o->[0]);
    }
    else { navigation($o, $o->[0]) };
}

$in->exit;

sub member { my $e = shift; foreach (@_) { $e eq $_ and return 1 } 0 }

sub xml_text {
    $_[0] =~ s/\\\'/\'/g;
    $_[0] =~ s/\\q/\"/g;
    $_[0] =~ s/\\a/\&/g;
    $_[0] =~ s/\\n/\n/g;
    $_[0];
}

sub load_wizard {
    ($Wizard_title, $lib_script, $perl_module, $rpm, $Wizard_pix_up, $summary_func) = @_;
    if ($rpm) {
	if (!$in->do_pkgs->is_installed($rpm)) {
	    if ($in->ask_okcancel("error", N("%s is not installed\nClick \"Next\" to install or \"Cancel\" to quit", c::from_utf8($rpm)))) {
		if (!$in->do_pkgs->install($rpm eq 'bind' ? 'bind-9' : $rpm)) {
		    $::Wizard_finished = 1;
		    $in->ask_okcancel("error", N("installation failed"));
		    $in->exit;
		}
	    }
	    else { $in->exit }
	}
    }
    if ($perl_module) {
	($::perl_module_name) = ($perl_module =~ /.*\/(.*)\.pm/);
	require $perl_module;
    }
}

sub	map_freetext {
    my	@liste;
    my	$valeur;

    my @data = map {
	my $str = $_->{variableName};
	my $page = $_;

	if ($_->{fillScript}) {
	    $ENV{$variable{$_->{variableName}}} = `. $lib_script && $_->{fillScript}`;
	}
	if ($_->{main_order} eq 'entry') { 
	    if (!$ENV{$variable{$_->{variableName}}} && $_->{fillfunc}) {
		$ENV{$variable{$_->{variableName}}} = $::{$perl_module_name."::"}{"$_->{fillfunc}"}->();
	    }
	    { label => N($_->{helpText}),
		val => \$ENV{$variable{$_->{variableName}}}, type => $_->{main_order},
		  disabled => $disabled{$_->{variableName}},
		    help => $_->{help}}
	}
	elsif ($_->{main_order} eq 'field' && $_->{fillfunc}) {
	    { label => N($_->{helpText}),
		val => $::{$perl_module_name."::"}{"$_->{fillfunc}"}->(), type => $_->{main_order},
		  disabled => $disabled{$_->{variableName}},
		    help => $_->{help}}
	}
	elsif ($_->{main_order} eq 'bool') {
	    if (!$ENV{$variable{$_->{variableName}}} && $_->{fillfunc}) {
		$ENV{$variable{$_->{variableName}}} = $::{$perl_module_name."::"}{"$_->{fillfunc}"}->();
	    }
	    if ($_->{listfunc}) {
		my @checklist = $::{$perl_module_name."::"}{"$_->{listfunc}"}->();
		my $i = 21 - scalar @checklist;
		# workaround to get get the scrollbar
 		if (!$::isSummary) {
 		    while ($i--) {
 			push @checklist, '';
 		    }
 		}
 		else {
 		    while ($i--) {
 			$::isSummary++;
 		    }
 		}
		#
		map {
		    if (length($_)) {
			$disabled{$str} = sub { callback($str)};
			{ val => \$bool{$_},
			    label => "",
			      type => 'bool',
				text => "$_",
				  help => "",
				    disabled => $disabled{$str}
				}
		    }
		} @checklist;
	    }
	    else {
		{ val => \$ENV{$variable{$_->{variableName}}},
		    label => "",
		      type => $_->{main_order},
			text => translate($_->{helpText}),
			  disabled => $disabled{$_->{variableName}},
			    help => $_->{help} }
	    }
	}
	elsif ($_->{main_order} eq 'combo') {
	    if($_->{fillScript}){
		@liste = ();
		$valeur = `. $lib_script && $_->{fillScript}`;
		while( $valeur =~ /(.+)\n/g){
		    push @liste, $1;
		    $chooser_hash{$1} = $1;
		}
	    }
	    elsif ($_->{fillfunc}){
		@liste = $::{$perl_module_name."::"}{"$_->{fillfunc}"}->();
	    }
	    else {
		@liste = @{$_->{Option}};
	    }
	    { label => N($_->{helpText}),
		val => \$ENV{$variable{$_->{variableName}}},
		  list => [@liste], type => $_->{main_order},
		    disabled => $disabled{$_->{variableName}} }}
	elsif ($_->{main_order} eq 'field') {
	    { val => $description{$ENV{$variable{$_->{variableName}}}} ?
		$description{$ENV{$variable{$_->{variableName}}}} :
		  $ENV{$variable{$_->{variableName}}},
		    label => $_->{helpText},
		      help => $_->{help}} }
    } @{$_[0]};
    \@data;
}

sub get_parameter {
    my ($o, $tree, $tag ,$page) = @_;

    foreach my $leaf (@$tree) {
	if (ref($leaf) eq 'ARRAY') {
	    $page = get_parameter($o, $leaf, $tag, $page);
	} elsif (ref($leaf) eq 'HASH') {
	    my $common_freetext_chooser;
	    my %actions = (
			   Wizard => sub {
			       load_wizard(@{$leaf}{qw(wizardTitle libScript perlModule rpm defaultImage)}) },
			   Variable => sub {
			       $variable{$leaf->{name}} = $leaf->{shellVariable};
			       $ENV{$variable{$leaf->{name}}} = $leaf->{defaultValue};
			       $disabled{$leaf->{name}} = sub { callback($leaf->{name})};
			   },
			   Page => sub {
			       !$welcome and $welcome = $page;
			       my $old_page = $page;
			       push @$o, $page = { %$leaf };
			       $old_page->{next_page} = $page;
			       if ($leaf->{canBack} =~ /.*false.*/) { $page->{no_prev} = 1}
			       if ($leaf->{canCancel} =~ /.*false.*/) { $page->{no_cancel} = 1}
			       if ($leaf->{nextFinish} =~ /.*true.*/) { $page->{finish} = 1}
			   },
			   Target => sub {
			       $page->{Target}->{jumpIndex}->{$leaf->{jumpIndex}} = $leaf->{targetName};
			   },
			   Info => sub {
			       # This is to avoid monospaced text to be interpolated
			       $leaf->{helpText} = translate($leaf->{helpText});
			       if ($leaf->{fontName} eq "Monospaced") {
			       	   chomp($leaf->{helpText});
				   $leaf->{helpText} = $leaf->{helpText} ?
				     "$leaf->{helpText}\n$leaf->{helpText}" : "$leaf->{helpText}\n";
			       }
			       $page->{info} = xml_text($leaf->{helpText} ? 
							"$page->{info}\n$leaf->{helpText}" : "$page->{info}\n");
							#$page->{info} = c::from_utf8($page->{info});
			       $page->{info} .= translate(`source $lib_script; $leaf->{fillScript}`) if
				 ($leaf->{fillScript})
			   },
			   Freetext => $common_freetext_chooser = sub {
			       my $main_order = ($tag eq 'Chooser') ? 'combo'
				 : ($tag eq 'Boolean') ? 'bool' 
				   : ($leaf->{editable} eq 'true') ? 'entry'
				     : 'field';
			       push @{$page->{freetext}},
				 {%$leaf, main_order => $main_order,
				  help => xml_text($leaf->{help})} if $main_order ne 'hidden';
			   },
			   Chooser => \&$common_freetext_chooser,
			   Boolean => \&$common_freetext_chooser,
			   Option => sub {
			       push @{${$page->{freetext}}[-1]->{Option}}, $leaf->{description};
			       $chooser_hash{$leaf->{description}} = $leaf->{value};
			       $description{$leaf->{value}} = $leaf->{description};
			       $disabled{$leaf->{description}} = sub { callback($leaf->{description})};
			   });
	    $actions{$tag} and &{$actions{$tag}};
	}
	elsif($leaf=~ /\w\D/) {
	    $tag = $leaf;
	}
    }
    $page;
}

sub find_page {
    my ($o, $name) = @_;
    $_->{name} eq $name and return $_ foreach @$o;
}

sub display {
    my ($o, $page) = @_;
    my $data;

    if ($page->{no_prev} || $page->{name} eq $welcome->{name}) {
	$::Wizard_no_previous = 1;
    }
    if ($page->{finish}) {
	$::Wizard_finished = 1;
	$::Wizard_no_cancel = 1;
    }
    if ($page->{nextFinish} eq 'true') {
        $::Wizard_no_previous = 1;
        $in->ask_okcancel(translate($page->{name}),
                          translate($page->{info})); # or quit_global($in, 0);
	exit;
    }
    elsif (!$page->{freetext}) {
	$in->ask_okcancel(translate($page->{name}),
			  translate($page->{info})) or navigation($o, $page->{old_page});
    }
    else {
	my $valeur;
	my @liste;
	if ($page->{executionLevel} eq 'NORMAL') {
	    $data = map_freetext($page->{freetext});
	    $in->ask_from($page->{name}, translate($page->{info}),
			  $data) or navigation($o, $page->{old_page});
	    foreach (@{$page->{freetext}}) {
		if ($_->{main_order} eq 'bool') {
		    $ENV{$variable{$_->{variableName}}} = $ENV{$variable{$_->{variableName}}} ? 1 : 0;
		    $description{$ENV{$variable{$_->{variableName}}}} = $ENV{$variable{$_->{variableName}}} ? N("enabled") : N("disabled");
		}
		elsif ($_->{main_order} eq 'combo') {
		    $ENV{$variable{$_->{variableName}}} = $chooser_hash{$ENV{$variable{$_->{variableName}}}};
		}
	    }
	}
    }
    undef $::Wizard_no_previous;
}

sub navigation {
    my ($o, $page, $previous_page) = @_;
    $page->{old_page} ||= $previous_page;

    $current_page = $page;
    display($o, $page);
    my ($next, $prev) = do {
	if (defined $perl_module_name && $page->{func}) {
	    my @func_arg = split(/\s/, $page->{func});
	    my $modStatus = $::{$perl_module_name."::"}{"$func_arg[0]"}->();
	    if ($page->{Target}->{jumpIndex}) {
		find_page($o, $page->{Target}->{jumpIndex}->{int($modStatus)}), $page;
	    }
	    else {
		$page->{next_page}, $page->{old_page};
	    }
	}
	elsif ($page->{jumpScript}) {
	    system("source $lib_script ; $page->{jumpScript}");
	    if ($page->{Target}->{jumpIndex}) {
		$? = $? >> 8;
		find_page($o, $page->{Target}->{jumpIndex}->{$?}), $page;
	    }
	    else {
		$page->{next_page}, $page;
	    }
	}
	elsif ($page->{subWizard}) {
	    my $sub_o = [];
	    my $sub_xmltree = XML::Parser->new(Style => 'Tree')->parsefile($page->{subWizard});
	    get_parameter($sub_o, $sub_xmltree);
	    eval {navigation($sub_o, $sub_o->[0]); };
	    $in->exit if $@ =~ /^wizcancel/;
	    $page->{old_page}->{no_prev} = 1;
	    $o->[0], $page, undef;
	}
	elsif ($page->{jumpPage}) {
	    find_page($o, $page->{jumpPage}), $page;
	}
	else {
	    $page->{next_page}, $page;
	}
    };
    navigation($o, $next, $prev);
}

sub	is_disabled_summary {
    my ($widget, $page) = @_;

    if ($page->{is}) {
	my ($page_val, $page_arg) = split(/\s*?=\s*/, $page->{is});
	if ($page_val eq $widget) {
	    foreach (@{$page->{freetext}}) {
		my ($val, $arg) = split(/\s*?=\s*/, $_->{is}) if ($_->{is});
		$disabled{$_->{variableName}} = defined $page_arg ? ($ENV{$variable{$page_val}} != $page_arg) : !$ENV{$variable{$page_val}};
		if ($_->{is} && !$disabled{$_->{variableName}}) {
		    $disabled{$_->{variableName}} = defined $arg ? $ENV{$variable{$val}} != $arg : !$ENV{$variable{$val}};
		}
	    }
	}
    }
    is_disabled_summary($widget, $page->{next_page}) if $page->{next_page};
}

# find in the page which widget to disable from "is" dependance key.
sub	is_disabled {
    my	($widget, $page) = @_;
    my	$ret;

    foreach (@{$page->{freetext}}) {
	if ($_->{is}) {
	    my ($val, $arg) = split(/\s*?=\s*/, $_->{is});
	    $ret = defined $arg ? $ENV{$variable{$val}} != $arg : !$ENV{$variable{$val}};
	}
	$disabled{$_->{variableName}} = $ret;
    }
}

sub	callback_common {
    return 1 if ($disabled{$_[0]} == 1);
    foreach (keys %variable) {
   	my $str = $ENV{$variable{$_}};
   	my $str2 = $_;
   	foreach (keys %chooser_hash) {
   	    if ($str eq $_) {
   		$ENV{$variable{$str2}} = $chooser_hash{$_};
   	    }
   	}
    }
    0;
}

sub	callback_summary {
    return 1 if callback_common($_[0]);
    is_disabled_summary($_[0], $o2->[0]);
}

sub	callback {
    return 1 if callback_common($_[0]);
    is_disabled($_[0], $current_page);
}

sub	get_summary {
    my	($o, $tree, $tag, $page) = @_;

    foreach my $leaf (@$tree) {
	if (ref($leaf) eq 'ARRAY') {
	    $page = get_summary($o, $leaf, $tag, $page);
	} elsif (ref($leaf) eq 'HASH') {
	    my $common_freetext_chooser;
	    my %actions = (
			   Wizard => sub {
			       load_wizard(@{$leaf}{
				   qw(wizardTitle libScript perlModule rpm defaultImage summaryFunc)}) },
			   Variable => sub {
			       $variable{$leaf->{name}} = $leaf->{shellVariable};
			       $ENV{$variable{$leaf->{name}}} = $leaf->{defaultValue};
			       $disabled{$leaf->{name}} = sub { callback_summary($leaf->{name})};
			   },
			   Freetext => $common_freetext_chooser = sub {
			       my $main_order = ($tag eq 'Chooser') ? 'combo' 
				 : ($tag eq 'Boolean') ? 'bool' 
				   : ($leaf->{editable} eq 'true') ? 'entry'
				     : 'hidden';
			       push @{$summary->{freetext}},
				 {%$leaf, main_order => $main_order,
				  help => xml_text($leaf->{help})} if $main_order ne 'hidden';
                           },
                           Chooser => \&$common_freetext_chooser,
                           Boolean => \&$common_freetext_chooser,
			   Option => sub {
			       push @{${$summary->{freetext}}[-1]->{Option}}, $leaf->{description};
			       $chooser_hash{$leaf->{description}} = $leaf->{value};
			       $description{$leaf->{value}} = $leaf->{description};
			       $disabled{$leaf->{description}} = sub {callback_summary($leaf->{description})};
			   });
	    $actions{$tag} and &{$actions{$tag}};
	} elsif ($leaf=~ /\w\D/){
	    $tag = $leaf;
	}
    }
    $page;
}
