package network::pxe;

use common;
use network::tools;
use Xconfig::resolution_and_depth;

our $tftp_root = "/var/lib/tftpboot";
my $client_path = '/X86PC/linux';
our $pxelinux_client_root = $tftp_root . $client_path;
our $pxelinux_images = $pxelinux_client_root . '/images';
our $pxelinux_help_file = $pxelinux_client_root . '/help.txt';
our $pxelinux_message_file = $pxelinux_client_root . '/messages';
our $pxelinux_config_file = $pxelinux_client_root . '/pxelinux.cfg/default';
our $pxe_config_file = '/etc/pxe.conf';

my @global_pxelinux_settings = qw(PROMPT DEFAULT DISPLAY TIMEOUT F1);
my @append_settings = qw(initrd ramdisk_size vga display);
my @automatic_settings = qw(method interface network server directory);

our %vga_bios_to_resolution = (
		    'normal' => "vga",
		    'text' => "text",
		    '' => "automatic",
		     map { $_->{bios} => "$_->{X}x$_->{Y}" } grep { $_->{Depth} == 16 } Xconfig::resolution_and_depth::bios_vga_modes()
		       );
our %vga_resolution_to_bios = reverse %vga_bios_to_resolution;

sub read_pxelinux_help() {
    my %info;
    foreach (cat_($pxelinux_help_file)) {
	/^(\w+)\s*:\s*(.*)$/ and $info{$1} = $2;
    }
    \%info;
}

sub read_pxelinux_conf() {
    my (%conf);
    my $info = read_pxelinux_help();
    my $entry = {};
    foreach (cat_($pxelinux_config_file)) {
	my $global = join('|', @global_pxelinux_settings);
	if (/^($global)\s+(.*)/) {
	    $conf{lc($1)} = $2;
	} elsif (/^label\s+(.*)/) {
	    $entry->{label} = $1;
	} elsif (/^\s+LOCALBOOT\s+(\d+)/) {
	    $entry->{localboot} = $1;
	} elsif (/^\s+KERNEL\s+(.*)/) {
	    $entry->{kernel} = $1;
	} elsif (/^\s+APPEND\s+(.*)/) {
	    my @others;
	    foreach (split /\s+/, $1) {
		my ($option, $value) = /^(.+?)(?:=(.*))?$/;
		if (member($option, @append_settings)) {
		    $entry->{$option} = $value;
		} elsif ($option eq 'automatic') {
		    foreach (split /,/, $value) {
			my ($option, $value) = /^(.+?):(.+)$/;
			$entry->{$option} = $value;
		    }
		} else {
		    push @others, $_;
		}
	    }
	    $entry->{others} = join(' ', @others);
	}
	if (exists $entry->{label} && (exists $entry->{localboot} || exists $entry->{kernel} && exists $entry->{initrd})) {
	    $entry->{info} = $info->{$entry->{label}};
	    exists $entry->{vga} and $entry->{vga} = $vga_bios_to_resolution{$entry->{vga}};
	    push @{$conf{entries}}, $entry;
	    $entry = {};
	}
    }
    \%conf;
}


sub list_pxelinux_labels {
    my ($conf) = @_;
    map { $_->{label} } @{$conf->{entries}};
}

sub write_pxelinux_conf {
    my ($conf) = @_;

    output($pxelinux_config_file,
	   join("\n",
		"# DO NOT EDIT auto_generated by drakpxelinux.pl",
		(map { $_ . ' ' . $conf->{lc($_)} } @global_pxelinux_settings),
		'',
		(map {
		    my $e = $_;
		    my $automatic = join(',', map { "$_:$e->{$_}" } grep { $e->{$_} } @automatic_settings);
		    ("label $e->{label}",
		     exists $e->{localboot} ?
		     "    LOCALBOOT $e->{localboot}" :
		     ("    KERNEL $e->{kernel}",
		      "    APPEND " . join(' ',
					   (map { "$_=$e->{$_}" } grep { $e->{$_} } @append_settings),
					   if_($automatic, "automatic=$automatic"),
					   $e->{others})),
		     '');
		 } @{$conf->{entries}})));
}

sub write_default_pxe_messages {
  my ($net) = @_;
  my $hostname = $net->{hostname} || chomp_(`hostname`);
  output($pxelinux_message_file, <<EOF);

                   Welcome to Mandrakelinux PXE Server
                                                       Pxelinux
              .              .-----------------------------------.
             /|\\            /    Press F1 for available images    \\
            /_|_\\           \\    Hosted by  $hostname
            \\ | /   _       /'-----------------------------------'
             \\|/   (')     /
              '.    U     /                                (O__
                 .   '.  /                 (o_  (o_  (0_   //\\
                 {o_   (o_  (o_  (o_  (o_  //\\  //\\  //\\  //  )
                 (')_  (`)_ (/)_ (/)_ (/)_ V_/_ V_/_ V_/_ V__/_
            ---------------------------------------------------------

 press F1 for help
EOF
}

sub write_default_pxe_help() {
  output($pxelinux_help_file, <<EOF);
Available images are:
---------------------
local: local boot
EOF
}

sub add_in_help {
  my ($NAME, $INFO) = @_;
  if (!any { /$NAME/ } cat_($pxelinux_help_file)) {
    append_to_file($pxelinux_help_file, <<EOF);
$NAME : $INFO
EOF

  } else {
    substInFile {
      s/$NAME.*/$NAME : $INFO/;
    } $pxelinux_help_file;
  }
}

sub change_label_in_help {
  my ($NAMEOLD, $NEWNAME) = @_;
  substInFile {
    s/$NAMEOLD\s(.*)/$NEWNAME $1/;
  } $pxelinux_help_file;
}

# remove entry in help.txt
sub remove_in_help {
  my ($NAME) = @_;
  substInFile {
    s/^$NAME\s:.*//x;
    s/^\s*$//;
  } $pxelinux_help_file;
}

# adjust pxe confi with good value
sub write_pxe_conf {
  my ($net, $interface) = @_;
  if (!-f "$pxe_config_file.orig") { cp_af($pxe_config_file, "$pxe_config_file.orig") }
  my $domainname = $net->{resolv}{domainname} || chomp_(`dnsdomainname`);
  my $ip_address = network::tools::get_interface_ip_address($net, $interface);

  substInFile {
    s/default_address.*/default_address=$ip_address/;
    s/mtftp_address.*/mtftp_address=$ip_address/;
    s/domain.*/domain=$domainname/;
  } $pxe_config_file;
}

1;