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

use base 'TO::Server';
use strict;
use Storable;
use Lease;
use TO;

sub leaf { 1 }

sub type { "host"}

# ADD volInfo, portInfo, Connections
# read and write the topology
#
sub addHBAs {
  my($class,  $hba_list) = @_;
  my($lease);
  my $renv = System->get_renv();
  my $hostname = $renv->{hostname};
  my $Config = PDM::ConfigFile->read();

  if (($lease = Lease->get("topo", 6, 7)) ) {
    my $to = TO->readExistingTopo();
    if (!$to) {
      $lease->release();
      return;
    }
    my $host_node = $to->nodeByName("host:" . $renv->{hostname});
    if (!$host_node) {
      $lease->release();
      return;
    }
    my $hba_cnt;

    for ($hba_cnt=0; $hba_cnt <= $#$hba_list; $hba_cnt++) {
      my $hba  = $hba_list->[$hba_cnt];
      my $devs = $hba->{deviceInfo};

      # ORGANIZE PORTS BY NODEWWN
      my($x1, %MAP);
      for ($x1=0; $x1 <= $#$devs; $x1++) {
         my $d = $devs->[$x1];
         my $key = $d->{ENCNodeWWN} || $d->{NodeWWN};
         next if ($key =~ /^0+$/);
         push(@{$MAP{$key}}, $d);
      }
      foreach my $nodeWWN (keys %MAP) {
          my $devs = $MAP{$nodeWWN};
          my $dev0 = $devs->[0];
          my $node = $to->nodeBySynonym($nodeWWN) || 
                         $to->nodeBySynonym($dev0->{PortWWN});
          if (!$node) {
            $node = TO::HBASTORAGE->newFromDEVICEPORT($to, $dev0, $hba);
            # maybe create an hba-api node
          }
          my $encType = $node->enclosureType($devs);
          for ($x1=0; $x1 <= $#$devs; $x1++) {
             my $d = $devs->[$x1];
             if (length($d->{ProductID}) < length($node->{info}{LGroup}) && 
                 length($d->{ProductID}) > 0) {
                $node->{info}{LGroup} = $d->{ProductID};
             }
             my $devType = $encType ?  $encType->isDeviceType($d) : "DP";

             if (index($devType, "D") >= 0) {
               $node->{diskInfo}{$d->{PortWWN}} = {
                     LogicalPath  => $d->{LogicalPath},
		     Revision     => $d->{Model},
		     VendorID     => $d->{Vendor},
		     ProductID    => $d->{ProductID},
                     NodeWWN      => $d->{NodeWWN},
                     PortWWN      => $d->{PortWWN},
                     RegisterName => $d->{RegisterName},
                     };
             }
             if (index($devType, "P") >= 0) {
               my($port, $san_port, $use_port) = $node->topoPort($d->{PortWWN}, $hba, 
                                                      $Config, $devs, $x1);

               # ADD portInfo
	       # make sure this doesn't overwrite an existing port
	       my $pinfo = $node->{portInfo}[$port];
	       if($pinfo->{PortWWN}){
	          # Port exists
		  if($pinfo->{PortWWN} !~ /$d->{PortWWN}/){
		    # This is a different port
		    # Must find an empty port or correct port
		    for(my $index = 0; $index <= 256; $index++){
		       my $p1info = $node->{portInfo}[$index];
	               if($p1info->{PortWWN}){
		          if($p1info->{PortWWN} =~ /$d->{PortWWN}/){
			     # Found the correct port
			     $port = $index;
			     last;
			  }
		       }else{
		         # Empty port slot
			 $port = $index;
			 last;
		       }
		    }
		  } # else port is same, use this port index
	       }
	       my $okay = 1;
	       if(defined($use_port)){
	         if($use_port != $port){
		   # Don't use this port
		   $okay = 0;
		 }
	      }
	       #$port = $use_port if (defined($use_port));
	       if($okay){
               $node->{portInfo}[$port] = {
                     PortWWN     => $d->{PortWWN},
                LocalPortWWN     => $d->{PortWWN},
                     NodeWWN     => $d->{NodeWWN},
                    RegisterName => $d->{RegisterName},
                    ConnectedOn  => $d->{ConnectedOn},
                     hba_path    => $hba->{path},
                     PhysPath    => $hba->{path},
                     LogicalPath => $d->{LogicalPath},
                  };
   
               # ADD Connection
               $san_port = $port if (!defined($san_port));
               $host_node->{port}[$hba_cnt] = $node->name()      . ":" . $san_port;
               $node->{port}[$san_port]     = $host_node->name() . ":" . $hba_cnt;
	       }
             }
             
             # ADD volInfo
             my($x, @LUNS);
             @LUNS = split(/\|/, $d->{LogicalPath});
             for ($x=0; $x <= $#LUNS; $x++) {
                my $lun = $LUNS[$x];
                $node->{volInfo}{$lun} = {
                             PortWWN => $d->{PortWWN},
                             NodeWWN => $d->{NodeWWN},
                       };
             }
          }
      }
    }
    $to->saveTopo($hostname);
    $lease->release();
  }
}



sub newFromDev {
  my($class, $topo, $dev, $arg) = @_;
  my $obj = $class->new($topo, $dev->{name}, {});
  if ($arg->{hba_list}) {
     my $ports = Storable::dclone($arg->{hba_list});
     foreach my $port (@$ports) {
        delete $port->{deviceInfo};
        $port->{LocalPortWWN} = $port->{PortWWN};
        foreach my $e ('Instance','PortType','PortSpeedValue',
            'PortSupportedSpeed','PortValue','PortFcId',
            'NumberofPorts', 
            'adapter_NodeSymbolicName','PortMaxFrameSize',
            'FabricName','adapter_Description','adapter_HardwareVersion',
            'adapter_VendorSpecificID','adapter_NumberOfPorts') {
            delete $port->{$e};
        }
     }
     $obj->{portInfo} = $ports;
  }
}

sub new {
  my($class, $Topo, $hostname, $info) = @_;
  my($size);
  my($name)  = "host:$hostname";
  my($hosts) = $Topo->[0];
  my $renv = System->get_renv();
  my $mgmtLevel = "D";

  if (!defined($hosts->{$name}) ) {
     my($obj) = {};
     $obj->{info}       = $info;
     $obj->{info}{type} = "Sun";
     $obj->{info}{class} = "host";
     $obj->{info}{hostid}= System->hostid();
     $obj->{info}{ipno}  = Util->name2ip($hostname);
     $obj->{info}{bitMode} = System->bitMode();
     $obj->{info}{model}   = $info->{model} || System->model();
     $obj->{info}{release} = System->os_release();
     $obj->{info}{mgmtLevel} = $mgmtLevel;
     $obj->{info}{name} = $name;
     $obj->{portInfo}   = [];
     $obj->{port}       = [];
     bless($obj, 'TO::HOST');
     $hosts->{$name} = $obj;
     $Topo->addSyn($hostname, $name);
  }
  return $hosts->{$name};
}

sub statusFunc {
  my($class, $name, $State) = @_;

  if (substr($name,0,2) eq "sp") {
     require TO::SP;
     return TO::SP->statusFunc($name, $State);
  }

  my $Comp = $State->components($name);
  my $i   = $Comp->value("e");
  my ($enc, $encInfo);
  my ($other, $disk, $diskInfo, $otherInfo, $port, $portInfo);
  my ($lunS, $lunI, $otherS, $otherI);

  my (@P, $x);
  foreach my $c (keys %$Comp) {
     my $el = $Comp->value($c);
     next if ($el->[0] <= 0);
     if (substr($c,0,4) eq "hba.") {
        my $po = substr($c,4) + 0;
        $P[$po] = $Comp->value($c);

     } elsif (substr($c,0,5) eq "port.") {
        my $po = substr($c,5) + 0;
        $P[$po] = $Comp->value($c);
     }
     $Comp->summ($c, \$other, \$otherInfo);
  }

  for ($x=0; $x <= $#P; $x++) {
     if ($P[$x]) {
       $port .= $P[$x][0] . ",";
       my $pi = $P[$x][1];
       $pi =~ s/\/devices//;
       $pi =~ s/[,\|]/ /g;
       $portInfo .= "$pi,";
     } else {
       $port .= ",";
       $portInfo .= ",";
     }
  }
  return ($enc, $port, $disk, $other, $encInfo,
          $portInfo, $diskInfo, $otherInfo);

}

sub iconLayout {
  my($ho) = @_;
  my $gif = $ho->getGif();
  return "E0E0E0/$gif,_," ; 
}


sub getGif {
  my($h) = @_;
  my $info = $h->{info};
  my $model = $info->{model};
  if ($model =~ /Fire-280R/) {
    return "280r.gif";
  } elsif ($model =~ /UltraAX-i2/ || $model =~ /Netra/) {
    return "netraX1.gif";
  } elsif ($model =~ /Enterprise.*10000/) {
    return "e10k.gif";
  } elsif ($model =~ /Enterprise/) {
    return "e45.gif";
  } elsif ($model =~ /Ultra/) {
    return "ultra.gif";
  }
  return "host2.gif";
}


1;

