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

#Name:  $
#  $Id: 3310.pm,v 1.43 2006/02/28 22:55:47 zhangy Exp $


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

sub revision {'$Revision: 1.43 $'}

#####################################################

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');
  $DB::single = 1;
  my $wwn      = $report->id('deviceName');
  my($id)      = $report->id('display');
  my($shortid) = $report->name();
  my($log)     = $report->log();
  my($renv)    = System->get_renv();
  my $mgmtLevel = $report->value('id.mgmtLevel') || 'D';
  my $path     = $report->value("id.device_path");
  my $type     = $report->id('category');

  CIM->version("1.1");

  if ($hm->connectionEvent($wwn, $report, {method => ($path ? 1:3), threshold_severity => 1} )) {  # IB / OOB
     return;
  }
  my($tran, $reps) = Transition->getTransition({ key => $report->deviceName(),
                                         code => 'ethernet',
                                        value => $report->value("info.ethernet_status"),
                             transition_value => "ping_failed",
                                       repeat => '12h',
                                 });
  $hm->connection("ethernet", $wwn, $tran, $report, "Ethernet", $reps, 
                         {connect_errs => $report->value("info.ethernet_errs"),
                                method => 2});

  my $freq = $renv->{audit_freq} || 7;
  my $audit = System->get_audit() ? "YES" : Timer->isXdays("Audit$wwn", $freq);

  if (!$oreport || $audit eq "YES" ) {  # new minnow device or audit time.
     my($etype) = $audit eq "YES" ? "$type.AuditEvent" : "$type.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  ],
                  [ Target      => "$type:$wwn"    ],
                  [ TargetName  => $id     ],
                  [ SourceIP    => $ip     ],
                  [ MgmtLevel   => $mgmtLevel ],
                  [ EventId     => PDM->getEventSequence  ],
                  [ Description => "$title $type called $id"],
                  [ Data        => $hm->serial($rep) ],
                         ]);

     $sd = Events->sourceDetector({ event => $ev , host => 1, rep => $rep});
      
     my($p) = NWS::3310->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);
  }

  $orep = ($oreport)? $oreport->content() : $rep; # same report if new disco.

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

  if ( $rep->{'info.Product'} =~ /3510/ ) {
       $hm->fcEvent($rep->{FC_COUNTERS}, $orep->{FC_COUNTERS});
  }
  elsif ( $rep->{'info.Product'} =~ /3511/ ) {
       $hm->fcEvent($rep->{FC_COUNTERS}, $orep->{FC_COUNTERS});
  }
  my($physicalFrame) = CIM::Key->new( ['CIM_PhysicalFrame',   # key of the frame
                        Tag               => $rep->get("id.key") ,
                        CreationClassName => 'CIM_PhysicalFrame' ]);

  my $enc_status = $rep->get("info.status");
  my $oenc_status = $orep->get("info.status");
  my $argin;
  $argin->{old_status} = $oenc_status;
  $argin->{new_status} = $enc_status;

  if ($enc_status && $oenc_status) {
    Grid->setCode("$type.ValueChangeEvent.enclosure");  # firmware_version, revision
    $hm->alarm($report, $orep, $type, "info", "status", $shortid, $id, $wwn, "enclosure.status",$argin);
  }


  # Check counter values
  Grid->setCode("$type.ValueChangeEvent.port.statistics");
  $hm->portStatEvents($report, 7, $rep, $orep, "channel");

  # my $dn = $rep->get("info.total_disk");
  my $dn = $rep->get("info.top_disk");
  Grid->setCode("$type.ValueChangeEvent.disk.statistics");
  $hm->portStatEvents($report, $dn, $rep, $orep, "components.disk", {info => 'serial_number'} );


# BATTERY EXPIRED
#
#  'battery_status.1.expiration_date' => 'Sat Feb 11 09:25:26 2006'
#  'battery_status.1.exp_status        => '' | 'W' | 'E';

  if ( ($rep->{'info.Product'} =~ /3510/ ) || ( $rep->{'info.Product'} =~ /3511/ )) {
   for ($x=1; $x <= 2; $x++) {
      my $expired    = $rep->{"battery_status.$x.expiration_date"};
      
      my($exp_day0, $exp_mth, $exp_day, $exp_time, $exp_year) = split(/\s+/, $expired);
      my $exp_jd     = Util->julian($exp_year, $Util::MTH{$exp_mth}, $exp_day);

      my $today_jd   = Util->get_today_jd();  
      my $days       = $exp_jd - $today_jd;
      $rep->{"battery_status.$x.exp_status"} = $orep->{"battery_status.$x.exp_status"};
      my $st         =  $rep->{"battery_status.$x.exp_status"};
      my $bat_name   =  $rep->{"battery_status.$x.name"};

      if ($st && $days > 60) {
         $rep->{"battery_status.$x.exp_status"} = "";
      }
      if (!$st && $days <= 60 && $days >=0) {
         Grid->setCode("$type.ValueChangeEvent.battery_expiredW");  # firmware_version, revision
         my $desc = "The $bat_name of $type $id is $days days from expiration";
         $rep->{"battery_status.$x.exp_status"} = "W";
         $hm->alarmEvent("battery.$x", "", $report, $wwn, $desc, undef, "expirationWarning");
         
      } elsif ($st eq "W" && $days <= 30 && $days >=0) {
         Grid->setCode("$type.ValueChangeEvent.battery_expiredE");  # firmware_version, revision
         my $desc = "The $bat_name of $type $id is $days days from expiration";
         $rep->{"battery_status.$x.exp_status"} = "E";
         $hm->alarmEvent("battery.$x", "", $report, $wwn, $desc, undef, "expirationError");

      } elsif (!$st && $days <0) {
         Grid->setCode("$type.ValueChangeEvent.MissingBatteryError");
         my $desc = "Can not obtain the information of $bat_name of $type $id.";
         $rep->{"battery_status.$x.exp_status"} = "E";
         $hm->alarmEvent("battery.$x", "", $report, $wwn, $desc, undef, "MissingBatteryError");
      } 
   }
 }

###########
# INFO
###########
    for my $e ('firmware_version','Revision', 'id_of_nvram_defaults', 
               'bootrecord_version') {
      my $e0 = lc($e);
      my $ofirm = $orep->{"info.$e"};
      my $nfirm = $rep->{"info.$e"};
      if ($ofirm && $nfirm && ($ofirm ne $nfirm)) {
         if ($hm->normalize_check($ofirm, $nfirm)) {
            Grid->setCode("$type.ValueChangeEvent.$e0");  # firmware_version, revision
            $hm->alarmEvent("info.$e","",$report, $wwn,
                   "$id: $e changed from '$ofirm' to '$nfirm'", undef, $e0);
         }
      }
    }

###########
# CHANNELS
###########
    for ($y=1; $y <= 20; $y++) {
      last if ($report->content()==$orep);  # skip if this is the first time discovery
      my $comp = "channel.$y.curwid";
      if ($orep->{$comp} && !$rep->{$comp}) {
          Grid->setCode("$type.ValueChangeEvent.channel");
          my $desc = "Channel " . $orep->{"channel.$y.idx"} . " is missing";
          $hm->alarmEvent($comp,"",$report,$wwn,"$id: $desc", undef, "channel");
      }

      my $comp2 = "channel.$y";

      next if (!( $rep->{"$comp2.mode"}) && !($orep->{"$comp2.mode"}));
      
      my $nmode= $rep->get("$comp2.mode");
      my $omode = $orep->get("$comp2.mode");
      my $argin;
      $argin->{old_status} = $omode;
      $argin->{new_status} = $nmode;

      Grid->setCode("$type.ValueChangeEvent.channel_mode");
     $hm->mapValueChangeEvent($report, $orep, $type, $comp2, "mode", $shortid, $id, $wwn, "channel.mode",$argin);

      
    }

#############
# ICL check
#############
   my $dtype = $rep->{'id.device_type'};
 if ($dtype =~/3510/) {
  for ($x = 1; $x<=2; $x++) {
   my $pos;
   if ($x ==1) {
      $pos = "lower_channel";
   } else {
      $pos = "upper_channel";
   }
   for ($y=0; $y <= 5; $y++) {
       last if ($report->content()==$orep);  # skip for the first time discovery
       my $field = "ICL";
       my $comp = $field.$pos.$y;
       my $comp_type = $rep->get("$field.type"); # inter-controller-link
        $comp_type =~ s/-/_/;
       next if (!$comp_type);
       Grid->setCode("$type.ValueChangeEvent.$comp_type");
       my $nstatus = $rep->get("$comp.icl_status");
       my $ostatus = $orep->get("$comp.icl_status");
        my $argin;
      $argin->{old_status} = $ostatus;
      $argin->{new_status} = $nstatus;
      $hm->mapValueChangeEvent($report, $orep, $type, $comp, "icl_status", $shortid, $id, $wwn, "ICL.icl_status",$argin);

   }
 }
 }
############
# components
############
  for ($x =1; $x<=8; $x++) { # deal with up to 7 extension box  
    for ($y=1; $y <= 50; $y++) {
      my $comp = "enclosure.$x.component.$y";
      my $comp_type = $rep->get("$comp.type"); #  'diskslot', 'emu', 'fan', 'ps', 'temp',
      next if (!$comp_type);
      my $comp_unit = $rep->get("$comp.unit"); 
      my $sn = $rep->get("$comp.fru-pn") . "/" . $rep->get("$comp.fru-sn");

      Grid->setCode("$type.ValueChangeEvent.$comp_type");
      my $nstatus = $rep->get("$comp.status");
      my $ostatus = $orep->get("$comp.status");
      my $argin;
      $argin->{old_status} = $ostatus;
      $argin->{new_status} = $nstatus;

      if (($report->content() == $orep) && ($nstatus =~ /Absent/i)) {
        # do not create event for first time discovery
        # as some component such as disk slot in absent state is OK
        next;   # do not create event
      } else { 
         $argin->{el_info} = "$comp_type-$comp_unit";
         $hm->mapValueChangeEvent($report, $orep, $type, $comp, "status", $shortid, $id, 
                 $wwn, "component.status", $argin);

         if ( $comp_type =~ /temp/) {
            Grid->setCode("$type.ValueChangeEvent.temperature");
            $hm->tempEvent($report, $orep, uc($type), $comp, "temp",
                         $shortid, $id, $wwn, 54, 51,
                         { comp_info => $sn } );  # high_temp, low_temp
         }
      }
    }
  }
###############################
# shut down primary controller
###############################
  if (($dtype =~ /3510/) || ($dtype =~ /3511/) 
      || (( $dtype =~ /3320/) && ( $dtype != /jbod/ ))
      || (( $dtype =~ /3310/) && ( $dtype != /jbod/ ))) {
    foreach my $el (keys %$rep) {
      next if ($el !~ /controller_shutdown_status/);
      my $comp = "array";
      my $comp_type = $rep->get("$comp.type");
      next if (!$comp_type);
      Grid->setCode("$type.ValueChangeEvent.$comp_type");

      my $nstatus = $rep->get("$comp.controller_shutdown_status");
      my $ostatus = $orep->get("$comp.controller_shutdown_status");
      my $argin;
      $argin->{old_status} = $ostatus;
      $argin->{new_status} = $nstatus;


     $hm->mapValueChangeEvent($report, $orep, $type, $comp, "controller_shutdown_status", $shortid, $id,
                 $wwn, "array.controller_shutdown_status", $argin);

   }
  }

###########
# safte 
###########
  if (!(($dtype =~ /3510/) || ($dtype =~ /3511/))) {
    foreach my $el (keys %$rep) {
      next if ($el !~ /safte\.status/);
      my $comp = "safte";
      my $comp_type = $rep->get("$comp.type");
      next if (!$comp_type);
      Grid->setCode("$type.ValueChangeEvent.$comp_type");
       
      my $nstatus = $rep->get("$comp.status");
      my $ostatus = $orep->get("$comp.status");
      my $argin;
      $argin->{old_status} = $ostatus;
      $argin->{new_status} = $nstatus;


     $hm->mapValueChangeEvent($report, $orep, $type, $comp, "status", $shortid, $id,
                 $wwn, "component.status", $argin);
 
   } 
  }

###################
# redundant status
##################
  if (($dtype =~ /3510/) || ($dtype =~ /3511/) 
      || (( $dtype =~ /3320/) && ( $dtype != /jbod/ ))
      || (( $dtype =~ /3310/) && ( $dtype != /jbod/ ))) {
    foreach my $el (keys %$rep) {
      next if ($el !~ /controller_redundancy_status/);
      my $comp = "enclosure";
      my $comp_type = $rep->get("$comp.type");
      next if (!$comp_type);
      Grid->setCode("$type.ValueChangeEvent.$comp_type");

      my $nstatus = $rep->get("$comp.controller_redundancy_status");
      my $ostatus = $orep->get("$comp.controller_redundancy_status");
      my $argin;
      $argin->{old_status} = $ostatus;
      $argin->{new_status} = $nstatus;


     $hm->mapValueChangeEvent($report, $orep, $type, $comp, "controller_redundancy_status", $shortid, $id,
                 $wwn, "enclosure.controller_redundancy_status", $argin);

   }
  }



###########
# FRUS
###########

   foreach my $e (keys %$orep) {
      next if ($e !~ /fru\.(\w+)\.name/);         
      my $comp = "fru.$1";
      if (!exists $rep->{"$comp.name"}) {
          my $grid_code = $orep->{"$comp.name"};
          Grid->setCode("$type.ComponentRemoveEvent.$grid_code");
          my $comp_info = NWS::3310->fruKey($orep, $comp);
           my $name = $orep->get("$comp.name");
           my $location = $orep->get("$comp.fru_location");
          my $info = $comp_info."(".$name." at ".$location.")";
          $hm->removeCompEvent($comp,$physicalFrame,$report, $orep, 'CIM_PhysicalPackage',
                               $comp_info, $wwn, { comp_info => $info });
      }
   }

   foreach my $e (keys %$rep) {
      next if ($e !~ /fru\.(\w+)\.name/);
      my $comp = "fru.$1";
      next if (!exists($rep->{"$comp.name"}) && !exists($orep->{"$comp.name"}));
      my $grid_code = $rep->{"$comp.name"};

      if (!exists($orep->{"$comp.name"})) {
         my $part = NWS::3310->newFru($rep, $comp);
         my $name = $rep->get("$comp.name");
          my $location = $rep->get("$comp.fru_location");
          my $info = $name." at ".$location;
         Grid->setCode("$type.ComponentInsertEvent.$grid_code");
         $hm->insertCompEvent($comp,$physicalFrame, $report, $orep, $part, "$wwn", 
                   $wwn, {comp_info => $info });

      } else {
         Grid->setCode("$type.ValueChangeEvent.fru_status");
         my  $inarg;
         $inarg->{comp_info} = $rep->get("$comp.name")."(".$rep->get("$comp.serial_number").")"; 
         $hm->mapValueChangeEvent($report, $orep, $type, $comp, "fru_status", $shortid, $id, $wwn, "fru.status", $inarg);
      }
      $hm->check_rev($orep, $rep, $report, $wwn, $id, $comp, "revision",
                            $rep->{"$comp.description"} );

   }


 
###########
# DISKS 
###########
    my $topdisk = $rep->get('info.top_disk');
    for ($y=0; $y <= $topdisk; $y++) {
        my $comp = "components.disk.$y";
        my $comp_info = "CH". $rep->get("$comp.ch") . " ID$y";
        my $oserial = NWS::3310->getKey($orep, $comp); 
        my $nserial = NWS::3310->getKey($rep, $comp);  
        next if (!$oserial && !$nserial);

        if ($oserial eq $nserial) {
           Grid->setCode("$type.ValueChangeEvent.disk");
           $hm->stateChangeEvent($comp, 'disk_status', $report, $rep, $orep, 'CIM_PhysicalPackage', 
                 $nserial, $wwn, { comp_info => $comp_info} );

        } else {
           if ($oserial) {
             Grid->setCode("$type.ComponentRemoveEvent.disk");
             $hm->removeCompEvent($comp,$physicalFrame,$report, $orep, 'CIM_PhysicalPackage',$oserial, $wwn, { comp_info => $comp_info} );
           }
           if ($nserial) {
             my($part) = NWS::3310->newDiskDrive($rep, $comp);
             Grid->setCode("$type.ComponentInsertEvent.disk");
             $hm->insertCompEvent($comp,$physicalFrame, $report, $orep, $part, $nserial, $wwn, { comp_info => $comp_info} );
           }
       }
       $hm->check_rev($orep, $rep, $report, $wwn, $id, $comp, "product_revision", 
                $comp_info);
    }

#############
# LOGICAL Volumes
# Note: Logical volumes is different from logical drive in minnow
#       1) Logical volumes consists of logical drives 
#       2) no raid for volumes
#############

    foreach my $e (keys %$orep) {
      next if ($e !~ /logical_volume\.(\w+)\.status/);
      my $comp = "logical_volume.$1";
      if (!exists $rep->{"$comp.status"}) {
         Grid->setCode("$type.ComponentRemoveEvent.logical_volume");
         $hm->removeCompEvent($comp, $physicalFrame, $report, $orep, 'CIM_PhysicalPackage',"$wwn.$comp", $wwn, { logicalVolume => 1} );
      }
    }

    foreach my $e (keys %$rep) {
      next if ($e !~ /logical_volume\.(\w+)\.status/);
      my $comp = "logical_volume.$1";

      next if (!exists($rep->{"$comp.status"}) && !exists($orep->{"$comp.status"}));
      if (!exists($orep->{"$comp.status"})) {
         my $lun = NWS::3310->newVolume($rep, $comp);
         Grid->setCode("$type.ComponentInsertEvent.logical_volume");
         $hm->insertCompEvent($comp, $physicalFrame, $report, $orep, $lun, "$wwn.$comp", $wwn, {logicalVolume => 1} );
         next;
      } else {
         Grid->setCode("$type.ValueChangeEvent.logical_volume");
         # $hm->stateChangeEvent($comp, 'status', $report, $rep, $orep,
         #                'CIM_PhysicalPackage', "$wwn.$comp",  $wwn );
         my $nstatus = $rep->get("$comp.status");
         my $ostatus = $orep->get("$comp.status");
         my $argin;
         $argin->{old_status} = $ostatus;
         $argin->{new_status} = $nstatus;
         $argin->{comp_info} = $comp;
         $hm->mapValueChangeEvent($report, $orep, $type, $comp, "status", $shortid, $id,
                 $wwn, "logical_volume.status", $argin);
      }
      my $opar = $orep->{"$comp.total_partitions"} || "N/A";
      my $npar = $rep->{"$comp.total_partitions"}  || "N/A";
      if ( $opar ne $npar) {
         Grid->setCode("$type.ValueChangeEvent.volume");
         $hm->alarmEvent($comp,"",$report,$wwn,"$id: Total partitions has been changed on $comp from '$opar' to '$npar'", undef, "volume"
        );
      }

      # PARTITION
      my $py;
      my $part_num = $rep->{"$comp.total_partitions"};
      for ($py = 1; $py <= $part_num; $py++) {
         my $comp1 = "$comp.partition.$py";
         my $osize = $orep->{"$comp1.effective_size"} || "N/A";
         my $nsize = $rep->{"$comp1.effective_size"}  || "N/A";

         if ( $osize ne $nsize) {
           Grid->setCode("$type.ValueChangeEvent.size");
          $hm->alarmEvent($comp,"",$report,$wwn,"$id: Effective size has been changed on $comp from $osize to $nsize", undef, "size");
         }
      }
    }

#############
# LOGICAL DRIVE
#############

    foreach my $e (keys %$orep) {
      next if ($e !~ /^logical_drive\.(\w+)\.status/);
      my $comp = "logical_drive.$1";
      if (!exists $rep->{"$comp.status"}) { 
         Grid->setCode("$type.ComponentRemoveEvent.logical_drive");
         $hm->removeCompEvent($comp, $physicalFrame, $report, $orep, 'CIM_PhysicalPackage',"$wwn.$comp", $wwn, { logicalDrive => 1 } );
      }
    }

    foreach my $e (keys %$rep) {
      next if ($e !~ /^logical_drive\.(\w+)\.status/);
      my $comp = "logical_drive.$1";

      next if (!exists($rep->{"$comp.status"}) && !exists($orep->{"$comp.status"}));
      if (!exists($orep->{"$comp.status"})) {
         my $lun = NWS::3310->newLun($rep, $comp);
         Grid->setCode("$type.ComponentInsertEvent.logical_drive");
         $hm->insertCompEvent($comp, $physicalFrame, $report, $orep, $lun, "$wwn.$comp", $wwn, {logicalDevice => 1} );
         next;
      } else {
         Grid->setCode("$type.ValueChangeEvent.logical_drive");
         # $hm->stateChangeEvent($comp, 'status', $report, $rep, $orep,
         #                'CIM_PhysicalPackage', "$wwn.$comp",  $wwn );
         my $nstatus = $rep->get("$comp.status");
         my $ostatus = $orep->get("$comp.status");
         my $argin;
         $argin->{old_status} = $ostatus;
         $argin->{new_status} = $nstatus;
         $argin->{comp_info}  = $comp;
         $hm->mapValueChangeEvent($report, $orep, $type, $comp, "status", $shortid, $id,
                 $wwn, "logical_drive.status", $argin);
      }
      my $opar = $orep->{"$comp.total_partitions"} || "N/A";
      my $npar = $rep->{"$comp.total_partitions"}  || "N/A";
      if ( $opar ne $npar) {
        Grid->setCode("$type.ValueChangeEvent.volume");
        $hm->alarmEvent($comp,"",$report,$wwn,"$id: Total partitions has been changed on $comp from '$opar' to '$npar'", undef, "volume");
      }
      my $orl = $orep->{"$comp.raid_level"} || "N/A";
      my $nrl = $rep->{"$comp.raid_level"}  || "N/A";
 
      if ( $orl ne $nrl) {
        Grid->setCode("$type.ValueChangeEvent.raid_level");
        $hm->alarmEvent($comp,"",$report,$wwn,"$id: Raid level has been changed on $comp from '$orl' to '$nrl'", undef, "raid_level");
      }
      # PARTITION 
      my $py;
      my $part_num = $rep->{"$comp.total_partitions"};
      for ($py = 1; $py <= $part_num; $py++) {
         my $comp1 = "$comp.partition.$py";
         my $osize = $orep->{"$comp1.effective_size"} || "N/A";
         my $nsize = $rep->{"$comp1.effective_size"}  || "N/A";

         if ( $osize ne $nsize) {
           Grid->setCode("$type.ValueChangeEvent.size");
          $hm->alarmEvent($comp,"",$report,$wwn,"$id: Effective size has been changed on $comp from $osize to $nsize", undef, "size");
         }
      }
    }

}



# components.disk.8.product_revision' => '0349
# fru.10.revision => '10'

sub check_rev {
  my($hm, $orep, $rep, $report, $wwn, $id, $comp, $el, $comp_info) = @_;
  my $rev  =  $rep->get("$comp.$el");
  my $orev = $orep->get("$comp.$el");
  my $cat  = $report->id('category');

  if ($rev && $orev && ($rev ne $orev) ) {
     Grid->setCode("$cat.ValueChangeEvent.revision");
     $hm->alarmEvent($comp, "", $report, $wwn,
         "Revision of $comp_info($comp) in $cat $id changed from '$orev' to '$rev'", 1, "revision");
  }
}

# remove "." from revision to avoid trigger event on 3.27R vs 327R

sub normalize_check {
   my ($hm, $orev, $nrev) = @_;
   $orev =~ s/\.//;
   $nrev =~ s/\.//;
   if ($orev eq $nrev) {
       return 0;
   } else {
       return 1;
   }
}

  

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

  my $cat = $rep->{"id.device_type"} || "3510";
  my $map = PDM->getDeviceStateMap("$cat.availability");

   my $status  = $rep->getState("$comp.status");
   my $ostatus = $orep->getState("$comp.status");

   my($oav, $av, $sev, $act);
   $sev =-9;  # default value
   ($oav, $av, $sev, $act) = $map->transition("disk_status.$ostatus", "disk_status.$status", $orep, $rep);
   return ($ostatus, $status, $oav, $av, $sev, $act);
}


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

  my $cat = $rep->{"id.device_type"} || "3510";
  my $map = PDM->getDeviceStateMap("$cat.availability");

   my $status  = $rep->getState("$comp.status");
   my $ostatus = $orep->getState("$comp.status");

   my($oav, $av, $sev, $act);
   $sev =-9;  # default value
   ($oav, $av, $sev, $act) = $map->transition("lun_status.$ostatus", "lun_status.$status", $orep, $rep);
   return ($ostatus, $status, $oav, $av, $sev, $act);

}

sub pre_check {
  # used for check status change between two reports
  # return 1 if the difference exists
  # return 0 if there is no difference
  # this is used to prevent unstatble output from sccli 
  
  my($hm, $report) = @_;
  my( $x ,$y);
  my($orep, $key);
  my($rep)	= $report->content;
  my($oreport) = PDM->getOldReport($report->fileKey);
  $DB::single = 1;

  if (!$oreport) {
     return 1;
  }

  $orep = $oreport->content();
   
  my $enc_status = $rep->get("info.status");
  my $oenc_status = $orep->get("info.status");

  if ( $enc_status ne $oenc_status) {
      return 1;
  }  

###########
# INFO
###########
    for my $e ('firmware_version','Revision', 'id_of_nvram_defaults',
		'bootrecord_version') {
	my $e0 = lc($e);
	my $ofirm = $orep->{"info.$e"};
	my $nfirm = $rep->{"info.$e"};
        if ($ofirm && $nfirm && ($ofirm ne $nfirm)) {
            return 1;
        }
    }

###########
# CHANNELS
###########
    for ($y=1; $y <= 20; $y++) {
	my $comp = "channel.$y.curwid";
	if ($orep->{$comp} && !$rep->{$comp}) {
              return 1;
	}

        my $comp2 = "channel.$y";

	next if (!( $rep->{"$comp2.mode"}) && !($orep->{"$comp2.mode"}));

	my $nmode= $rep->get("$comp2.mode");
	my $omode = $orep->get("$comp2.mode");
        if ($nmode ne $omode) {
            return 1;
        }
    }

#############
# ICL check
#############
   my $dtype = $rep->{'id.device_type'};
   if ($dtype =~/3510/) {
     for ($x = 1; $x<=2; $x++) {
     my $pos;
     if ($x ==1) {
      $pos = "lower_channel";
     } else {
      $pos = "upper_channel";
     }
     for ($y=0; $y <= 5; $y++) {
       my $field = "ICL";
       my $comp = $field.$pos.$y;
       my $comp_type = $rep->get("$field.type"); # inter-controller-link
       $comp_type =~ s/-/_/;
       next if (!$comp_type);
       my $nstatus = $rep->get("$comp.icl_status");
       my $ostatus = $orep->get("$comp.icl_status");

       if ($nstatus ne $ostatus) {
          return 1;
       }
    }
   }
  }

############
# components
############
  for ($x =1; $x<=8; $x++) { # deal with up to 7 extension box
    for ($y=1; $y <= 50; $y++) {
	my $comp = "enclosure.$x.component.$y";
	my $comp_type = $rep->get("$comp.type"); #  'diskslot', 'emu', 'fan', 'ps', 'temp',
	next if (!$comp_type);
	my $comp_unit = $rep->get("$comp.unit");
	my $sn = $rep->get("$comp.fru-pn") . "/" . $rep->get("$comp.fru-sn");

	my $nstatus = $rep->get("$comp.status");
	my $ostatus = $orep->get("$comp.status");

        if ($nstatus ne $ostatus) {
            return 1;
        }
    }
  }

###############################
# shut down primary controller
###############################
  if (($dtype =~ /3510/) || ($dtype =~ /3511/)
      || (( $dtype =~ /3320/) && ( $dtype != /jbod/ ))
      || (( $dtype =~ /3310/) && ( $dtype != /jbod/ ))) {
    foreach my $el (keys %$rep) {
      next if ($el !~ /controller_shutdown_status/);
      my $comp = "array";
      my $comp_type = $rep->get("$comp.type");
      next if (!$comp_type);

      my $nstatus = $rep->get("$comp.controller_shutdown_status");
      my $ostatus = $orep->get("$comp.controller_shutdown_status");

      if ($nstatus ne $ostatus) {
            return 1;
      }
   }
  }

###########
# safte
###########
  if (!(($dtype =~ /3510/) || ($dtype =~ /3511/))) {
    foreach my $el (keys %$rep) {
      next if ($el !~ /safte\.status/);
      my $comp = "safte";
      my $comp_type = $rep->get("$comp.type");
      next if (!$comp_type);
 
      my $nstatus = $rep->get("$comp.status");
      my $ostatus = $orep->get("$comp.status");
      
      if ($nstatus ne $ostatus) {
            return 1;
      }
   }
  }

###################
# redundant status
##################
  if (($dtype =~ /3510/) || ($dtype =~ /3511/)
      || (( $dtype =~ /3320/) && ( $dtype != /jbod/ ))
      || (( $dtype =~ /3310/) && ( $dtype != /jbod/ ))) {
      foreach my $el (keys %$rep) {
 	next if ($el !~ /controller_redundancy_status/);
 	my $comp = "enclosure";
 	my $comp_type = $rep->get("$comp.type");
 	next if (!$comp_type);

        my $nstatus = $rep->get("$comp.controller_redundancy_status");
 	my $ostatus = $orep->get("$comp.controller_redundancy_status");
         
        if ($nstatus ne $ostatus) {
            return 1;
	}
     }
  }

###########
# FRUS
###########

   foreach my $e (keys %$orep) {
	next if ($e !~ /fru\.(\w+)\.name/);
	my $comp = "fru.$1";
	if (!exists $rep->{"$comp.name"}) {
            return 1;
	}
   }

   foreach my $e (keys %$rep) {
	next if ($e !~ /fru\.(\w+)\.name/);
	my $comp = "fru.$1";
	next if (!exists($rep->{"$comp.name"}) && !exists($orep->{"$comp.name"}));

	if (!exists($orep->{"$comp.name"})) {
            return 1;
	} else {
             my $nstatus = $rep->get("$comp.fru_status");
             my $ostatus = $orep->get("$comp.fru_status");
         
             if ($nstatus ne $ostatus) {
                 return 1;
             }
         
	}

   }

###########
# DISKS
###########
    my $topdisk = $rep->get('info.top_disk');
    for ($y=0; $y <= $topdisk; $y++) {
	my $comp = "components.disk.$y";
	my $oserial = NWS::3310->getKey($orep, $comp);
	my $nserial = NWS::3310->getKey($rep, $comp);
	next if (!$oserial && !$nserial);

	if ($oserial ne  $nserial) {
          return 1;
	}
    
        my $nstatus = $rep->get("$comp.status");
        my $ostatus = $orep->get("$comp.status");
         
        if ($nstatus ne $ostatus) {
            return 1;
        }

    }

#############
# LOGICAL Volumes
#############

    foreach my $e (keys %$orep) {
	next if ($e !~ /logical_volume\.(\w+)\.status/);
	my $comp = "logical_volume.$1";
	if (!exists $rep->{"$comp.status"}) {
             return 1;
	}
    }

    foreach my $e (keys %$rep) {
	next if ($e !~ /logical_volume\.(\w+)\.status/);
	my $comp = "logical_volume.$1";

	next if (!exists($rep->{"$comp.status"}) && !exists($orep->{"$comp.status"}));
	if (!exists($orep->{"$comp.status"})) {
            return 1;
	} else {
	   my $nstatus = $rep->get("$comp.status");
	   my $ostatus = $orep->get("$comp.status");
           if ($nstatus ne $ostatus) {
	    return 1;
	   }

	}
	my $opar = $orep->{"$comp.total_partitions"} || "N/A";
	my $npar = $rep->{"$comp.total_partitions"}  || "N/A";
	if ( $opar ne $npar) {
             return 1;
	}
 
        # PARTITION
	my $py;
	my $part_num = $rep->{"$comp.total_partitions"};
	for ($py = 1; $py <= $part_num; $py++) {
	 my $comp1 = "$comp.partition.$py";
	 my $osize = $orep->{"$comp1.effective_size"} || "N/A";
	 my $nsize = $rep->{"$comp1.effective_size"}  || "N/A";

	 if ( $osize ne $nsize) {
              return 1;
	 }
      }
    }

#############
# LOGICAL DRIVE
#############

    foreach my $e (keys %$orep) {
	next if ($e !~ /^logical_drive\.(\w+)\.status/);
	my $comp = "logical_drive.$1";
	if (!exists $rep->{"$comp.status"}) {
            return 1;
	}
    }

    foreach my $e (keys %$rep) {
	next if ($e !~ /^logical_drive\.(\w+)\.status/);
	my $comp = "logical_drive.$1";

	next if (!exists($rep->{"$comp.status"}) && !exists($orep->{"$comp.status"}));
	if (!exists($orep->{"$comp.status"})) {
            return 1;
        } else {
	  my $nstatus = $rep->get("$comp.status");
	  my $ostatus = $orep->get("$comp.status");
          if ($nstatus ne $ostatus) {
                return 1;
          }
        }
        my $opar = $orep->{"$comp.total_partitions"} || "N/A";
        my $npar = $rep->{"$comp.total_partitions"}  || "N/A";
        if ( $opar ne $npar) {
             return 1;  
        }
        my $orl = $orep->{"$comp.raid_level"} || "N/A";
        my $nrl = $rep->{"$comp.raid_level"}  || "N/A";
     
	if ( $orl ne $nrl) {
             return 1;
	}

        # PARTITION
        my $py;
        my $part_num = $rep->{"$comp.total_partitions"};
        for ($py = 1; $py <= $part_num; $py++) {
	 my $comp1 = "$comp.partition.$py";
	 my $osize = $orep->{"$comp1.effective_size"} || "N/A";
	 my $nsize = $rep->{"$comp1.effective_size"}  || "N/A";

	 if ( $osize ne $nsize) {
              return 1;
	 }
        }
    }

###################
# fc counter check
###################
    my $new = $rep->{FC_COUNTERS}->{data};
    my $old = $orep->{FC_COUNTERS}->{data};

    foreach my $k (sort keys %$new) {
         return 1 if (!exists $old->{$k}); 
    }

    foreach my $e (sort keys %$old) {
         return 1 if (!exists $new->{$e});
    }

    foreach my $k (sort keys %$new) {
        my @n1 = split(/\t/, $new->{$k});
	my @o1 = split(/\t/, $old->{$k});


	my $o_crc = $o1[3];
	my $n_crc = $n1[3];
      
        if ($n_crc ne $o_crc) {
            return 1;
        } 
        
    }
###################
# finally no diff
###################
    return 0;
  
}

1;
