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

#  $Name: bld21_017 $ 
#  $Id: Switch.pm,v 1.8 2005/04/20 17:23:33 sbrooks Exp $


use base 'Health';
use NWS::Switch;
use Ilist;
use Message;
use Report;
use Catalog;
use Events;
use strict;
use Debug;

sub revision {'$Revision: 1.8 $'}


sub all_logic {
  my($hm, $report) = @_;
  my($ev, $ed, $pertains, $x ,$y, $contain, $sd);
  my($orep, $key);
  my($rep)     = $report->content;
  my($oreport) = PDM->getOldReport($report->fileKey);
  my($ip)      = $report->id('ip');
  my($name)    = $report->name;
  my $wwn      = $report->id('deviceName');
  my($id)      = $report->id('display');
  my($log)     = $report->log();
  my $mgmtLevel = $report->value('id.mgmtLevel') || 'D';
  if (!$wwn) {
    Debug->errNoRepeat(T3_NO_KEY => $ip, 24, "Switch ($name/$ip) cannot be identified");
     return;
  }

  CIM->version("1.1");
  $DB::single = 1;

  return if ($hm->connectionEvent($wwn, $report, {method => 2, threshold_severity => 1} ));
  my $freq  = System->get_renv()->{audit_freq} || 7;
  my $audit = System->get_audit() ? "YES" : Timer->isXdays("Audit$wwn", $freq);

  if (!$oreport || $audit eq "YES" ) {  # new t300 or audit time.
     my($etype) = $audit eq "YES" ? "switch.AuditEvent" : "switch.DiscoveryEvent";
     my($title) = $audit eq "YES" ? "Auditing a":"Discovered a new";
     my($dt)    = "A" if (!$audit);
     Grid->setCode($etype);
     $ev = CIM::Instance->new('NWS_Event', [
                  [ EventType   => $etype ],
                  [ EventId     => PDM->getEventSequence  ],
                  [ Target      => "switch:$wwn" ],
                  [ TargetName  => $id],
                  [ SourceIP    => $ip  ],
                  [ MgmtLevel   => $mgmtLevel],
                  [ Description => "$title Switch called $id"],
                  [ Data        => $hm->serial($rep) ],
                         ]);

     $sd = Events->sourceDetector({ event => $ev , host => 1, rep => $rep});
      
     my($p) = NWS::Switch->newSystem($rep);

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

     my($monitors) = CIM::Instance->new('NWS_AgentMonitors', [
                  [ Agent       => $sd->[0]  ],
                  [ Element     => $p->[0] ],
                    ]);

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

     PDM->saveMessage($ed);
     if ($audit) {  # dump stats.

        Grid->setCode("switch.Statistics");
        $ev = CIM::Instance->new('NWS_Event', [
                  [ EventType   => 'switch.Statistics'  ],
                  [ EventId     => PDM->getEventSequence  ],
                  [ Target      => "switch:$wwn" ],
                  [ TargetName  => $id  ],
                  [ SourceIP    => $ip  ],
                  [ MgmtLevel   => $mgmtLevel],
                  [ Description => "Statistics about Switch $id :"],
                  [ Data        => Util->nnl($rep->toStringP('port.\d+.stats'))],
                         ]);

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

        my($system_key) = CIM::Key->new( ['NWS_System', 
                    'Name'            =>$rep->get('id.wwn'), 
                    CreationClassName => 'NWS_System']);

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

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

        PDM->saveMessage($ed);

     }
  }
  $orep = ($oreport)? $oreport->content() : $rep;

  foreach my $el ('fan.1', 'fan.2', 'power', 'temp') {

      if ($el =~ /fan/) {
        Grid->setCode("switch.AlarmEvent.fan");
      } elsif ($el eq "power") {
        Grid->setCode("switch.AlarmEvent.power");
      } else {
        Grid->setCode("switch.AlarmEvent.temperature");
      }

      $hm->mapValueChangeEvent($report, $orep, "SWITCH", "chassis.$el", "status", $id, $id, $wwn, "$el.status");
      #my $s2 = $orep? $orep->get("chassis.$el.status") : "";
      #my $s1 = $rep->get("chassis.$el.status");

  }
  return if (!$oreport);

  # FC-COUNTERS
  $hm->fcEvent($rep->{FC_COUNTERS}, $orep->{FC_COUNTERS});

  my $uptime = $rep->get("chassis.uptime");
  my $ouptime = $orep->get("chassis.uptime");
  if ($uptime < $ouptime) {
     if($ouptime < 4286304000){
       # this isn't within a day of a counter wrap so report change
       Grid->setCode("switch.AlarmEvent.system_reboot");
       $hm->valueChangeEvent("chassis.uptime", "", $report, $wwn, "Switch uptime decreased on $id from $ouptime to $uptime", 1, "system_reboot");
     }
  }

  $hm->locationChangeEvent($report, $rep, $orep, $wwn);

  my($physicalFrame) = CIM::Key->new( ['CIM_PhysicalFrame',   # key of the frame
                        Tag               => $rep->get("id.wwn") ,
                        CreationClassName => 'CIM_PhysicalFrame' ]);

  my($PORTS) = $rep->get('version.ports');


# check if port state has changed

  my($comp);

  for ($x=1; $x <= $PORTS; $x++) {
     $comp = "port.$x"; # . sprintf("%3.3d", $x);
     Grid->setCode("switch.StateChangeEvent.port");
     my $extra;
     if (exists $rep->{"port.$x.admin"}) {
        $extra = "Admin-Status is '" . $rep->{"port.$x.admin"} . "' use to be '" . $orep->{"port.$x.admin"} . "'";
     }
     $hm->stateChangeEvent($comp, 'status', $report, $rep, $orep, 'CIM_Card', "$wwn.$comp", $wwn, 
          {info => $extra } );
  }
#
#  generate events for the important counters 
#
  my($data);
  my($rep1) = $rep->subset("ASIC");
  foreach my $k (keys %$rep1) {
    if (defined($orep->{"ASIC.$k"})) {
       my $diff =  $rep->{"ASIC.$k"}  - $orep->{"ASIC.$k"};
       if ($diff > 0) {
          $data .= "ASIC.$k increments by $diff\n";
       }
    }
  }

  Grid->setCode("switch.AlarmEvent.port.statistics");
  $hm->portStatEvents($report, $PORTS, $rep, $orep);

  my($ozone, $nzone) ;
  my($oZ) = $orep->subset("zone");
  my($nZ) = $rep->subset("zone");

  foreach my $x (keys %$oZ) {
    next if ($x eq "total");
    my $v = $oZ->{$x}; 
    chop($v) if (substr($v,-1) eq " ");
    $v =~ s/ /,/g;
    $ozone .= substr($x,0,-8) . "=($v) ";
  }
  foreach my $x (keys %$nZ) {
    next if ($x eq "total");
    my $v = $nZ->{$x}; 
    chop($v) if (substr($v,-1) eq " ");
    $v =~ s/ /,/g;
    $nzone .= substr($x,0,-8) . "=($v) ";
  }

  chop($ozone) if ($ozone);
  chop($nzone) if ($nzone);

  if ($ozone && $nzone && ($ozone ne $nzone)) { 
       my($desc) = "Switch $id was rezoned: [$nzone] ";
       Grid->setCode("switch.AlarmEvent.zone");
       $hm->valueChangeEvent("zone", "", $report, $wwn, $desc, 1, "zone_change");

     if (0) {  # ned to be turned on
       my($eid, $ev, $sd);
       $eid  =  PDM->getEventSequence;
       $ev = CIM::Instance->new('NWS_Event', [
             [ EventType   => "switch.TopologyEvent"  ],
             [ Caption     => "zone-new"],
             [ MgmtLevel   => $mgmtLevel],
             [ Description => $desc ],
             [ EventId     => $eid ]]);

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

       my($switch) = CIM::Key->new( ['NWS_System', 
                    'Name'            =>$rep->get('id.wwn'), 
                    CreationClassName => 'NWS_System']);

       my($zones) = NWS::Switch->zones($rep, $switch);

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

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

       PDM->saveMessage($ed);
    }

  }
}

sub status {
   my($hm, $rep, $orep, $comp) = @_;
   my($map) = PDM->getDeviceStateMap("switch.availability");
   my($status, $ostatus, $admin, $oadmin, $old, $new, $sev, $act);

   if (substr($comp, 0, 7) eq "chassis") {
      $ostatus = $orep->getState("$comp.status");
      $status  = $rep->getState("$comp.status");
      ($old, $new, $sev, $act) = $map->transition("status.$ostatus", "status.$status", $orep, $rep);

   } else {
      $ostatus = $orep->getState("$comp.mode");
      $oadmin =  $orep->getState("$comp.admin");


      if (!$rep->{"$comp.mode"}) {
         $rep->{"$comp.mode"} = $orep->{"$comp.mode"};
      }
      if (!$rep->{"$comp.admin"}) {
         $rep->{"$comp.admin"} = $orep->{"$comp.admin"};
      } 
      $status  = $rep->getState("$comp.mode");
      $admin = $rep->getState("$comp.admin");

      ($old, $new, $sev, $act) = $map->transition("mode.${ostatus}_${oadmin}", "mode.${status}_${admin}", $orep, $rep);
   }

   return ($ostatus, $status, $old, $new, $sev, $act );

}


# statiuc method
# return status-state and 0/1
# port.001
# port.002
# ...
# port.016

sub compStatus {
   my($hm, $rep, $orep, $comp) = @_;

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

   my($status) = $rep->get("$comp.mode");
   my($admin) =  $rep->get("$comp.admin");


   my($new) = $map->get("mode.${status}_${admin}");

   $status  = "UNKNOWN" if (!$status);

   return ( $status, $new );

}




1;

