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

#  $Name:  $ 
#  $Id: Health.pm,v 1.63 2002/09/29 21:14:15 ccadieux Exp $

use Report;
use Carp;
use Transition;
use Thresholds;
use CIM::Instance;
use strict;
use Message;
use State;

sub new {
  my($class) = @_;

  my($x) = {};

  bless($x, "Health");
  return $x;
}


sub saveAlert {
  my($hm, $ev, $level, $id, $report, $cause, $desc) = @_;
  my($pdm) = $hm->{pdm};

  my($type) = $ev->propertyByName("EventType")->value;
  my($cap) = $ev->propertyByName("Caption")->value;
  $type .= ".$cap" if ($cap);

  my($alert) = CIM::Instance->new('NWS_AlertIndication', [
                  [ AlertId      => $id  ],
                  [ Description  => $desc],
                  [ AlertType    => $type],
                  [ Severity     => $level],
                 [ ProbableCause => $cause],
                  ]);
  my($pertains) =  CIM::Instance->new('NWS_AlertPertainsToEvent', [
                  [ Event        => $ev ],
                  [ Alert        => $alert ],
                  ]);

  my($ed) = Message->new({ id     => $report->id,
                            instances => [$alert, $pertains],
                            type      => Message::TYPE_ALERT ,
                            });
  $pdm->saveMessage($ed);
}


sub locationChangeEvent {
  my($hm, $report, $rep, $orep, $keyval) = @_;

  my($ev, $key, $sd, $pertains, $ed);
  my $renv = System->get_renv();
  return if ($renv->{solution} eq "Y");
  my($pdm) = $hm->{pdm};
  my($cat) = $report->category();
  my($name) = $report->id('display');
  my $mgmtLevel = $report->value('id.mgmtLevel') || 'D';

  my($old) = "Contract:"   . $orep->get("location.contractNo")  . ", " . 
             "HostId:"     . $orep->get('location.hostId')      . ", " .
             "CustomerNo:" . $orep->get("location.customerNo")  . ", " .
             "Site:" .       $orep->get("location.siteName")    . ", " . 
                             $orep->get("location.siteAddress") . ", " .
                             $orep->get("location.siteCity")    . ", " .
                             $orep->get("location.siteState")   . ", " .
                             $orep->get("location.siteZip")     . ", " .
                             $orep->get("location.siteContact") . "," .
                             $orep->get("location.siteEmail") ;

  my($new) = "Contract:"   . $rep->get("location.contractNo")   . ", " . 
             "HostId:"     . $rep->get('location.hostId')       . ", " .
             "CustomerNo:" . $rep->get("location.customerNo")   . ", " . 
             "Site:" .       $rep->get("location.siteName")    . ", " . 
                             $rep->get("location.siteAddress") . ", " .
                             $rep->get("location.siteCity")    . ", " .
                             $rep->get("location.siteState")   . ", " .
                             $rep->get("location.siteZip")     . ", " .
                             $rep->get("location.siteContact") . "," .
                             $rep->get("location.siteEmail") ;

  if ($old ne $new) {
    #my $desc = Events->info('LocationChange', $cat, $name)->serialize();
    my $desc = "Location of $cat $name was changed:";
    $ev = CIM::Instance->new('NWS_Event', [
                  [ EventType   => lc($cat) . ".LocationChange"  ],
                  [ EventId     => $pdm->getEventSequence  ],
                  [ MgmtLevel   => $mgmtLevel ],
                  [ Description => $desc ], 
                  [ Data        => "Location Changed from:\n$old\nto:\n$new" ],
                         ]);
     my($key) = CIM::Key->new( ['NWS_System',
                   'Name'       => $keyval,
                    CreationClassName => 'NWS_System']);

     $sd = Events->sourceDetector({ event => $ev });

     $pertains = CIM::Instance->new('NWS_EventPertainsToSystem', [
                  [ Event       => $ev  ],
                  [ Element     => $key ],
                    ]);

     my($loc) = NWS->location($rep);

     my($locp) = CIM::Instance->new('NWS_AgentLocation', [
                  [ Agent       => $sd->[0]  ],
                  [ Element     => $loc ],
                    ]);


     $ed = Message->new( { id        => $report->id,
                            instances => [$ev, @$sd, $pertains, $loc, $locp ],
                          });
     $pdm->saveMessage($ed);
  }
     
}

# $hm->alarm($report, $orep, "BROCADE", "sensor.temperature.1", "status",
#                             $id, $id, $wwn, "sensor.temperature.status");
#      sensor.temperature.1        : used as a key in the state DB
#      sensor.temperature.1.status : used to read the agent-report
#      sensor.temperature.status   : used as a key in the Avail. Map file.

#  id = display id, use by saveState only
#  wwn= cim key
#  shortid = name
#  map_id = used to assign on topology
#  arg->{info} : extra info
#  $arg->{use_map_id}   : use the map_id for the events.

sub alarm {
  my($class, $report, $orep, $cat, $comp, $el, $shortid, 
     $display_id, $cimkey, $map_id, $arg) = @_;

  my $rep = $report->content();
  my $s2 = $orep->{"$comp.$el"} || "[Undefined]";
  my $s1 = $rep->{"$comp.$el"}  || "[Undefined]";
  my $extra = "($arg->{info})" if ($arg->{info});
  my $desc_display = "$comp.$el";

  my $state_comp = ($arg->{use_map_id})? $map_id : $comp;

  my($map) = PDM->getDeviceStateMap(lc($cat) . ".availability");

  $map_id = $el if (!$map_id);
  my($ostatus) = $map->get("$map_id.$s2");
  my($status)  = $map->get("$map_id.$s1");
  if (System->get_bad_health()) {
     $s1 = "BAD"; $status = 0;
     delete $orep->{"$comp.${el}_time"};
  }

  my ($action, $sign);
  if ($status eq "X") {
    $sign = "X"; $action = 2;
  } elsif ($status == 0) {
    $sign = "M";  $action = 2;
  } else {
    $sign = "P"; $action = 0;
  }
  my $al = 0;
  if ($s1 ne $s2 && ($s2 ne "[Undefined]") ) {
     my $desc = "The state of '$desc_display' on $shortid changed from '$s2' to '$s1' $extra";
     my $ev = $class->alarmEvent("", $report, $cimkey, $desc, $action, "$sign.$comp.$el" , {noState => 1});
     $al =1;
     if ($status == 1) {
       State->saveState($cat, $cimkey, $state_comp, $display_id, Message::SEVERITY_NORMAL, $desc, $status, $ev);
     }
  }
  my $time_id = "$comp.${el}_time";
  $rep->{$time_id} = $orep->{$time_id} if (exists($orep->{$time_id}));

  if ($status != 1) {
    if ($s1 ne "[Undefined]" ) { # in comment to fix host lun monitoring problem.
       my $desc = "The state of '$desc_display' on $shortid is '$s1' $extra";
       my $time = $rep->{$time_id};
       if (!$time) {
         my $ev = $class->alarmEvent("", $report, $cimkey, $desc, $action, "$sign.$comp.$el", {noState => 1}) if (!$al); 
         $rep->{$time_id} = time;
         # could be error or warning if status == 0 or 'X');
         # warning the first time around or if last_value was 0/X

         my $sev = ($orep ne $rep && ($ostatus == 1)) ? 
                      Message::SEVERITY_ERROR : Message::SEVERITY_WARNING;
         State->saveState($cat, $cimkey, $state_comp, $display_id, $sev, $desc, $status, $ev);
       }
    }
  } else {
     delete $rep->{$time_id};
  }
}

# if actionable == 2, sev = error,
# if actionable == 1, sev = warning,
# if actionable == 0, sev = normal
# $arg->{severity} can be used.

sub alarmEvent {
  my($hm, $data, $report, $keyval, $desc, $actionable, $caption, $arg) = @_;

  my($ev, $key, $sd, $pertains, $ed);
  my($pdm) = $hm->{pdm};
  my $captionIsState = $arg->{captionIsState};
  my($cat) = $report->category();
  my($id)  = $pdm->getEventSequence ;
  my($rep) = $report->content();
  my $mgmtLevel = $report->value('id.mgmtLevel') || 'D';
  $actionable = 1 if (!defined($actionable)); # can turn off actionable
  $caption = "AlarmEvent" if (!$caption);
  my $sev  = $arg->{severity} || $actionable;

  $ev = CIM::Instance->new('NWS_Event', [
                  [ EventType   => lc($cat) . ".AlarmEvent"  ],
                  [ EventId     => $id          ],
                  [ Data        => $data        ],
                  [ Caption     => $caption     ],
                  [ Target      => lc($cat) . ":" . $keyval],
                  [ TargetName  => $report->id('display')],
                  [ Actionable  => $actionable  ],
                  [ MgmtLevel   => $mgmtLevel   ],
                  [ SourceIP    => $rep->{'id.ipno'}],
                  [ Severity    => $sev         ],
                  [ Description => $desc        ],
                         ]);
   $key = CIM::Key->new( ['NWS_System',
                   'Name'       => $keyval,
                    CreationClassName => 'NWS_System']);
   $sd = Events->sourceDetector({ event => $ev });

   $pertains = CIM::Instance->new('NWS_EventPertainsToSystem', [
                  [ Event       => $ev  ],
                  [ Element     => $key ],
                    ]);

   $ed = Message->new( { id        => $report->id,
                          instances => [$ev, @$sd, $pertains ],
                        });
   $pdm->saveMessage($ed);

   $hm->saveAlert($ev,  $sev, $id, $report, 
       $report->id("logFile") . "\n $data" , $desc);

   if (!$arg->{noState}) {
     my $c = $captionIsState ? $caption : "alarm.$caption";
     State->saveState($cat,  $keyval, $c, "Alarm", $sev, $desc, 1, $ev);
   }
   return $ev;
}

sub portStatEvents {
  my($hm , $report, $PORTS, $rep, $orep) = @_;
  my $wwn = $report->id('deviceName');
  my $id  = $report->id('display');
  my $cat = $report->category();

  my($x, $port, @P);
  for ($x=0; $x <= $PORTS; $x++) {
     $port = "port.$x";
     my $state = $rep->get("$port.state");
     next if ($state =~ /offline/ || $state =~ /unknown/ || $rep->get("$port.mode") eq "offline" );

     my $rep1 = $rep->subset("$port.error");
     foreach my $val (keys %$rep1) {
         next if ($val eq "C3Discards");
         my($old) = $orep->get("$port.error.$val");
         my($new) = $rep->get("$port.error.$val");
         if ($new > $old) {
           my($level, $cnt, $desc, $mins) = Thresholds->test($cat, $val, $x, $new-$old);
           if ($level eq "W" || $level eq "E") {
             $P[$x] .= "Received $cnt '$desc' in $mins mins (value=$new)\n";
           }
         }
     }
  }
  for ($x=0; $x <= $PORTS; $x++) {
    if ($P[$x]) {
      my $data = $P[$x];
      chop($data);
      if ($data =~ /\n/) {
         $hm->alarmEvent( $data, $report,  $wwn, 
            "Change in statistics on switch $id, port-$x:", 
            Message::SEVERITY_WARNING, "port.$x.statistics", {captionIsState => 1});
      } else { 
         $hm->alarmEvent( "", $report,  $wwn, 
            "Switch $id, port-$x: $data",
            Message::SEVERITY_WARNING, "port.$x.statistics", {captionIsState => 1});
      }
    }
  }

}

sub logEvent {
  my($hm, $log, $report, $keyval, $desc, $sev, $caption, $save) = @_;

  my($ev, $key, $sd, $pertains, $ed);
  my($pdm) = $hm->{pdm};
  my($cat) = $report->category();
  my($id)  =  $pdm->getEventSequence ;
  my($id2) =  $report->id('display');

  my($rep) = $report->content();
  my($name)= $rep->get('id.name') if ($rep);
  $caption = "MessageLog" if (!$caption);

  if ($save) {
     open(O, ">" . System->get_home() . "/DATA/dump/${cat}LogFile");
     print O $log;
     close(O);
  }
  $desc =  "$cat.MessageLog on $id2:" if (!$desc);
  my $action= 0;
  $action = 1 if ($sev == Message::SEVERITY_ERROR);

  $ev = CIM::Instance->new('NWS_Event', [
                  [ EventType   => lc($cat) . ".LogEvent"  ],
                  [ EventId     => $id ],
                  [ Data        => $log ],
                  [ Caption     => $caption ],
                  [ Target      => lc($cat) . ":" . $keyval],
                  [ TargetName  => $report->id('display')],
                  [ Actionable  => $action],
                  [ SourceIP    => $rep->{'id.ipno'}],
                  [ Severity    => $sev ],
                  [ Description => $desc ] 
                         ]);
   $key = CIM::Key->new( ['NWS_System',
                   'Name'       => $keyval,
                    CreationClassName => 'NWS_System']);
   $sd = Events->sourceDetector({ event => $ev });

   $pertains = CIM::Instance->new('NWS_EventPertainsToSystem', [
                  [ Event       => $ev  ],
                  [ Element     => $key ],
                    ]);

   $ed = Message->new( { id        => $report->id,
                          instances => [$ev, @$sd, $pertains ],
                        });
   $pdm->saveMessage($ed);

   $hm->saveAlert($ev, $sev, $id, $report, $report->id("logFile") . "\n $log", $desc );

   #State->saveState($cat,  $keyval, "alarm.${cat}Log", "Alarm", $sev, $desc, 1, $ev);

   return $ev;
}


# pc = probable cause
# ra = recomm actions

sub linkEvent {
  my($hm, $report, $type1, $key1, $type2, $key2, $desc, $reads, $writes, $hba,
      $fc_type) = @_;

  my($ev, $key, $sd, $pertains, $ed, $ehba);
  my($pdm)   = $hm->{pdm};
  my($id)    =  $pdm->getEventSequence ;
  my $ix = index($key1, ":");
  my $keyval = substr($key1, 0, $ix);
  

  my($e_hba, $k1, $host_hba, $f1, $f2, $f3, $hostid, $link1, $link2);
  my(@hba_list, $node1, $loc);

  $ev = CIM::Instance->new('NWS_Event', [
                  [ EventType   => "san.LinkEvent.$fc_type"  ],
                  [ EventId     => $id ],
                  [ Target      => $key1], 
                  [ TargetName  => $report->id('display')],
                  [ Caption     => "${type1}|$type2" ],
                  [ Actionable  => 1],
                  [ SourceIP    => System->get_ipno() ],
                  [ Description => $desc ],
                  [ Severity    => Message::SEVERITY_WARNING ],
                         ]);

   $sd = Events->sourceDetector({ event => $ev });

   my $system = CIM::Key->new( ['NWS_System',
                   'Name'             => $keyval,
                    CreationClassName => 'NWS_System']);

   $pertains = CIM::Instance->new('NWS_EventPertainsToSystem', [
                  [ Event       => $ev  ],
                  [ Element     => $system ],
                    ]);

   $ed = Message->new({ id        => $report->id,
                        instances =>
                        [$ev, @$sd, @hba_list, $pertains ],
                      });

   $pdm->saveMessage($ed);

   State->saveLinkState($type1, $key1, $type2, $key2, 
         Message::SEVERITY_WARNING, $desc, $reads, $writes, $ev);

   $hm->saveAlert($ev,  Message::SEVERITY_WARNING, $id, $report, "", $desc );

}
  
  
# 2=outoband, 1=inband 3=both

sub connectionEvent {
  my($hm, $keyval, $report, $args) = @_;
  my($key, $ev, $sd, $pertains, $ed, $id, $text, $rc);
  my($cat) = $report->category();
  my($rep) = $report->content();
  my $name = $rep->get('id.name') if ($rep);

  if ($args->{method} == 3) {  # BOTH
    $text = "OutOfBand";

    my($tran, $reps) = Transition->getTransition({      key => $report->deviceName(),
                                         code => 'status',
                                        value => $report->status(),
                             transition_value => Report::STATUS_CANNOT_CONNECT,
                                       repeat => '12h',
                                 });
    $rc = $hm->connection("e", $keyval, $tran, $report, $text, $reps, $args);

    if (defined($rep->{'info.IB_status'})) {  # T3 only so far.
       my $host = $rep->{'info.IB_host'}; 

       $text = "InBand(" . Util->shortHostname($host) . ")";

       my($tran, $reps) = Transition->getTransition( {  key => $report->deviceName(),
                                         code => 'statusIB',
                                        value => $rep->{'info.IB_status'},
                             transition_value => Report::STATUS_CANNOT_CONNECT,
                                       repeat => '12h',
                                       });
       $hm->connection("ib", $keyval, $tran, $report, $text, $reps, $args);
    }
    return $rc;

  } else {
    my $ho = System->hostname();
    my $ei;
    if ($args->{method} == 1) {
       $text = "InBand($ho)";
       $ei = "ib";
    } else {
       $text = "OutOfBand($ho)";
       $ei = "e";
    }

    my($tran, $reps) = Transition->getTransition({      key => $report->deviceName(),
                                         code => 'status',
                                        value => $report->status(),
                             transition_value => Report::STATUS_CANNOT_CONNECT,
                                       repeat => '12h',
                                 });
    return $hm->connection($ei, $keyval, $tran, $report, $text, $reps, $args);
  }

}

sub connection {
  my($hm, $comp, $keyval, $tran, $report, $text, $reps, $args) = @_;
  my($pdm) = $hm->{pdm};
  my($key, $id, $desc);
  my($ev, $sd, $pertains, $ed);
  my($cat) = $report->category();
  my($rep) = $report->content();
  my($name)= $rep->get('id.name') if ($rep);
  my($connect_errs) = $rep->get('id.connect_errs');

  my($id2)  = $report->id('display');

  $key = CIM::Key->new( ['NWS_System',
                   'Name'             => $keyval,
                    CreationClassName => 'NWS_System']);

  return 1 if ($tran eq "LOST");
  my $comp1 = $comp;
  $comp1 = "$comp." . $rep->{'id.caption'} if ($rep && $rep->{'id.caption'});

  if ($tran =~ /IN/) { #lost  or lost-repeat
     return 1 if (!$keyval);  # never had good connection
     return 1 if ($reps > 6);
     $id =  $pdm->getEventSequence;
     my $reboot = "( last reboot was " . System->lastReboot() . ")" 
                 if ($text =~ /InBand/);
     my $repeat = "(lost for " . ($reps*8) . " hours)" if ($reps > 0);
     $desc = "Lost communication ($text) with $cat $id2 $repeat$reboot: " .
             $connect_errs;
     $ev = CIM::Instance->new('NWS_CommunicationLostEvent', [
                  [ EventType   => lc($cat) . ".CommunicationLostEvent"  ],
                  [ EventId     => $id  ],
                  [ Caption     => $comp1 ],
                  [ Description => $desc  ],
                  [ Target      => lc($cat) . ":" . $keyval],
                  [ TargetName  => $report->id('display')],
                  [ Method => $args->{method} ],
                  [ Actionable  => 1],
                  [ SourceIP     => $rep->{'id.ipno'}],
                  [ Severity    => Message::SEVERITY_DOWN],
                  [ Timeout     => 20],
                         ]);
     $sd = Events->sourceDetector({ event => $ev });

     $pertains = CIM::Instance->new('NWS_EventPertainsToSystem', [
                  [ Event       => $ev  ],
                  [ Element     => $key ],
                    ]);

     State->saveState($cat,  $keyval, $comp, $name, 
         Message::SEVERITY_DOWN, "Lost Communication ($text) with $id2", 0, $ev);

     $ed = Message->new( { id        => $report->id,
                            instances => [$ev, @$sd, $pertains ],
                          });
     $pdm->saveMessage($ed);

     $hm->saveAlert($ev,  Message::SEVERITY_DOWN, $id, $report, "", $desc);
     return 1;
  }
  if ($tran eq "OUT") { # can connect
     $desc = "Regained communication($text) with $cat $id2";
     $id =  $pdm->getEventSequence;
     $ev = CIM::Instance->new('NWS_CommunicationEstablishedEvent', [
                  [ EventType   => lc($cat) . ".CommunicationEstablishedEvent"  ],
                  [ EventId     => $id ],
                  [ Description => $desc ],
                  [ Target      => lc($cat) . ":" . $keyval],
                  [ TargetName  => $report->id('display')],
                  [ Caption     => $comp1 ],
                  [ SourceIP     => $rep->{'id.ipno'}],
                  [ Severity    => Message::SEVERITY_GREEN],
                  [ Method      => 1],
                         ]);
     $sd = Events->sourceDetector({ event => $ev });


     $pertains = CIM::Instance->new('NWS_EventPertainsToSystem', [
                  [ Event       => $ev  ],
                  [ Element     => $key ],
                    ]);

     State->saveState($cat,  $keyval, $comp, $name, 
                  Message::SEVERITY_GREEN, "Regained Communication ($text)", 1, $ev);

     $ed = Message->new( { id        => $report->id,
                            instances => [$ev, @$sd, $pertains ],
                            });

     $pdm->saveMessage($ed);

     $hm->saveAlert($ev,  Message::SEVERITY_WARNING, $id, $report,"",$desc);
  }
  return 0;  # keep going
}

#
# returns availability-state of the device (old,new, description) :
#    returns (1/0, 1/0, "Old=..., New=...");

sub status {
   croak("Health::status is abstract, must implement in device Health");
}

#
# arg = {logical => 1, descIsValue=> 1}
#
sub stateEvent {
  my($hm, $component, $report,  $rep, $orep, $cim1, $nserial, $keyval, $arg) = @_;
  my($key, $ev, $sd, $pertains, $ed , $id);
  my($ovalue, $nvalue, $old, $new) = $hm->status($rep, $orep, $component);
  if (System->get_bad_health()) {
      $nvalue = "BAD"; $new = 0;
  }
  my $name   = $rep->get('id.name');
  my $data   = "";
  my $ix     = index($component, ".");
  my $id2    = $report->id('display');
  my $error  = 0;
  my $cat    = $report->category();
  my $catcap = uc($cat);
  my $mgmtLevel = $report->value('id.mgmtLevel') || 'D';

  my($comp0) = $component;
   if ($ovalue ne $nvalue || ($rep == $orep && !$new) ) { # availability change or new report  and unavailable
         my($newval); 
         if ($new eq "X") {
            $newval = "Unknown";
         } else {
            $newval = ($new)?"Available":"Not-Available";
         }
         if ($rep == $orep) {
            $old = 1;
            $ovalue = "unknown";
         }
         $id =  PDM->getEventSequence;
         my $xx = (index($component, $nserial) < 0) ? "($nserial) ":" ";
         my($desc);
         if ($arg->{descIsValue}) {
            $desc = "'$component'${xx}in $catcap $id2 is now $newval: $nvalue";
         } else {
            $desc = "'$component'${xx}in $catcap $id2 is now $newval (state changed from '$ovalue' to '$nvalue'):";
         }

         if (!$nserial) {
             $arg->{noState} = 1;
             my $ev0 = $hm->alarmEvent("", $report, $keyval, $desc, undef,"$cat.$component", $arg);
             if ($new != 1) { #  bad comp
                State->saveState($cat,  $keyval, $component, $name, Message::SEVERITY_ERROR, $desc, $new, $ev0);
                 $error++;
             } else {
                State->saveState($cat,  $keyval, $component, $name, Message::SEVERITY_GREEN, $desc, $new, $ev0);
             }
             return $error;
         }
         $old = 0 if ($old eq "X");
         my $yellow;
         my $sign = "X";
         if ($new eq "X") {
            $new = $old;
            $yellow =1;
         }
         my ($severity, $action);
         if (!$new) { #  bad comp
           $severity = Message::SEVERITY_ERROR;
           $action = 1;
           $sign = "M";
           $error++;
         } elsif ($yellow) {
           $severity = Message::SEVERITY_ERROR;
           $action = 1;
           $error++;
         } else {
           $severity = Message::SEVERITY_GREEN;
           $action = 0;
           $sign = "P";
         }
         $ev = CIM::Instance->new('NWS_StateChangeEvent', [
             [ EventType    => lc($cat) . ".StateChangeEvent"   ],
             [ EventId      => $id ],
             [ PriorState   => $old],
             [ CurrentState => $new],
             [ MgmtLevel    => $mgmtLevel ],
             [ PriorValue   => $ovalue],
             [ CurrentValue => $nvalue],
             [ Actionable   => $action  ],
             [ Caption      => "$sign.$comp0"],
             [ Severity    => $severity ],
             [ Description  => $desc ],
             [ Target       => lc($cat) . ":" . $keyval],
             [ TargetName  => $report->id('display')],
             [ Data         => $data],
             [ SourceIP     => $rep->{'id.ipno'}],
                    ]);

         $sd = Events->sourceDetector({ event => $ev });

         $key = CIM::Key->new( [$cim1,
                  Tag               => $nserial,
                  CreationClassName => $cim1]);

         $pertains = CIM::Instance->new(
                $arg->{logical} ? 'NWS_EventPertainsToLogicalDevice': 
                                  'NWS_EventPertainsToPhysicalElement', [
             [ Event       => $ev  ],
             [ Element     => $key ],
               ]);

         $ed = Message->new( { id        => $report->id,
                       instances => [$ev, @$sd, $pertains ],
                       });

         PDM->saveMessage($ed);
         State->saveState($cat,  $keyval, $component, $name, $severity, $desc, $new, $ev);
         $hm->saveAlert($ev,  $severity, $id, $report, "", $desc);

   }
   my $time_id = "$component.statusTime";
   $rep->{$time_id} = $orep->{$time_id};

   return $error;

}

# old/new are severities, ovalue and nvalue are descriptions
# new=1 (warning) new=2 (error) etc..

sub sevStateEvent {
  my($hm, $component, $report,  $rep, $orep, $cim1, $nserial, $keyval, $arg) = @_;
  my($key, $ev, $sd, $pertains, $ed , $id);

  my($ovalue, $nvalue, $old, $new, $oavail, $navail) = $hm->status($rep, $orep, $component);

  my $name   = $rep->get('id.name');
  my $data   = "";
  my $ix     = index($component, ".");
  my $id2    = $report->id('display');
  my $error  = 0;
  my $cat    = $report->category();
  my $catcap = uc($cat);
  my $mgmtLevel = $report->value('id.mgmtLevel') || 'D';
  my $sign   = $navail eq "X" ? "X" : ($navail == 1 ? "P": "M");
  my($comp0) = $component;

  if ($ovalue ne $nvalue || ($rep == $orep && $new) ) { # availability change or new report  and unavailable
         $id =  PDM->getEventSequence;
         my $nvalue2 = $nvalue;
         $nvalue2 = substr($nvalue2,15) if ($nvalue2 =~ /\d\d\-\d\d/);
         my $desc = "$arg->{label} $catcap-$id2: $nvalue2";

         $ev = CIM::Instance->new('NWS_StateChangeEvent', [
             [ EventType    => lc($cat) . ".StateChangeEvent"   ],
             [ EventId      => $id ],
             [ PriorState   => "$oavail"],
             [ CurrentState => "$navail"],
             [ MgmtLevel    => $mgmtLevel ],
             [ PriorValue   => $ovalue],
             [ CurrentValue => $nvalue],
             [ Actionable   => ($new > 1)  ],
             [ Caption      => "$sign.$comp0"],
             [ Severity     => $new],
             [ Description  => $desc ],
             [ Target       => lc($cat) . ":" . $keyval],
             [ TargetName  => $report->id('display')],
             [ Data         => $data],
             [ SourceIP     => $rep->{'id.ipno'}],
             [ OriginalEvent => $rep->{"$component.status-details"}],
                    ]);

         $sd = Events->sourceDetector({ event => $ev });

         if ($arg->{logical}) {              # logical (like NWS_Slot,
           $key = CIM::Key->new( [$cim1,    
                  CreationClassName => $cim1, 
                  SystemName        => $rep->{'id.wwn'} . "." . $component,
                  DeviceID          => $nserial 
                  ]);
         } else {
           $key = CIM::Key->new( [$cim1,    # physical (like NWS_PhysicalPackage)
                  Tag               => $nserial,
                  CreationClassName => $cim1
                  ]);
         }

         $pertains = CIM::Instance->new(
                $arg->{logical} ? 'NWS_EventPertainsToLogicalDevice': 
                                  'NWS_EventPertainsToPhysicalElement', [
             [ Event       => $ev  ],
             [ Element     => $key ],
               ]);

         $ed = Message->new( { id => $report->id,
                        instances => [$ev, @$sd, $pertains ], });

         PDM->saveMessage($ed);
         State->saveState($cat,  $keyval, $component, $name, $new, $desc, $navail, $ev);
         $hm->saveAlert($ev,  $new, $id, $report, "", $desc);

   }
   my $time_id = "$component.statusTime";
   $rep->{$time_id} = $orep->{$time_id};

   return $error;

}

sub removeCompEvent {
  my($hm, $component, $pf, $report,  $cim1, $oserial, $keyval, $arg) = @_;
  
  my($key, $ev, $sd, $pertains, $ed, $contain);
  my($pdm) = $hm->{pdm};
  my $extra_desc = $arg->{desc};
  my($cat) = $report->category();
  my $mgmtLevel = $report->value('id.mgmtLevel') || 'D';

  my($ix) = index($component, ".");
  my($comp0) = $component;

  my($id)  =  $pdm->getEventSequence;
  my($rep) = $report->content();
  my($name)= $rep->get('id.name') if ($rep);
  my($comp1) = $component;
  $comp1  = "" if (index($oserial, $component) >= 0);
  my($id2) = $report->id('display');

  my($desc) = "$comp1($oserial) was removed from $id2 $extra_desc";
  $ev = CIM::Instance->new('NWS_Event', [
             [ EventType   => lc($cat) . ".TopologyEvent"  ],
             [ Caption     => "remove.$comp0"],
             [ Description => $desc ],
             [ MgmtLevel    => $mgmtLevel ],
             [ Actionable   => 1     ],
             [ Severity    => Message::SEVERITY_ERROR ],
             [ SourceIP     => $rep->{'id.ipno'}],
             [ Target      => lc($cat) . ":" . $keyval],
             [ TargetName  => $report->id('display')],
             [ EventId     => $id ]]);

   $sd = Events->sourceDetector({ event => $ev });

   $key = CIM::Key->new( [$cim1,   # key of the disk
                  Tag               => $oserial,
                  CreationClassName => $cim1]);

   $contain = CIM::Instance->new( 'CIM_Container', [
                  [GroupComponent => $pf],            # frame is a package
                  [PartComponent  => $key],           # package is an element
                  [LocationWithinContainer => $component],
                   ]);

   $pertains = CIM::Instance->new('NWS_EventPertainsToContainer', [
                  [Event          => $ev   ],
                  [Association    => $contain ],
                  [DiscoveryType => "D"   ],   # delete
               ]);

   State->saveState($cat,  $keyval, $component, $name, Message::SEVERITY_ERROR, $desc, 0, $ev);

   $ed = Message->new( { id        => $report->id,
                       instances => [$ev, @$sd, $contain, $pertains ],
                       severity  => Message::SEVERITY_ERROR});

   $pdm->saveMessage($ed);
   $hm->saveAlert($ev,  Message::SEVERITY_ERROR, $id, $report, "",$desc);
}

sub insertCompEvent {
  my($hm, $component, $pf, $report, $part, $nserial, $keyval, $arg) = @_;
  my($key, $ev, $sd, $pertains, $ed, $contain, $pertains2);

  my($pdm) = $hm->{pdm};
  my($cat) = $report->category();
  my $extra_desc = $arg->{desc};

  my($ix) = index($component, ".");
  my($comp0) = $component;
  my $mgmtLevel = $report->value('id.mgmtLevel') || 'D';

  my($rep) = $report->content();
  my($name)= $rep->get('id.name') if ($rep);

  my($id) =  $pdm->getEventSequence;
  my($id2) = $report->id('display');

  my($comp1) = $component;
  $comp1  = "" if (index($nserial, $component) >= 0);

  my($desc) = "$comp1($nserial) was added to $id2 $extra_desc";

  $ev = CIM::Instance->new('NWS_Event', [  
             [ EventType   => lc($cat) . ".TopologyEvent"  ],
             [ Caption     => "add.$comp0"],
             [ Description => $desc ],
             [ MgmtLevel    => $mgmtLevel ],
             [ Target      => lc($cat) . ":" . $keyval],
             [ TargetName  => $report->id('display')],
             [ Severity    => Message::SEVERITY_NORMAL ],
             [ SourceIP     => $rep->{'id.ipno'}],
             [ EventId     => $id ]]);

  $sd = Events->sourceDetector({ event => $ev });

  $pertains = CIM::Instance->new('NWS_EventPertainsToPhysicalElement', [
             [ Event       => $ev  ],
             [ Element     => $part->[1]],
               ]);

  $contain = CIM::Instance->new('CIM_Container', [
              [GroupComponent           => $pf],         #PhysicalFrame
              [PartComponent            => $part->[1]],
              [LocationWithinContainer  => $component],
               ]);

  $pertains2 = CIM::Instance->new('NWS_EventPertainsToContainer', [
              [Event                    => $ev],
              [Association             => $contain  ],
              [DiscoveryType            => "A"       ],
               ]);

  State->saveState($cat,  $keyval, $component, $name, Message::SEVERITY_NORMAL, $desc, 1, $ev);

  $ed = Message->new( { id        => $report->id,
                       instances => [$ev, @$sd, @$part, $pertains , $contain, $pertains2],
                       severity  => Message::SEVERITY_ERROR});

  $pdm->saveMessage($ed);
  $hm->saveAlert($ev,  Message::SEVERITY_WARNING, $id, $report, "", $desc);
}

1;
