package Catalog::Fault;
use Catalog::RF;
use base 'Catalog::RF';
use strict;

###################################################
#  FAULT POLICIES FILES
#
# Fault Policies Parsing
# Author: Christian Cadieux
# Transform back and forth between storade resource files and XML documents.


# Fault       : System/Fault/*fault
#               $fault = Catalog::Fault->parseFile("System/Fault/6130.fault");
#               print $fault->toText();
#   

# <fault_policies>
#   <policy name=policy1>
#     <error no=1 frequency="1">
#       <value name="EventType">ComponentRemoveEvent</value>
#       <value name="DisplayTopic">/Controller\.(\w+)$/</value>
#     </error>
#     <error no=2 frequency="1+">
#     </error>
#     <condition no=1>
#       <expr>Condition</expr>
#     </condition>
#     <variable no=1>
#     <condition no=1> $err1.DisplayTopic.1 eq $err2.DisplayTopic.1</condition>
#     <fault base="err1">
#       <value name=Severity>...</value>
#     </fault>
#  </fault_policies>
###################################################

sub info {
  return {
         ROOT => "fault_policies",
        hash  => { policy    => "name",
                   error     => "no",
                   variable  => "no",
                  condition => "no",
                  value     => "name",
         }};
}

sub toCatalog {
  my($class, $arg) = @_;
  my $D = ($arg->{BASE_DIR} || System->get_home()) . "/System/Fault";
  my(%D2);
  opendir(O, $D);
  my @files = readdir(O); closedir(O);
  foreach my $f (@files) {
    if ($f =~ /\.fault$/) {
       my $diag = $class->parseFile("System/Fault/$f");
       my $pols = $diag->{fault_policies}{policy};
       foreach my $name (keys %$pols) {
            next if ($name eq "_ATT");
            my $atts = $pols->{$name}{_ATT};
            my $type = $atts->{deviceType};
            my @types = split(/\|/, $type);
            foreach my $t (@types) {
                $D2{$t}{$name} = $pols->{$name};
            }
       }
    }
  }
  my $C = System->get_home() . Catalog->device_path();
  foreach my $t (keys %D2) {
      mkdir "$C/$t",0777 if (!-d "$C/$t");
      my $d = $class->new($D2{$t});
      open(W, ">$C/$t/fault.xml");
      print W $d->toXML();
      close(W);
  }
}

sub new {
  my($class, $rep) = @_;
  my $d =  { fault_policies => { _ATT => { revision => "\$" . "Revision:\$" },
                               policy => $rep },  _ARG => $class->info()};

  bless($d, "Catalog::Fault");
  return $d;
}

sub fromCatalog {
  my($class, $arg) = @_;
  my $D = System->get_home() . Catalog->device_path();
  chdir $D;
  my @files = `ls */fault.xml`;

  my $DATA =  Catalog->system_path() . "/Fault/";
  mkdir $DATA,0777 if (!-d $DATA);

  my(%D2);
  foreach my $f (@files) {
     chomp($f);
     my $rep =  Catalog::XML->parseFile("$D/$f", $class->info());
     if (!$rep) {
         print "Error reading Catalog/device/$f\n";
         last;
     }
     my $ix = index($f, "/");
     my $f2 = substr($f, 0, $ix);
     open(W, ">$DATA/$f2.fault");
     print W $class->toText($rep);
     close(W);
  }
}




sub parseFile {
  my($class, $file, $arg) = @_;

  my $D = System->get_home();
  if (open(O, "$D/$file")) {
     my @l = <O>; close(O);
     return $class->parse(\@l, $class->file_name($file));
  } else {
     $class->err("opening $file: $! \n");
     return undef;
  }
}

sub parse {
  my($class, $array, $file_name) = @_;

  my $out .= "<fault_policies file=\"$file_name\" revision=\"\$" . "Revision: \$\">\n";
  my ($rule, $x, %FAULT, @COND, @ERR, @VAR, %GLOB);
  foreach my $l (@$array) {
       chop($l);
       $l = Util->rtrim($l);
       if (substr($l,0,1) eq "#") {
         $out .= "<!-- $l -->\n";
         next;
       }
       if (substr($l,0,1) eq "[") {
          $rule = substr($l,1,-1);
          if ($#ERR >= 0) {
              $out .= &new_policy(\%GLOB,\@ERR, \@COND, \@VAR, \%FAULT);
              %FAULT = (); @ERR = (); @COND = (); @VAR = (); %GLOB = ();
          }
          $GLOB{name} = $rule;

       } elsif (index($l,"=") > 0) {
          my($n, $v) = split(/\s*=\s*/, $l,2);
          my @N = split(/\./, $n);

          if (substr($N[0],0,3) eq "err") {
             my $no = substr($N[0],3);
             if ($N[1] eq "value") {
                $ERR[$no]{_value}{$N[2]} = $v;
             } else {
                $ERR[$no]{_attr}{$N[1]} = $v;
             }
          } elsif ($N[0] eq "fault") {
             if ($N[1] eq "value") {
                $FAULT{_value}{$N[2]} = $v;
             } else {
                $FAULT{_attr}{$N[1]} = $v;
             }
          } elsif (substr($N[0],0,9) eq "condition") {
             my $no = substr($n,9);
             $COND[$no]{$N[1]} = $v;

          } elsif (substr($N[0],0,8) eq "variable") {
             my $no = substr($n,8);
             $VAR[$no] = $v;
          } else {
             $GLOB{$n} = $v;
          }
       }
   }
   if ($#ERR >= 0) {
     $out .= &new_policy(\%GLOB,\@ERR, \@COND, \@VAR, \%FAULT);
   }
   $out .= "</fault_policies>\n";
   my $report =  Catalog::XML->parse($out,$class->info());
   bless($report, "Catalog::Fault");
   return $report;
}

sub new_policy {
  my($GLOB, $ERR, $COND, $VAR, $FAULT) = @_;
  my ($x,  $out);
  $out .= "<policy name=\"$GLOB->{name}\"";
  foreach my $el (sort keys %$GLOB) {
     next if ($el eq "name");
     $out .= " $el=\"$GLOB->{$el}\"";
  }
  $out .= ">\n";
  for ($x=0; $x <= $#$ERR; $x++) { 
     if ($ERR->[$x]) {
       $out .= "  <error no=\"$x\" ";
       if (exists $ERR->[$x]{_attr}) {
         my $v = $ERR->[$x]{_attr};
         foreach my $el (sort keys %$v) {
            $out .= " $el=\"$v->{$el}\"";
         }
       }
       $out .= ">\n";

       if (exists $ERR->[$x]{_value}) {
         my $v = $ERR->[$x]{_value};
         foreach my $el (sort keys %$v) {
            $out .= "    <value name=\"$el\">$v->{$el}</value>\n";
         }
       }
       $out .= "  </error>\n";
     }
  }

  for ($x=0; $x <= $#$COND; $x++) { 
     if ($COND->[$x]) {
       my $v = $COND->[$x];
       foreach my $el (sort keys %$v) {
         $out .= "  <condition no=\"$x\">\n";
         $out .= "     <$el>$v->{$el}</$el>\n";
         $out .= "  </condition>\n";
       }
     }
  }
  for ($x=0; $x <= $#$VAR; $x++) { 
     if ($VAR->[$x]) {
       $out .= "  <variable no=\"$x\" >$VAR->[$x]</variable>\n";
     }
  }
  $out .= "  <fault";
  if (exists $FAULT->{_attr}) {
      my $v = $FAULT->{_attr};
      foreach my $el (sort keys %$v) {
         $out .= " $el=\"$v->{$el}\"";
      }
  }
  $out .= ">\n";

  if (exists $FAULT->{_value}) {
      my $v = $FAULT->{_value};
      foreach my $el (sort keys %$v) {
         $out .= "    <value name=\"$el\">$v->{$el}</value>\n";
      }
  }
  $out .= "    </fault>\n";
  $out .= "</policy>\n";
  return $out;
}

sub toText {
  my($class, $node) = @_;
  $node = $class if (ref($class));

  my $out;
  my $rep = $node->{fault_policies}{policy};
  foreach my $name (keys %$rep) {
     next if ($name eq "_ATT");
     my $policy = $rep->{$name};
     $out .= "\n[$name]\n";  
     my $att = $policy->{_ATT};
     foreach my $a (keys %$att) {
         next if ($a eq "name");
         $out .= "$a = $att->{$a}\n";
     }
     $out .= "\n";
     my $errs = $policy->{error};
     foreach my $err_no (sort keys %$errs) {
        next if ($err_no eq "_ATT");
        my $err = $errs->{$err_no};
        my $att = $err->{_ATT};
        my $vals = $err->{value};
        foreach my $a (keys %$att) {
           next if ($a eq "no");
           $out .= "err$err_no.$a = $att->{$a}\n";
        }
        foreach my $v (keys %$vals) {
           next if ($v eq "_ATT");
           $out .= "err$err_no.value.$v = $vals->{$v}{_VAL}\n";
        }
     }
     my $vars = $policy->{variable};
     foreach my $v (keys %$vars) {
        next if ($v eq "_ATT");
        $out .= "variable$v.value = $vars->{$v}{_VAL}\n";
     }
     my $vars = $policy->{condition};
     foreach my $v_no (keys %$vars) {
        next if ($v_no eq "_ATT");
        my $v = $vars->{$v_no};
        foreach my $el (keys %$v) {
          next if ($el eq "_ATT");
          $out .= "condition$v_no.$el = $v->{$el}{_VAL}\n";
        }
     }
     if (exists $rep->{fault}{_ATT}) {
       my $att = $rep->{fault}{_ATT};
       foreach my $a (keys %$att) {
          $out .= "fault.$a = $att->{$a}\n";
       }
     }
     my $vals = $policy->{fault}{value};
     foreach my $v (keys %$vals) {
        next if ($v eq "_ATT");
        $out .= "fault.value.$v = $vals->{$v}{_VAL}\n";
     }
  }
  return $out;
}

1;
