package AutoForm;
#<copyright>
# ----------------------------------------------------------
# Sun Proprietary/Confidential Code
# Copyright 2001, Sun Microsystems, Inc. All rights reserved.
# ----------------------------------------------------------
#</copyright>

use strict;
use System;
use Util;
use Modules;
use base 'Html';
#
# can generate maintenance forms and command from a config file (System/ST_Tests
#

# $af = AutoForm->new("System/Tests", 
#           {language      => 'french', width=> "90%", noInfo => 1
#            promptBgColor => "#CCCCFF"  });
#
sub new {
  my($class, $file, $arg) = @_;
  my $renv = System->get_renv();
  my $ruser = System->get_ruser();
  my $lang =  $ruser->{language} || $renv->{language};
  my $locale = $arg->{locale};

  $arg->{language} = $lang;
  my $var = {file => $file, arg => $arg};
  my($M, $l);

  my $F = System->get_home() . "/$file";
  if ($locale && $locale ne "en") {
    $F = System->get_home() . "/Lang/$file/$locale";
    $F = System->get_home() . "/$file" if (!-d $F);
  }


  if (-d $F) {
     opendir(O, $F);
     $M = "/tmp/ras.test.merge.$$";
     my(@tests) = readdir(O); closedir(O);
     open(W, ">$M");
     foreach my $f (@tests) {
        next if ($f !~ /\.test$/);
        open(O, "$F/$f");
        while ($l = <O>) {
          print W $l;
        }
        close(O);
     }
     close(W);
     open(O, $M);
  } elsif (!open(O, $F)) {
     return ("Cannot open $F:$!",undef);
  }
  my($section, $no, $val, $opt, $type, $size);
  $section = "GLOBAL";
  my %opts;
  while ($l = <O>) {
     chop($l);
     next if (substr($l,0,1) eq "#");
     if (substr($l,0,1) eq "[") {
        my $i = index($l, "]");
        $section = substr($l,1,$i-1);
        $opts{$section}{info}{sectionName} = $section;
     } else {
        my($n, $v) = split(/ *= */, $l, 2);
        next if (index($l,"=") < 0);
        if ($n =~ /^row(\d+)\.opt$/) {
           $no = $1;
           $opt = Util->trim($v);
           my $opt0 = $opt;
           if (substr($opt,0,1) eq "-") {
              $opt0 = substr($opt,1) ;
           }
           $opts{$section}{no}{$opt0} = $no;
           $opts{$section}{opts}[$no]{opt} = $opt;

        } elsif ($n =~ /^row(\d+)\.type$/) {
           $no = $1;
           ($type, $size) = split(/ +/, $v);

           $opts{$section}{opts}[$no]{type} = $type;
           $opts{$section}{opts}[$no]{size} = $size;
        } elsif ($n =~ /^row(\d+)\.(.*)/) {
           $no = $1; $val = $2;
           $opts{$section}{opts}[$no]{$val} = $v;   # default, name, values
        } else {
           if ($n eq "desc") {
             $opts{$section}{info}{$n} .= $v . " "; 
           } else {
             $opts{$section}{info}{$n} = $v;   # general info
           }
        }
    }
  }
  close(O);
  unlink($M) if ($M);
  $var->{command} = \%opts;
  bless($var, "AutoForm");
  return (undef, $var);
}

sub commandList {
  my($af) = @_;

  my $c = $af->{command};

  return sort keys %$c;
}

sub commandByName {
  my($af, $name) = @_;

  my $c = $af->{command};
  if (exists($c->{$name})) {
     my($c) = $c->{$name};
     bless($c, 'AF_Command');
     return $c;
  } else {
     return undef;
  }
}


sub parseTestArgs {
  my($class, $o) = @_;
  my @a = split(/\|/, $o);
  my %H;
  foreach my $el (@a) {
     my ($name, $val) = split(/\=/, $el, 2);
     $H{$name} = $val;
  }
  return \%H;
}
  

# $add = $af->addForm('a5ktest', {header => "extra", debug => 1} );

sub addForm {
  my($af, $command, $arg) = @_;

  return $af->form('a', $command, $arg);
}

# $update = $af->updateForm('a5ktest', 
#                     {header => 1, defaults => 1} ,
#                     {A=>'val1', B=> 'val2', C=> 'val3'},
#                    );
#
sub updateForm {
  my($af, $command, $arg, $data, $pre_data) = @_;
  my($upd1, $err1, $err2, $upd2, $UPD, $UPD2);
  my $info  = $af->{command}{$command}{info};

  my $LB = Labels->read('GUI::Test')->section('defaults');
   
  ($err1, $upd1, $UPD) = $af->form('u', $command, $arg, $data->{$command}, $pre_data);
  my $defaults = $af->{command}{$command}{info}{defaults};


  if ($defaults) {
     my $d = defined($data->{$command}{DEFAULTS})?
                 $data->{$command}{DEFAULTS}: $data->{DEFAULTS};

     ($err2, $upd2, $UPD2) = $af->form('u', 'DEFAULTS', $arg, $d, $pre_data);
     my $c = $arg->{debug}?3:2;

     push(@$UPD, @$UPD2);
     return ($err1.$err2, 
             "$upd1<tr><td colspan=$c><b>" . $LB->{general_options} . "</td>$upd2", 
              $UPD);
  } else {
     return ($err1, $upd1, $UPD);
  }
}

sub form {
  my($af, $mode, $command, $arg, $val, $pre_data) = @_;

  my $use_pre_data = $arg->{use_pre_data};
  my $CACHE = Cache->read("tests", 'tests');
  my $default_email = $CACHE->{DEFAULTS}{'#EMAIL'};
   
  my($renv) = System->get_renv();
  my $ruser = System->get_ruser();
  my $window = $ruser->{window} || $renv->{window};
  my $hideConst = $arg->{hideConst};

  my $width = $af->{arg}{width} || "90%";
  my $out;
  return ("Command '$command' not found in $af->{file}", undef) 
           if (!exists($af->{command}{$command}));

  my $info  = $af->{command}{$command}{info};
  my $debug = $arg->{debug};
  my $pcolor = $af->{arg}{promptBgColor} || $Style::LIGHT;

  if (defined($arg->{header})) {
    $out .="<table border=1 cellspacing=0 cellpadding=1 width=$width>";
    my $title =  $info->{name};
    $title .= " - $arg->{header}" if ($arg->{header});
    $title .= ($mode eq "a")? "&nbsp;(Add)": "&nbsp;(Update)";
    $out .= "<tr><td colspan=2 bgcolor=$Style::DARK><font color=white><b>&nbsp;$title</td>\n";
  }


  my $opts = $af->{command}{$command}{opts};
  my $syns = $af->{command}{$command}{no};
  my $err;
  if ($mode eq "u") {
     foreach my $v (keys %$val) {
         next if ($v eq "DEFAULTS");
         if (!defined($syns->{$v})) {
            $err .= "Parm $v not defined,";
         }
     }
  }
  if ($info->{desc}) {
     $out .= "<tr><td colspan=4><center><table border=0 cellpadding=2 bgcolor=#F0F0F0 width=90%><tr><td>$info->{desc}</table></td>";
  }
  my($size, $x, $last_ck, $cnt2);
  my(@FLD);

  for ($x=1; $x <= $#$opts; $x++) {
      my $opt = $opts->[$x];
      my $name = $opt->{name};
      my $code = $opt->{opt};
      next if (!$code);
      next if ($hideConst && $opt->{type} eq "const");
      my $desc;
      if ($opt->{desc} && !$af->{arg}{noInfo}) {
        $desc = "<font color=blue><small>$opt->{desc}</small></font>";
      } 
      $out .= "<tr>" ; #  if ($window ne "N" || ($window eq "N" && ++$cnt2 % 2 == 1));
      $out .= "<td bgcolor=$pcolor align=right width=40%>$name: </td><td>&nbsp;";
      my $out0;

      $code = substr($code,1) if (substr($code,0,1) eq "-");
      if ($pre_data) {
         if (substr($opt->{default},0,1) eq "#"  && $pre_data->{$opt->{default}}){
           $val->{$code} = $pre_data->{$opt->{default}};
         } elsif ($pre_data->{"opt_" . $opt->{opt}}) {
           $val->{$code} = $pre_data->{"opt_" . $opt->{opt}};
         }
      }
      if ( index(",text,const,number,password," , ",$opt->{type},") >= 0) {
         $size = $opt->{size} || 30;
         my $ty;
         if ($opt->{type} eq "const") {
            $ty = "hidden";
         } else {
            $ty = ($opt->{type} eq "password")? "password":"text";
         }
         if ($mode eq "a") {
            $out0 .= "<b>$opt->{default}</b>" if ($opt->{type} eq "const");
            $out0 .= "<input type=$ty name=opt_$code size=$size value=\"$opt->{default}\">";
         } else {
            my $v1;
            if (exists($val->{$code})) {
               $v1 = $val->{$code};
            } else {
               if ($opt->{type} ne "password") {
                 $v1 = $opt->{default};
                 $v1 = $default_email if (!$v1 && $code eq "#EMAIL");
               }
            }
            $out0 .= "<b>$v1</b>" if ($opt->{type} eq "const");
            $out0 .= "<input type=$ty name=opt_$code size=$size value=\"$v1\">";
            $out0 .= "&nbsp; (number)" if ($opt->{type} eq "number");
         }

      } elsif ($opt->{type} eq "checkbox") {
         my $ck;
         if ($mode eq "a") {        
            $ck = "checked" if ($opt->{default} == 1);
            $out0 .= "<input type=checkbox name=opt_$code $ck>";
         } else {
            my($v1);
            if (exists($val->{$code})) {
               $v1 = $val->{$code}? 1:0;
            } else {
               $v1 = $opt->{default} ? 1:0;
            }
            $ck = "checked" if ($v1);
            $out0 .= "<input type=checkbox name=opt_$code $ck>";
            
         }
         $last_ck++;
      } elsif ($opt->{type} eq "radio" || $opt->{type} eq "select") {

        my($pre_list, @vals);
        if ($pre_data && substr($opt->{values},0,1) eq "#" && 
            $pre_data->{$opt->{values}}) {
           @vals = split(/\|/, $pre_data->{$opt->{values}} );
        } else {
           @vals = split(/\|/, $opt->{values});
        }

        my $ck0;
        if ($opt->{type} eq "radio") {
            $ck0 = "checked";
        } else {
            $out0 .= "<select name=opt_$code>";
            $ck0 = "selected";
        }
        foreach my $v (@vals) {
             my($v1, $v2) = split(/=/, $v);
             my($value, $desc);
             if ($v2) {
                $value = $v1; $desc = $v2;
             } else {
                $value = $desc = $v1;
             }
             my $ck;
             if ($mode eq 'a') {
                $ck = $ck0 if ($value eq $opt->{default});
             } else {
                my $v1;
                if (exists($val->{$code})) {
                   $v1 = $val->{$code};
                } else {
                   $v1 = $opt->{default};
                }
                $ck = $ck0 if ($value eq $v1);
             }
             if ($opt->{type} eq "radio") {
                $out0 .= "<input type=radio name=opt_$code value=\"$value\" $ck>:$desc&nbsp;&nbsp;";
             } else {
                $out0 .= "<option value=\"$value\" $ck>$desc</option>";
             }
          }
          if ($opt->{type} eq "select") {
             $out0 .= "</select>";
          }
      }  
      $out0 .= "<td>&nbsp;<font color=brown>$opt->{opt}" if ($debug);
      $out0 .= "&nbsp; $desc" if ($desc);
      $out .= $out0;
      push(@FLD, [ $name, $out0]);
  }
  
  $out .= "</table>\n" if (defined($arg->{header}));
  return ($err, $out, \@FLD);
}

#
# get the value of the option $option in $q
# return ($err, $val);
#
sub getOption {
  my($af, $option, $q) = @_;

  return $q->{"opt_$option"};
}

sub makeCommand {
  my($af, $command, $q, $minus_o) = @_;
  my($x, $opts, $args, $code0, $args_o);

  if (!exists($af->{command}{$command})) {
     return("Command $command not found in $af->{file}", undef) ;
  }
  my $info     = $af->{command}{$command}{info};
  $args = $info->{soptions} . " ";
  my $binpath = $af->info("binpath");

  my $defaults = $info->{defaults};  # 0/1
  if ($defaults) {
     $opts     = $af->{command}{DEFAULTS}{opts};
     for ($x=1; $x <= $#$opts; $x++) {
         my $opt = $opts->[$x];
         my $code = $opt->{opt};
         $code0 = "opt_" . substr($code,1);
         if ($opt->{type} eq "checkbox") {
            $args .= "$code " if ($q->{$code0});
         } else {
            $args .= "$code $q->{$code0} " if (exists($q->{$code0}));
         }
     }
  }
  $opts     = $af->{command}{$command}{opts};

  $args_o = "-o ";
  my $minus = 0;
  for ($x=1; $x <= $#$opts; $x++) {
     my $opt = $opts->[$x];
     my $code = $opt->{opt};
     next if (substr($code, 0,1) eq "#");
     if (substr($code,0,1) eq "-") {
        $minus = 1;
        $code0 = "opt_" . substr($code,1);
     } else {
        $code0 = "opt_$code";
     }
     if ($minus) {   #  -XX goes before the -o dev=...
       if ($opt->{type} eq "checkbox") {
          $args .= "$code " if ($q->{$code0});
       } else {
          $args .= "$code $q->{$code0} " if (defined($q->{$code0}));
       }
       
     } else {
       if ($opt->{type} eq "checkbox") {
          $args_o .= "$code=1|" if ($q->{$code0});
       } else {
          $args_o .= "$code=$q->{$code0}|" if (defined($q->{$code0}));
       }
     }
  }
  chop($args_o) if (substr($args_o,-1) eq "|");
  $args_o = "" if ($args_o eq "-o ");

  if ($info->{path}) {
    $command = $info->{path};
  } elsif ($binpath) {
    $command = "$binpath/$command";
  }

  if ($minus_o) {
    return (undef, $command, $args, $args_o);
  } else {
    return (undef, $command, $args);
  }
}

sub values {
  my($af, $command, $q) = @_;
  my($x, %V, $code0);
  if (!exists($af->{command}{$command})) {
     return("Command $command not found in $af->{file}", undef) ;
  }
  my $info     = $af->{command}{$command}{info};
  my $defaults = $info->{defaults};  # 0/1
  my $opts     = $af->{command}{$command}{opts};
  my $err;
  for ($x=1; $x <= $#$opts; $x++) {
      my $opt = $opts->[$x];
      my $code = $opt->{opt};
      $code = substr($code,1) if (substr($code,0,1) eq "-");
      $code0 = "opt_$code";
      my $pt = $opt->{pattern};
      if ($pt && $q->{$code0} !~ /$pt/) {
         $err .= "value of '$opt->{name}' should match '$pt', ";
      }

      if ($opt->{type} eq "text" || $opt->{type} eq "number" || 
          $opt->{type} eq "password") {
          $V{$code} = $q->{$code0};
      } elsif ($opt->{type} eq "checkbox") {
          $V{$code} = $q->{$code0} ? 1:0;
      } elsif ($opt->{type} eq "select") {
          $V{$code} = $q->{$code0};
      } elsif ($opt->{type} eq "radio") {
          $V{$code} = $q->{$code0};
      }
  }
  return ($err, \%V);

}
sub info {
  my($af, $val) = @_;

  if ($val) {
    return $af->{command}{GLOBAL}{info}{$val};
  } else {
    return $af->{command}{GLOBAL}{info};
  }
}

sub defaults {
  my($af, $command) = @_;
  my($x, %V, $code0);
  return ("Command $command not found in $af->{file}", undef) 
           if (!exists($af->{command}{$command}));

  my $opts = $af->{command}{$command}{opts};

  for ($x=1; $x <= $#$opts; $x++) {
      my $opt = $opts->[$x];
      my $code = $opt->{opt};
      $code = substr($code,1) if (substr($code,0,1) eq "-");
      $code0 = "opt_$code";
      $V{$code} = $opt->{default} if (defined($opt->{default}));
  }
  return (undef, \%V);
}


package AF_Command;

sub info {
  my($c, $val) = @_;

  if (defined($val)) {
    return $c->{info}{$val};
  } else {
    return $c->{info};
  }
}

sub name {
  my ($c) = @_;
  return $c->{info}{name};
}

sub sectionName {
  my ($c) = @_;
  return $c->{info}{sectionName};
}

sub options {
  my($c) = @_;

  return $c->{opts};
}

sub sequence {
  my($c) = @_;

  return $c->{no};
}

  




1;
