package Snapshot;
use strict;
use System;


sub fixRenv {
  my($class, $renv) = @_;

  foreach my $l ('logfile','t300logfile','dsp_logfile', 'trap_messages', 'messages.6130') {
     my $file = $renv->{$l};
     next if (!$file);
     my $ix = rindex($file, "/");
     $renv->{$l} = System->get_snapshot() . "/" . substr($file, $ix+1);
  }
  $renv->{manual_topology} = 1;
}

sub seekLogfile {
  my($class, $snap, $renv) = @_;

  foreach my $f ('logfile','t300logfile', 'dsp_logfile', 'trap_messages', 'messages.6130') {
     $snap->{"${f}_seek"} = (stat($renv->{$f}))[7];
  }
}



sub prepare {
  my($class, $rep) = @_;

  my $data;
  $rep = $rep->{_value};
  use Data::Dumper;
  $Data::Dumper::Indent = 1;

  foreach my $el (sort keys %$rep) {
     if (ref($rep->{$el})) {
       my $d = Dumper($rep->{$el});
       $data .= " '$el' => " . substr($d,7,-2)  . ",\n";
     } else {
       my $new = $rep->{$el};
       $new =~ s/'/\\'/g;
       $data .= " '$el' => '$new',\n";
     }
  }
  return $data;
 
}

#
# CALLED FROM RASAGENT TO SETUP A SNAPSHOT FOR EXECUTION
# -T 001         # fail
# -T 001,REPAIR
#
sub setup {
  my($class, $snap, $base) = @_;

  my($snap, $oper) = split(/,/, $snap);
  my $DATA = System->get_home() . "/DATA";
  $oper = "FAIL" if (!$oper);
  $oper = uc($oper);

  my $BASE = $base || "/var/opt/SUNWstade/SNAP";
  Debug->print2("Use Snapshot '$BASE/$snap'");
  if (!-d "$BASE/$snap") {
    print "Error: Directory $BASE/$snap does not exists!\n";
    exit;
  }

  System->set_snapshot("$BASE/$snap/$oper");

  mkdir "$DATA/TEST_REPORTS", 0777;

  my $COPY = "$BASE/$snap/$oper";

  foreach my $d ('EDOCS',   'SEQUENCER',  'MAXEVENTS','CACHE',
                 'DEVICES', 'THRESHOLDS', 'TIMELAPSE','ALARMS' ) {
    unlink "$DATA/$d.db";
    unlink "$DATA/$d.db.lock";
  }
  unlink "$DATA/Events_1.1.sch";
  unlink "$DATA/Storage_1.1.sch";

  system("cp $COPY/Events.log $DATA");
  if (-f "$COPY/EventsSys.log") {
    system("cp $COPY/EventsSys.log $DATA");
  }
  if (-f "$COPY/SLAVE_DATA") {
    system("cp $COPY/SLAVE_DATA $DATA");
  }
  system("cp $BASE/$snap/rasagent.conf $DATA");
  if (-f "$BASE/$snap/Inventory.golden") {
    system("cp $BASE/$snap/Inventory.golden $DATA");
  }
  system("rm -f $DATA/topo/*");
  system("cp $BASE/$snap/topo/* $DATA/topo");
  system("rm -f $DATA/OLD_REPORTS/*:*");
 

  if ($oper eq "REPAIR") {
    system("cp $BASE/$snap/FAIL/OLD_REPORTS/*:*  $DATA/OLD_REPORTS" );
    &create_tests("$COPY/OLD_REPORTS",          "$DATA/TEST_REPORTS");
  } else {  # FAIL
    system("cp $BASE/$snap/BASE/OLD_REPORTS/*:*  $DATA/OLD_REPORTS" );
    &create_tests("$COPY/OLD_REPORTS",          "$DATA/TEST_REPORTS");
  }
}

sub create_tests {
 my($FROM, $TO) = @_;

   opendir(O, $FROM);
   my @files = readdir(O); closedir(O);
   foreach my $f (@files) {
     next if ( $f !~ /\:/);
     my $rep = Util->deserialize0("$FROM/$f");
     my $data = Snapshot->prepare($rep);
     open(O, ">$TO/$f");
     print O $data;
     close(O);
   }
}

use vars qw($OPER $DIR $DONE $PATH);


sub saveFile {
  my($class, $file, $data) = @_;
  my $path = $class->path();
  if ($path) {
     open(O, ">$path/$file");
     print O $data;
     close(O);
  }
}

sub appendFile {
  my($class, $file, $data, $arg) = @_;
  my $path = $class->path();
  my $nocomment = $arg->{nocomment};
  if ($path && $data) {
     open(O, ">>$path/$file");
     my $today = System->get_today();
     print O "$today  ==========================================\n" if (!$nocomment);
     print O $data;
     close(O);
  }
}


# return $DIRECTORY

sub path {
  my($class) = @_;
  my($line);
  return $PATH if ($DONE);
  $DONE = 1;

  my $file = System->get_home() . "/DATA/SNAP";
  if (open(O, $file)) {
     $line = <O>; 
     close(O);
     chomp($line);
     my($op, $dir) = split(/\=/, $line);
     $PATH = "$dir/" . uc($op);
     return $PATH;
  }
  return undef;
}

sub saveEvents {
  my($class, $COPY, $eventid_list) = @_;

  if (!$COPY) {
    $COPY = "/tmp/StorADE";
    mkdir $COPY, 0777  if (!-d $COPY);
  }
  Debug->print2("Snapshot: Saving events to $COPY/Events...");

  mkdir "$COPY/Events", 0777  if (!-d "$COPY/Events");
  system("/bin/rm -f $COPY/Events/*");

  my $edocs = PDM->getMessagesFromList($eventid_list);
  foreach my $ed (@$edocs) {
       next if (!$ed);
       my $toc = $ed->toC();
       my $ev  = $ed->instances(0);
       my $id  = $ev->value("EventId");
       open(O1, ">$COPY/Events/$id.toc");
       use bytes;
       print O1 $toc;
       no bytes;
       close(O1);      
  }
}

# key separate parent from other events.
#
sub key {
  my($class, $ed) = @_;
  my $ev = $ed->instances(0);
  my $et = $ev->value("EventType");
  my $t  = $ev->value("Target");
  my $co = $ev->value("Component");
  my $ag = $ev->value("Aggregate");
  return ($ag > 0 ? "AggregatedEvent," : "") . "$et,$t,$co";

}

sub eventsDir {
  my($class, $DIR)= @_;
  if (!-d "$DIR/Events") {
     return 0;
  }
  opendir(O, "$DIR/Events");
  my @L = readdir(O); closedir(O);
  my $found = 0;
  foreach my $l (@L) {
    if ($l =~ /\.toc$/) {
       $found = 1; last;
    }
  }
  return $found;
}


# compare new events to the ones saved in the snapshot
# 
sub compareEvents {
  my($class, $eventid_list) = @_;
  return 0 if (!System->get_snapCompareEvents());

  my $DIR = System->get_snapshot();
  return 0 if (!$class->eventsDir($DIR)); 
  my(@old_list);

  opendir(O, "$DIR/Events");
  my @files = readdir(O); closedir(O);
  foreach my $f (sort @files) {
     next if ($f !~ /\.toc$/);
     open(O, "$DIR/Events/$f");
     my @lines = <O>; close(O);
     my $string = join("", @lines);
     my $ed = Message->fromC($string);
     push(@old_list, $ed);
  }

  my(%OLD, %NEW);
  my $edocs = PDM->getMessagesFromList($eventid_list);
  foreach my $old (@old_list) {
     next if (!$old);
     my $key = $class->key($old);
     push(@{$OLD{$key}}, $old);
  }
  foreach my $new (@$edocs) {
     next if (!$new);
     my $key = $class->key($new);
     push(@{$NEW{$key}}, $new);
  }
  foreach my $e (keys %OLD) {
      if (!$NEW{$e}) {
          Debug->print0("SNAP_ERROR_01|$e| Event from Snapshot is missing");
          next;
      }
  }
  my ($x);
  foreach my $e (keys %NEW) {
      if (!$OLD{$e}) {
          my $et = $NEW{$e}[0];
          my $ev = $et->instances(0);
          if ($ev->value("EventType") !~ /Discovery/) {
            Debug->print0("SNAP_ERROR_03|$e| New event is not in the Snapshot");
          }
          next;
      }
      my $o = $OLD{$e};
      my $n = $NEW{$e};
      if ($#$o != $#$n) {
         Debug->print0("SNAP_ERROR_04|$e| Number of events changed from " . ($#$o+1) . " to " . ($#$n+1));
      } else {
          for($x=0; $x <= $#$o; $x++) {
            eval {
              $class->compare1("$e\[$x\]", $o->[$x], $n->[$x]);
            };
          }
      }
  }

  return 1;
}

sub cimKey {
  my($class, $e) = @_;
  my($x, $key);
  $key = "$e->[1],";
  my $values = $e->[3];
  foreach my $v (@$values) {
     if ($v->[3]) {
         if (ref($v->[1])) {
           my $k1 = $v->[1];
           $key .= "$k1->[0](";
           my ($y);
           for ($y=1; $y <= $#$k1; $y+=2) {
             next if ($k1->[$y] eq "EventId" || ref($k1->[$y+1]));
             $key .= $k1->[$y] . ":" . $k1->[$y+1] . ",";
           }
           chop($key);
           $key .= "),";
         } else {
           $key .= "$v->[0]:$v->[1],";
         }
     }
  }
  return $key;
}

sub compare1 {
  my($class, $id, $old, $new) = @_;

  my $oldes = $old->instances;
  my $newes = $new->instances;

  my $olde = $oldes->[0];
  my $newe = $newes->[0];

  foreach my $e ('Caption','Actionable','SolutionId','Severity', 'GridCode','Aggregate') {
      my $ov = $olde->value($e);
      my $nv = $newe->value($e);
      if ($ov ne $nv) {
          Debug->print0("SNAP_ERROR_05|$id| $e changed from '$ov' to '$nv'");
      }
  }
  my( %OKEY, %NKEY, $x);

  # reading all cim-instances of a specific event

  for ($x=1; $x <= $#$oldes; $x++)  {
     my $o = $oldes->[$x];
     next if (!$o);
     my $k = $class->cimKey($o);
#print "old $k \n";
     $OKEY{$k} = $o;
  }

  for ($x=1; $x <= $#$newes; $x++)  {
     my $n = $newes->[$x];
     next if (!$n);
     my $k = $class->cimKey($n);
#print "new $k \n";
     $NKEY{$k} = $n;
  }

  foreach my $e (keys %OKEY) {
     if (! exists $NKEY{$e}) {
         Debug->print0("SNAP_ERROR_06|$id| CIM_Instance '$e' is missing");
     }
  }

  foreach my $e (keys %NKEY) {
     if (! exists $OKEY{$e}) {
         Debug->print0("SNAP_ERROR_07|$id| New CIM_Instance '$e' was added");
     }
  }
}

#
# 001/rasagent.conf
# 001/BASE/OLD_REPORTS/..
# 001/FAIL/TEST_REPORTS/..
# 001/FAIL/t300messages, dsp_message
# 001/FAIL/Events.log
# 001/REPAIR/TEST_REPORTS/..
# 001/REPAIR/Events.log
# 
#
# run at the end of storade on FAIL or REPAIR
#
sub process {
   my($class, $renv, $eventid_list) = @_;
   $DB::single=1;
   my($line);
   if (System->get_snapshot()) {  # running with -T
     $class->compareEvents($eventid_list);
     $class->saveEvents("", $eventid_list); # save events if -T 
     return;
   }

   my $file = System->get_home() . "/DATA/SNAP";
   if (open(O, $file)) {
      $line = <O>; 
      close(O);
      chomp($line);
      ($OPER, $DIR) = split(/\=/, $line);
   }

   if (!$OPER) {  # save events to temp if debug -2
     if (Debug->level() >= 2) {
       Debug->print2("Saving new events to /tmp/StorADE/Events");
       $class->saveEvents("", $eventid_list);
     }
     return;
   }

   my $COPY = "$DIR/" . uc($OPER);
   my $snap = Util->deserialize0("$DIR/snapshot.conf");
   my $COUNT = "count_" . lc($OPER);
   $snap->{$COUNT}++;
   $snap->{hostid} = System->hostid();

   $class->saveEvents($COPY, $eventid_list);

   Debug->print2("Snapshot: Copying Reports and logfiles to $COPY...");

   my $DATA = System->get_home() . "/DATA";

   $class->seekCopy("$DATA/Events.log", "$COPY/Events.log", 
                      $snap->{events_log_seek}, $snap->{$COUNT});

   $class->seekCopy("$DATA/EventsSys.log", "$COPY/EventsSys.log", 
                      $snap->{eventsSys_log_seek}, $snap->{$COUNT});

   if ($snap->{$COUNT} == 1) {
     system("cp $DATA/OLD_REPORTS/*:* $COPY/OLD_REPORTS");
   } else {
     system("cp $DATA/OLD_REPORTS/*:* $COPY/NEXT_REPORTS");
   }
   system("cp $DATA/ALARMS.db* $COPY");
   if (-f "$DATA/SLAVE_DATA") {
      system("cp $DATA/SLAVE_DATA $COPY");
   }
   if (-f "$DATA/SLAVE_DATA.2") {
     system("cp $DATA/SLAVE_DATA.2 $COPY");
   }

   my($line, $tell);
   foreach my $log ('logfile','t300logfile','dsp_logfile', 'trap_messages', 'messages.6130') {
      my $file = $snap->{$log};
      next if (!-f $file); 
      open(FILE, $file);
      seek(FILE, $snap->{"${log}_seek"}, 0);
      my $ofile = $file;
      my $ix = rindex($file, "/");
      $ofile = substr($file, $ix+1) if ($ix > 0);
      open(W, ">>$COPY/$ofile");
      print W "# $COUNT=$snap->{$COUNT}\n";
      for ($tell = tell(FILE); $line = <FILE>; $tell = tell(FILE)) {
         print W $line;
      }
      close(W);
   }
   $snap->{"date_". lc($OPER)} = Util->get_today();
   $snap->{"time_". lc($OPER)} = time;

   Snapshot->seekLogfile($snap, $renv);

   Util->serialize0("$DIR/snapshot.conf", $snap);

}

sub seekCopy {
  my($class, $from, $to, $seek, $count) = @_;
  my($tell, $line);
  open(FILE, $from);
  seek(FILE, $seek,0);
  open(W, ">>$to");
  print W "RUN-COUNT $count\n";
  for ($tell = tell(FILE); $line = <FILE>; $tell = tell(FILE)) {
     print W $line;
  }
  close(W);
}


1;
