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

#  $Name:  $ 
#  $Id: SRS.pm,v 1.30 2002/09/05 15:18:38 ccadieux Exp $

use PDM;
use Carp;
use Message;
use SAF;
use Util;
use strict;
use Catalog;
use Util::Http;

use base 'Provider';
sub revision {'$Revision: 1.30 $'}

sub description {"SRS"}
sub saf         {1}
sub id          {"srs"}
sub url         {"/ETMessage/"}

sub new {
  my($self, $pdm)  = @_;

  my($p) = { pdm => $pdm };

  bless($p,'Provider::SRS');
  return $p;
}

#SAN-T3
#SAN-Switch
#SAN-VE                 (instead of Vicom)
#SAN-Storage
#SAN-SE-Series

sub UPDATE {
  my($class, $q) = @_;
  my($active, $ip, $proxy, $to, $err, $name, $nat, $info, $ip2);
  my($renv, $dev, $host,$notifs, $o);
   my $deny = Roles->verifyRole($q, "admin");
  my $G = Labels->read();
  my $L = Labels->read('Provider')->section('srs');

  if ($q->{ACTION_update}) {
    ($renv, $dev, $host,$notifs) = PDM::ConfigFile->read;

    $renv->{'pro.srs.active'} = $q->{active}? "Y":"N";
    $renv->{'pro.srs.ip'}      = $q->{ip};
    $renv->{'pro.srs.frequency'}     = ($q->{freq} +0) || 6;
    PDM::ConfigFile->write( $renv, $dev, $host,$notifs);

    $err = Html->info($L->{err_1}); 
  }

  ($renv, $dev, $host,$notifs) = PDM::ConfigFile->read;

  if ($renv->{'pro.srs.active'} eq "Y") {
    $active = "checked" ;
  } else {
    $info = "<font color=red><b>$G->{inactive}</b>";
  }

  $ip      = $renv->{'pro.srs.ip'};
  $nat     = $renv->{'pro.srs.nat'};
  my $freq = $renv->{'pro.srs.frequency'};

 $o =<<EOF;
$err
<form  method=get>
 <input type=hidden name=GO value=GUI::Providers::display>
 <input type=hidden name=option value=$q->{option}>
<center>
<table border=2 cellspacing=2 width=90% bgcolor=white><tr><td>
<table border=0 cellspacing=2 width=100%>
<tr>
<td colspan=2 bgcolor=#666699><b><font color=white>&nbsp;$L->{label}</td>

<tr><td bgcolor=$main'LIGHT align=right>$G->{active}:</td>
      <td><input type=checkbox name=active $active> $info

<tr><td bgcolor=$main'LIGHT align=right>$G->{ip}:</td>
      <td><input type=text name=ip value=\"$ip\" size=40>

<tr><td bgcolor=$main'LIGHT align=right>$L->{heartbeat}:</td>
      <td><input type=text name=freq value=\"$freq\" size=2 maxlength=2>


</table>
</table>
<b>
EOF
  if (!$deny) {
     $o .= "<input type=submit name=ACTION_update value=$G->{submit_update}>";
  }
  $o .= "</form>";
  return $o;

}

sub RUN {
  my($pro) = @_;
  my($notif, $p, $ed, $id, $cat, %SP, %MAP);
  my($pdm)   = $pro->{pdm};
  my($ed_desc, $email_text);
  my($edocs) = $pdm->getMessages;
  $DB::single = 1;
  my $ID = $pro->id();

  my($renv, $devices, $hosts, $notifs) = PDM::ConfigFile->read();
  return if ($renv->{"pro.$ID.active"}  ne "Y");

  my $SEQ  = PDM->getCacheHandle($ID . "_seq");
  my $time = System->srs_time();
  my $ip   = Util->name2ip($renv->{hostname});
  my $freq = $renv->{"pro.$ID.frequency"} || 6;
  my $dtd = "http://localhost/srs_station_message.dtd";

  my $HEAD =<<EOF;
<?xml version="1.0" encoding="US-ASCII" standalone="no"?>
<!DOCTYPE srs_station_message SYSTEM "$dtd">
EOF

  my($saf) = SAF->new({ file => $ID, size => 2000000 } );
  my($saferr, $safcnt, $old);
  while ( ($old = $saf->read()) ) {
     my $err = $pro->send($renv, $old);
     if ($err) {
       $saf->failed($old);
       $saferr++;
     } else { 
       $safcnt++;
     }
  }
  if ($saferr) {
    Debug->err(SRS => "Cound not send $saferr old messages!");
  } elsif ($safcnt ) {
    Debug->print2("  - SRSProvider: $safcnt old messages sent!");
  }
  $saf->done;
  $saferr = 0;

  my($last_topo, $mess);
  my $topo = &srs_topo($devices, $hosts, $renv, \%MAP);
  my $LD =  System->get_home(). "/DATA/last_${ID}_topo";

  if (open(O, $LD)) {
     my @a = <O>; close(O);
     $last_topo = join("", @a);
  }

  if ($pdm->getEventCount == 0 && $topo eq $last_topo) {
    if (Timer->getTimer(uc($ID)) > $freq * 60) {
      Timer->resetTimer(uc($ID));
      $SEQ->{seq}++;
      my $frq = $freq * 60;
      my $srs =<<EOF;
$HEAD
 <srs_station_message seq_no="$SEQ->{seq}" timestamp="$time" 
                      sourceIP="$ip" sourceName="RASAGENT">
    <heartbeat period="$frq" />
 </srs_station_message>
EOF
      my $err = $pro->send($renv, $srs);
      if ($err) {
        Debug->err(SRS => "Cannot send:$err");
        $saf->write($srs) if ($pro->saf());
      } 
      Debug->print2("  - SRSProvider: HeartBeat");
    }
    return;
  }
  Timer->resetTimer(uc($ID));

  my $transmission = 0;

  if ($topo ne $last_topo) {
     $SEQ->{seq}++;
     $transmission = 1;
     $mess =<<EOF;
$HEAD
<srs_station_message seq_no="$SEQ->{seq}" timestamp="$time" 
                      sourceIP="$ip" sourceName="RASAGENT">
   $topo
</srs_station_message>
EOF
     my $err = $pro->send($renv, $mess);
     Debug->print2("  - ${ID}Provider: topology");
     if ($err) {
        Debug->err(SRS => "Cannot send:$err");
        $saf->write($mess) if ($pro->saf());
     } else {
       open(O, ">$LD");
       print O $topo;
       close(O);
     }
  }
  
  my($ev, $x, $alert, $severity, $al, $agent, $host, $desc);
  my($event_desc, $event_type, $source);
  my($event_id, $event_time);
  $DB::single = 1;
  my($srs) ;

  for ($x=0; $x <= $#$edocs; $x++) {
     $ed   = $edocs->[$x];
     next if ($ed->type() eq Message::TYPE_ALERT); # Skip alerts
     next if ($ed->id("active") eq "N");

     $ev       = $ed->instances(0);
     $event_type = $ev->propertyByName("EventType")->value();
     
#           RAS    SRS
#  warning  1      3
#  error    2      4/minor 5/major
#  down     3      5/major 6/critital
#
     my $actionable = $ev->value("Actionable");
     my $caption    = $ev->value('Caption');
     next if ($actionable ne "TRUE");
     next if ($ev->value("MgmtLevel") eq "DS");
     $severity   = $ev->value("Severity");

     $severity += ($severity < 2) ? 2 : 4 ;

     $event_desc = $ev->value("Description");
     my $event_desc0 = $event_desc;
     my($g_info, $g_cause, $g_action, $g_code) =  Grid->getInfoString($event_type, $caption);
     $event_desc .= " [EventCode: 1.$g_code] " if ($g_code);
     my $data;
     if (substr($event_desc,-1) eq ":") {
       if ($data) {
         my @X = split(/\n/, $data);
         $event_desc .= " ($#X lines)";
       }
     }
     $event_desc = Util->escapeValue($event_desc);
     
     $event_id   = $ev->propertyByName("EventId")->value();
     $event_time = $ev->propertyByName("EventTime")->value();
     $event_time = substr($event_time,0,8) . "." .  substr($event_time,8,6) . 
                   substr($event_time, -5,3);
     $agent      = $ed->instances(1);
     $host       = $ed->instances(4);
     # $source     = $ev->propertyByName("SourceIP")->value();
     $cat   = $ed->id("category"); #  or System->model();
     next if (index("stools4,topo,host,mpxio,san", $cat) >= 0);

     my $target  = $ev->propertyByName("Target")->value();
     $target =~ s/[\:\.]/-/g;
     $source     = $MAP{$target}[0];
     my $module  = $MAP{$target}[1];
     if (!$source) {
        Debug->print3("${ID}Provider: Cannot find source_ip for $target, defaulting to master_ip");
        $source = Util->name2ip($renv->{hostname});
        $module = "rasagent";
     }
        
     my($sys)  = $ed->instances(4);
     $sys = $ed->instances(8) if ($sys->type() eq "H");
     $transmission = 1;

     $SEQ->{seq}++;
     $srs =<<EOF;
$HEAD
 <srs_station_message seq_no="$SEQ->{seq}" timestamp="$time" 
                      sourceIP="$ip" sourceName="RASAGENT">
    <alarm source="$source" provider="RASAGENT" module="$module"
           alarm_id="$event_id" timestamp="$time" state="O" severity="$severity"
           type="$event_type">
          $event_desc
    </alarm>
 </srs_station_message>
EOF
     my $err = $pro->send($renv, $srs);
     if ($err) {
       Debug->err(SRS => "${ID}Provider: Cannot send message :$err");
       $saf->write($srs) if ($pro->saf());
       $saferr++;
     } else { 
       Debug->print2("  - ${ID}Provider: alarm $event_desc0 ");
     }
  }
#


}

sub send {
   my($pro, $renv, $mess) = @_;
   my($D);
   my $ID = $pro->id();
   my $ext = $pro->url();

   foreach my $srs_ip ('ip') {
     my($url) = $renv->{"pro.$ID." . $srs_ip};
     next if (!$url);

     $url = "http://$url" if (substr($url,0,4) ne "http");
     $url .= $ext;

     if (-d "/net/code/usr6/Events") {
       $D = "/net/code/usr6/Events/srs.xml";
       if (open(O2, ">>$D")) {
         print O2 "# url=$url\n";
         print O2 $mess;
         print O2 "\n--------------------------------------------\n";
         close(O2);
       }
     }

     my($err, $value) = Util::Http->post($url, $mess, 20);

     if ($pro->id() ne "sunmc") {    # deal with error unless it's sunmc
       if ($err =~ /500/) {  # retry
          sleep(1);
          ($err, $value) = Util::Http->post($url, $mess, 20);
       }
       if ($err) {
          $err .= ": $value";
          return $err;
       }
     }
   }
   return undef;
}


sub srs_topo {
  my($devices, $hosts, $renv, $MAP) = @_;
  my(%H,%G, $port, %IP);
  my($acronym) = $renv->{GSV_ACRONYM};
  my %TYPE;
  $TYPE{""}                = $renv->{solution_model};
  $TYPE{$renv->{hostname}} = $renv->{solution_model};
  
  foreach my $h (@$hosts) {
     $TYPE{$h->{hostname}} = $h->{solution_model};
     $IP{$h->{hostname}} = $h->{ipno};
  }

  foreach my $d (@$devices) {
     my $ho = $d->{host} || $renv->{hostname};

     if ($d->{type} eq "t3" && $d->{mgmtLevel} ne "C") { # C= not a rack component
         my $wwn  = $d->{key};
         my $wwn0 = $wwn;
         $wwn =~ s/\./-/g;
         $MAP->{"t3-$wwn"}[0] = $d->{ipno};
         $MAP->{"t3-$wwn"}[1] = $d->{name}; # "rasagent";
         $wwn = $d->{name} . "-$wwn";

         if ($wwn )  {
            $G{t3} .=<<EOF;
      <node action="ADD" address="$d->{ipno}" name="t3-$wwn" model="t3" serial="$wwn0"/>
EOF
         }
     } elsif ($d->{type} eq "se" && $d->{mgmtLevel} eq "D") { # rack as devices
         my $wwn  = $d->{key};
         my $wwn0 = $wwn;
         $wwn =~ s/\./-/g;
         $MAP->{"se-$wwn"}[0] = $d->{ipno};
         $MAP->{"se-$wwn"}[1] = $d->{name}; # "rasagent";
         $wwn = $d->{name} . "-$wwn";

         if ($wwn )  {
            $G{se} .=<<EOF;
      <node action="ADD" address="$d->{ipno}" name="se-$wwn" model="se" serial="$wwn0"/>
EOF
         }
     } elsif ($d->{class} =~ /^switch/ && $d->{mgmtLevel} ne "C") {
         my $t    = $d->{type};
         my $wwn  = $d->{wwn};
         my $wwn0 = $wwn;
         $wwn =~ s/\./-/g;
         $MAP->{$t . "-$wwn"}[0] = $d->{ipno};
         $MAP->{$t . "-$wwn"}[1] = $d->{name}; # "rasagent";

         $wwn = $d->{name} . "-$d->{wwn}";

         if ($wwn) {
            $G{switch} .=<<EOF;
      <node action="ADD" address="$d->{ipno}" name="$t-$wwn" model="$t" serial="$wwn0"/>
EOF
         }

     } else {
         my $host = $d->{host} || $renv->{hostname};
         &addModule(\%G, $host, $d->{type}, $d->{key}, $MAP, $d->{name}, $TYPE{$d->{host}}, $IP{$d->{host}});
     }
  }
  &addModule(\%G, $renv->{hostname}, "message", System->hostid(), $MAP);
  if ($renv->{categories} =~ /t3/) {
    #&addModule(\%G, $renv->{hostname}, "t3message", System->hostid(), $MAP);
  }

  foreach my $h (@$hosts) {
     &addModule(\%G, $h->{hostname}, "message", $h->{hostid}, $MAP, 
                undef, undef, $h->{ipno});
     if ($h->{categories} =~ /t3/) {
       #&addModule(\%G, $h->{hostname}, "t3message", $h->{hostid}, $MAP);
     }
  } 
    
# the SRS provider name MUST remain RASAGENT 
# the version 2.2 maps to StorADE 2.0
# Changes to this require contact with the SRS team, Phil Cornelius

  my $out =<<EOF;
<topology type="FULL">
  <provider name="RASAGENT" vendor="SUN Microsystems" version="2.2"
            description="$acronym Agent"/>
EOF
  my %N = (t3 => "SAN_T3", switch => "SAN_Switch", se => "SAN_SE_Series");

  foreach my $x (keys %G) {
     if ($x eq "t3" || substr($x,0,6) eq "switch" || $x eq "se") {
        $out .= "    <group name=\"$N{$x}\" type=\"$x\">\n$G{$x}\n    </group>\n";
     }
  }
  foreach my $x (keys %G) {
     if ($x ne "t3" && substr($x,0,6) ne "switch" && $x ne "se") {
        $out .= "$G{$x}      </node>\n";
     }
  }
  $out .= "</topology>\n";
  return $out;
}

sub addModule {
  my($G, $host, $type, $wwn, $MAP, $dev_name, $id, $ipno) = @_;
  my($d_ip, $d_host);
  $d_host = $host || System->hostname();
  $d_ip = $ipno || Util->name2ip($d_host);
  $wwn =~ s/\./-/g;
  $MAP->{"$type-$wwn"}[0] = $d_ip;

  if (!$G->{$d_host}) {

      $G->{$d_host} .=<<EOF;
      <node action="ADD" address="$d_ip" name="$d_host" model="rashost" serial="$id-$d_ip">
EOF
   }
   my $name= "$type-";
   $name .= "$dev_name-" if ($dev_name);
   $name .= $wwn;
   $MAP->{"$type-$wwn"}[1] = $name;
   $G->{$d_host} .=<<EOF;
        <module name="$name" vendor="SUN" model="$type" 
                   serial="$wwn" version="1.0" description="$type">
        </module>
EOF
}

  
1;
