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

#  $Name: bld61_002 $ 
#  $Id: TOPO.pm,v 1.5 2006/04/18 13:37:27 mckenney Exp $


use base 'Health';
use NWS::SAN;
use Ilist;
use Message;
use Report;
use Events;
use FCRules;
use strict;
use Debug;
use TO;
use UNIVERSAL qw( isa ) ;

sub revision {'$Revision: 1.5 $'}


sub all_logic {
  my($hm, $report) = @_;

  my($ev, $ed, $pertains, $x ,$y, $contain, $sd);
  my($key);

  $DB::single = 1;
  my $to = TO->readExistingTopo();
  return if (!$to);

  my $renv  = System->get_renv();
  my $freq  = $renv->{audit_freq} || 7;
  my $eventType;

  my $audit = System->get_audit() ? "YES" : Timer->isXdays("Audit_topo", $freq);

  if ($audit) {
     $eventType = ($audit eq "YES") ? "AuditEvent" : "DiscoveryEvent";
  }  else {
     return;
  }

  my($renv) = System->get_renv();

  my($rep) = {};
  Agent::addIdentification({renv => $renv}, $rep);
  $rep = ReportContent->new($rep);

  CIM->version("1.1");

  my($hosts) = $to->hostList();
  my($switches) = $to->switchList();
  my($storages) = $to->storageList();
  my($id) =  PDM->getEventSequence ;

  my($zoom, $orient, $data) = $to->appletStream();
  my $num_ve = 0;
  my $num_sto = 0;
  my $num_switches = 0;
  my $num_dsp = 0;
  foreach my $sw (@$switches) {
      my($info) = $sw->info();
      if ($info->{class} =~ /switch.ve/){
        $num_ve++;
      } elsif($info->{class} eq "storage.dsp"){
      	 $num_dsp++;
      }else {
        $num_switches++;
      }
  }
  foreach my $sw (@$storages) {
      my($info) = $sw->info();
      next if( $info->{class} eq "storage.se2");
      if ($info->{class} eq "storage.dsp"){
         $num_dsp++;
      } else {
         $num_sto++;
      }
  }
  my $with;
  my $sp = $renv->{solution} eq "N" ? "host" : "sp";

  $with =  ($#$hosts+1) . " $sp " ;
  $with .= ", $num_switches switch(es) " if ($num_switches);
  $with .= ", $num_ve VE(s) "            if ($num_ve);
  $with .= ", $num_dsp DSP "             if ($num_dsp);
  $with .= ", $num_sto Array(s)"         if ($num_sto);

  my($desc) = "Topology event with $with";

  Grid->setCode("topo.$eventType");
  $ev = CIM::Instance->new('NWS_Event', [
                  [ EventType   => "topo.$eventType"  ],
                  [ EventId     => $id ],
                  [ Caption     => "SAN_Topology" ],
                  [ Description => $desc ],
                  [ Data        => $data ],
                         ]);

  $sd = Events->sourceDetector({ event => $ev ,  host => 1, rep => $rep});
  my($hostInstance) = $sd->[3];
  my($node1, $node2, $hba, $p, $hba1, $link);
  my(@all, $target, $port);
  push(@all, $ev,@$sd);

  foreach my $h (@$hosts) {
      my($hbas) = $h->port();
      my($hba_infos) = $h->portInfo();

      for ($hba=0; $hba <= $#$hbas; $hba++) {
           my($hb) = $hba_infos->[$hba];
           next if (substr($hb->{RegisterName},0,6) eq "pseudo");
           $node1 = $h->hostid() . ".port.$hba";
           my($type, $wwn, $port) = split(/:/, $hbas->[$hba]);
           next if (!$type || $type eq "hub");
           ($target, $port) = $to->nodeByName($hbas->[$hba]);
           next if (!$target);

           $hba1 = CIM::Instance->new('NWS_HbaPort', [
                  [ Tag         =>  $node1         ],
                  [ PortWWN     =>  $hb->{PortWWN} ],
                  [ NodeWWN     =>  $hb->{NodeWWN} ],
                  [ RegisterName=>  $hb->{RegisterName}],
                  [ LGroup      =>  $hb->{LGroup}  ],
                  [ HbaNumber   =>  $hba           ],
                  [ Path        =>  $hb->{path}    ],
                         ]);

           $node2 = $target->getPortCIMId($port);
           next if (!$node2);

           my($hba2host) = CIM::Instance->new('NWS_HostHba', [
                  [ Host      => $hostInstance ],
                  [ Hba       => $hba1         ],
                  [ LocationWithinContainer =>  "port.$hba" ],
                    ]);

           my($node2cim) = CIM::Key->new( ['CIM_Card',
                   CreationClassName => 'CIM_Card',
                   Tag               => $node2]);


           $link = CIM::Instance->new('NWS_Link', [
                  [ Link1       => $hba1     ],
                  [ Link2       => $node2cim ],
                    ]);

           $pertains = CIM::Instance->new('NWS_EventPertainsToLink', [
                  [ Event       => $ev  ],
                  [ Link        => $link ],
                    ]);
           push(@all, $hba1,$hba2host, $link, $pertains);
      }
  }
  my(%DONE);
  foreach my $sw (@$switches) {
      my($ports) = $sw->port();
      my($port_infos) = $sw->portInfo();

      for ($p=0; $p <= $#$ports; $p++) {
           my($type, $wwn, $port) = split(/:/, $ports->[$p]);
           next if (!$type || ($type eq "host"));

           $node1 = $sw->key() . ".port.$p";

           if ($type eq "hub") {
              my($hub) = $to->nodeByName("hub:$wwn");
              my($t0, $wwn0, $port0) = split(/:/, $hub->{info}{from});
              $node2 = "$wwn0.port.$port0";

           } else {  # any storage or switch
              ($target,$port) = $to->nodeByName($ports->[$p]);
              return if (!$target);
              $node2 = $target->getPortCIMId($port);
           }
           next if (!$node2);

           my($switchport) = CIM::Key->new( ['CIM_Card',
                   CreationClassName => 'CIM_Card',
                   Tag               => $node1]);

           my($storageport) = CIM::Key->new( ['CIM_Card',
                   CreationClassName => 'CIM_Card',
                   Tag               => $node2]);

           my $done;
           if ($node1 lt $node2) {
               $done = "$node1$node2";
           } else {
               $done = "$node2$node1";
           }
           next if ($DONE{$done});
           $DONE{$done} = 1;

           $link = CIM::Instance->new('NWS_Link', [
                  [ Link1       => $switchport   ],
                  [ Link2       => $storageport  ],
                    ]);

           $pertains = CIM::Instance->new('NWS_EventPertainsToLink', [
                  [ Event       => $ev  ],
                  [ Link        => $link ],
                    ]);

           push(@all, $link, $pertains);
       }
   }
   # does storage to hub (link to what is behind the hub)
   foreach my $st (@$storages) {
      my($ports) = $st->port();
      my($port_infos) = $st->portInfo();
  
      my($p);
      for ($p=0; $p <= $#$ports; $p++) {
           my($type, $wwn, $port) = split(/:/, $ports->[$p]);
           next if ($type ne "hub");

           my($agent) = uc($st->type() ) . "Agent";
           ($target, $port) = $to->nodeByName($ports->[$p]);
           next if (!$target);
           $node1 = $target->getPortCIMId($port);
           next if (!$node1);

           my($hub) = $to->nodeByName("hub:$wwn");

           my($t0, $wwn0, $port0) = split(/:/, $hub->{info}{from});
           $node2 = "$wwn0.port.$port0";

           my($storageport) = CIM::Key->new( ['CIM_Card',
                   CreationClassName => 'CIM_Card',
                   Tag               => $node1]);

           my($sw_ho_port) = CIM::Key->new( ['CIM_Card',
                   CreationClassName => 'CIM_Card',
                   Tag               => $node2]);

           $link = CIM::Instance->new('NWS_Link', [
                  [ Link1       => $storageport  ],
                  [ Link2       => $sw_ho_port   ],
                    ]);

           $pertains = CIM::Instance->new('NWS_EventPertainsToLink', [
                  [ Event       => $ev  ],
                  [ Link        => $link ],
                    ]);

           push(@all, $link, $pertains);

       }
   }

   $ed = Message->new( { id  => $report->id,
                         instances => \@all, 
                         severity  => Message::SEVERITY_NORMAL });

   PDM->saveMessage($ed);
}
1;

