package FSA::POLICIES;
use strict;
use System;
use FSA;

# pol_type = Device|System|SAN
# single target

sub debug {
  my($renv, $line) = @_;
  if ($renv->{fsa_debug} > 1) {
     print "    FSA:  $line \n";
  }
}

sub run {
  my($class, $pol_type, $Config, $topo, $targets, $elist, $debug) = @_;
  my($x,$y,$ex);
  my $rules = FSA::POLICIES->read();
  my @T = split(/\:/, $targets->[0]);
  my %SEV = (I => 0, W => 1, E => 2, D => 3);
  my $renv = System->get_renv();

  # looking for a rule that can  fire
  foreach my $f (@$rules) {
     my $pt = $f->{policyType} || "Device";
     next if ($pt ne $pol_type);
     my $dt = $f->{deviceType};
     next if ($T[0] !~ /^$dt$/); # compare target_type to valid types.
     my $errs = $f->{errors};
     my (%GOOD, @ESTATS, %EDATA, @SAVE_BASE, @DONE);
     my $run_fault=1;
     my $weight;
     &debug($renv, "Trying $f->{name}");

     for ($ex=1; $ex <= $#$errs; $ex++) {
        my $e = $errs->[$ex];
        my $values = $e->{values};
        for ($x=0; $x <= $#$elist; $x++) { 
           next if ($DONE[$x]);
           my $ed  = $elist->[$x];
           my $ev  = $ed->instances(0);
           my %EDATA0;
           my $good = 1;
           foreach my $c (keys %$values) {
               my $v = $values->{$c};
               if (!&event_match(\%EDATA0,$ex, $ev, $c, $v)) {
                  $good = 0; last;
               }
           }
           if ($good) {
             &debug($renv, "$f->{name}.err$ex: PASS: " . $ev->value("Description") );
             $GOOD{$x} = 1;
             foreach my $el (keys %EDATA0) {
                $EDATA{$el} = $EDATA0{$el};
             }
             $ESTATS[$ex]++ ; $weight++;
             push(@{$SAVE_BASE[$ex]}, $ed);
             $DONE[$x]=1;
             &save_data($ex, \%EDATA, $ev);
           } else {
             &debug($renv, "$f->{name}.err$ex: FAILED: " . $ev->value("Description"));
           }
 
        }
        if (!&freq_match($ESTATS[$ex], $e->{frequency})) {
          print "$f->{name}.err$ex: FREQUENCY is WRONG\n" if ($debug);
          $run_fault=0; last;
        }
     }
     if ($run_fault) {
       my $pass = 1;
       my $conditions = $f->{conditions};
       my ($c);
       for ($c=1; $c <= $#$conditions; $c++) {
          # run perl code if condition is too hard.
          my $val = $conditions->[$c]{value};
          $val =~ s/\$(err\d\.[\w\.]+)/'"' . $EDATA{$1} . '"'/eg;
          my $B;
          eval '$B = ' . $val;
          if (!$B) {
            $pass =0; last;
          }
       }
       if ($pass) {
          my $vars = $f->{variables};
          my ($c);
          for ($c=1; $c <= $#$vars; $c++) {
            my $val = $vars->[$c]{value};
            $val =~ s/\$(err\d\.[\w\.]+)/'"' . $EDATA{$1} . '"'/eg;
            my $B;
            eval '$B = ' . $val;
            $EDATA{"variable$c.value"} = $B;
          }
          for ($ex=1; $ex <= $#$errs; $ex++) { # change severity if needed
             my $e = $errs->[$ex];
             if ($e->{new_severity}) {
                foreach my $ed (@{$SAVE_BASE[$ex]}) {
                    $ed->id('new_severity', $e->{new_severity});
                }
             }
             my $values = $e->{values};
          }
          my $fault = $f->{fault};
          if (!$fault) {
             return (1); # done but no fault.
          }
          my $ed1 = $SAVE_BASE[substr($fault->{base},3)][0];
          my $ev1 = $ed1->instances(0);
          my $sev = $ed1->severity2();
          my $attributes = $fault->{attributes};
          my $arg = {};
          foreach my $att (keys %$attributes) {
             my $v =  $attributes->{$att};
             if ($att eq "EventType" || $att eq "GridCode") {
               $v = "$T[0].$v";
             } elsif ($att eq "Severity") {
               $v = exists $SEV{$v}? $SEV{$v} : $v ;
             } else {
               $v =~ s/\$(err\d\.[\w\.]+)/$EDATA{$1}/eg;
               $v =~ s/\$(variable\d\.\w+)/$EDATA{$1}/eg;
             }
             $arg->{$att} = $v;
          }
          my $desc = $arg->{Description};
          $arg->{Fault} = $f->{name};
          Debug->print2("$f->{name}: weight=$weight");
          my @NEW_LIST;
          foreach my $x2 (keys %GOOD) {
            push(@NEW_LIST, $elist->[$x2]);
          }
          my @ev = FSA->newEvent($elist, $targets, $ev1, $desc, $arg);
          return (1,\@NEW_LIST, $sev, @ev);
       }
     }
  }
  return (0); # not done, may need to be aggregated the default way.

}

sub event_match {
  my($EDATA, $ex, $ev, $c, $v) = @_;
  my($cat);
  my $ev_v = $ev->value($c);
  if ($c eq "EventType") {
    ($cat, $ev_v) = split(/\./, $ev_v);
  }
  return 1 if ($v eq "_ANY_");
  if (substr($v, 0, 1) eq "/" ) { # this is a pattern match  /../ 
     my $v1 = substr($v,1,-1);
     if ($ev_v =~ /$v1/i) {
       $EDATA->{"err$ex.$c.1"} = $1;
       $EDATA->{"err$ex.$c.2"} = $2;
       $EDATA->{"err$ex.$c.3"} = $3;
       $EDATA->{"err$ex.$c.4"} = $4;
       return 1;
     } else {
       return 0;
     }
  } else {
     return lc($ev_v) eq lc($v);
  }
}

sub freq_match {
  my($tot, $freq) = @_;
  if (substr($freq,-1) eq "+") {
     return $tot >= substr($freq,0,-1);
  } else {
     return $freq == $tot;
  }
}
sub save_data {
  my($ex, $EDATA, $ev) = @_;
  my @L =  $ev->value("EventType");
  $EDATA->{"err$ex.Category"}     = $L[0];
  $EDATA->{"err$ex.EventType"}    = $L[1];

  my @SEV = ('I' , 'W', 'E', 'D');
  
  $EDATA->{"err$ex.PriorValue"}   = $ev->value("PriorValue");
  $EDATA->{"err$ex.CurrentValue"} = $ev->value("CurrentValue");
  $EDATA->{"err$ex.Severity"}     = $SEV[$ev->value("Severity")];
  $EDATA->{"err$ex.Target"}       = $ev->value("Target");
  $EDATA->{"err$ex.TargetName"}   = $ev->value("TargetName");
  $EDATA->{"err$ex.Caption"}      = $ev->value("Caption");
  $EDATA->{"err$ex.DisplayTopic"} = $ev->value("DisplayTopic");
  $EDATA->{"err$ex.Component"}    = $ev->value("Component");
  $EDATA->{"err$ex.Description"}  = $ev->value("Description");
}


sub read {
  my($class) = @_;
  my $DIR = System->get_home() . "/System/Fault";
  my($l);
  opendir(O, $DIR);
  my @D = readdir(O); closedir(O);
  my @F;
  my $rcnt = -1;
  foreach my $f (@D) {
     next if (substr($f,-6) ne ".fault");
     my $FNAME = substr($f,0,-6);
     open(O, "$DIR/$f");
     my $rule;
     while ($l = <O>) {
       chop($l);
       $l = Util->rtrim($l);
       next if (substr($l,0,1) eq "#");
       if (substr($l,0,1) eq "[") {
          $rule = substr($l,1,-1);
          $rcnt++;
          $F[$rcnt]{name} = "$FNAME.$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") {
                $F[$rcnt]{errors}[$no]{values}{$N[2]} = $v;
             } else {
                $F[$rcnt]{errors}[$no]{$N[1]} = $v;
             }
          } elsif ($N[0] eq "fault") {
             if ($N[1] eq "value") {
                $F[$rcnt]{fault}{attributes}{$N[2]} = $v;
             } else {
                $F[$rcnt]{fault}{$N[1]} = $v;
             }
          } elsif (substr($N[0],0,9) eq "condition") {
             my $no = substr($n,9);
             $F[$rcnt]{conditions}[$no]{value} = $v;
             $F[$rcnt]{conditions}[$no]{type}  = $N[1];

          } elsif (substr($N[0],0,8) eq "variable") {
             my $no = substr($n,8);
             $F[$rcnt]{variables}[$no]{value} = $v;
          } else {
             $F[$rcnt]{$n} = $v;
          }
       }
     }
     close(O);
  }
  return \@F;
}

1;
