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

#  $Id: COMMON.pm,v 1.20 2004/10/04 16:18:05 sbrooks Exp $

use Report;
use CIM::Instance;
use Data::Dumper;
use Health::T3;
use strict;
use Report;
use Ilist;
use PDM;
use NWS;
use COMMON;
use Util;

sub revision {'$Revision: 1.20 $'}


use vars qw ($FRUMAP);

sub newSystem {
  my ($class, $rep) = @_;
  my(@pil, $i, $dd, $a, $j, $k, $k1, $v);
  my $UNITS;
  my $key  = $rep->get('id.device_key'); # really the key now
  my $renv = System->get_renv();
  my $type = $rep->get("id.device_type");
  $FRUMAP = undef;

  my $p1 = CIM::Instance->new('NWS_System',[
                    [Name 		=> $key    ],
                    [OtherIdentifyingInfo  => $rep->get("id.device_ipno") ],
                    [SystemName         => $rep->get('id.device_name')],
                    [LogInfo            => ""  ],
                    [IP 		=> $rep->get('id.device_ipno') ],
                    [FruCount 		=> $rep->get('fru.count')  ],
                    [FruCtlrCount 	=> $rep->get('ctrl.count') ],
                    [FruDiskDriveCount 	=> $rep->get('disk.count') ],
                    [FruPowerCount 	=> $rep->get('pcu.count')    ],
                    [VolCount 		=> $rep->get('volume.count') ],
                    [SysBootDelay 	=> $rep->get('system._SysBootDelay')],
                    [SysRevision 	=> $rep->get('system._Version')],
                    [SerialNo 	        => $rep->get('system._IdentifyingNumber')],
                    [Caption            => uc($type) ],
                ]);

  my $p2 = CIM::Instance->new('CIM_PhysicalFrame', [
                  [Tag 			=> $key],
                  [Name			=> $key],
                  [Manufacturer 	=> $rep->get("system._Vendor")],
                  [SerialNumber 	=> $rep->get("system._IdentifyingNumber")],
                  [Model 		=> $type],
                  ]);

  my $a2 = CIM::Instance->new('CIM_ComputerSystemPackage', [
                  [Antecedent          => $p1],
                  [Dependent           => $p2],
                  ]);

  my $l1 = NWS->location($rep);
  
  my $al1 = CIM::Instance->new('NWS_PhysicalFrameLocation', [
                  [Element 		=> $p2],
                  [PhysicalLocation 	=> $l1],
                  ]);
               
  push (@pil, $p1, $p2, $a2, $l1, $al1);

  # These are for creating the pool or vdisk to drive association.
  my %driveInstances;
  my %poolInstances;

  # Search through the report, for every occurance of a _DeviceID
  # and create the appropriate CIM instance for it.
  foreach my $el (sort keys %$rep) {
      my @L = split(/\./, $el);
      my $k = "$L[0].$L[1]";
      if ($L[2]  eq "_DeviceID") {
        my $dd = $class->insert($rep, $k, $p1, $p2, 1);
        push(@pil, @$dd);

	# If this was a pool, save the instance in a temporary hash.
	if (($L[0] eq "pool") || ($L[0] eq "vdisk")) {
	   my $driveList = $rep->get("$L[0].$L[1]._BasedOn");
	   if (($dd) && ($driveList)){

              $driveList = Util->trim($driveList);
              my @driveArray = split(/"\s*,\s*"/, substr($driveList,1,-1));

              foreach my $drive (@driveArray) {
                 $poolInstances{$drive} = $dd;
              }
	   }
	}
	# If this is a drive, save the instances (it's an array) in a temporary hash.
	# The drive id must be prepended to make it a common report ref value.
	if (($dd) && ($L[0] eq "disk")) {
	   my $driveID = $rep->get("$L[0].$L[1]._DeviceID");
	   if ($driveID){
              $driveInstances{"disk:$driveID"} = $dd;	#tXdriveY
	   }
	}

      }
  }

  # Now add the associations between the drives and the pools.
  foreach my $disk (keys %poolInstances)
  {
     my $antecedent = $driveInstances{$disk}; #disk (array)
     my $dependent = $poolInstances{$disk}; #pool (also an array ie. the association)

     # The array may exist, but be empty, so check both ways.
     if (($antecedent) && ($dependent)) {
        if ((@$antecedent > 0) && (@$dependent > 0))	{
           my $poolToDiskAssoc = CIM::Instance->new('CIM_MediaPresent', [
                                  [Antecedent => $antecedent->[0] ],
                                  [Dependent  => $dependent->[0] ],
                                  ]);

           push (@pil, $poolToDiskAssoc);
	}
     }

  }


  return Ilist->new(\@pil);
}


sub insert {
   my($class, $rep, $k, $nwssystem, $physicalFrame, $needContainer) = @_;
   my @L = split(/\./, $k);
   my (@pil, $dd);


   if (($L[0] eq "pool") || ($L[0] eq "vdisk") || ($L[0] eq "volume")) {
     my $pool = $class->newLogical($rep, $k);

     if ($pool) {
        push (@pil, $pool);

        my $assoc =  CIM::Instance->new('CIM_MediaPresent', [
                                         [Antecedent => $nwssystem ],
                                         [Dependent  => $pool ],
                                        ]);
	if ($assoc) {
	   push (@pil, $assoc);
	}

     }
     return \@pil;
   } 


   if ($L[0] eq "disk") {
     $dd = $class->newDisk($rep, $k);
   } 
   elsif ($L[0] eq "ctrl") {
     $dd = $class->newController($rep, $k);
   } 

#   elsif ($L[0] eq "fcport") {
#     $dd = $class->newPort($rep, $k);
#   } 

   elsif ($L[0] eq "pcu") {
     $dd = $class->newPower($rep, $k);
   }
   elsif ($L[0] eq "midplane") {
     $dd = $class->newMidplane($rep, $k);
   }
   else {
     $dd = $class->newFRU($rep, $k);
   }
   return [] if (!$dd);

   my $a = CIM::Instance->new('CIM_Container', [
              [GroupComponent          => $physicalFrame      ],
              [PartComponent           => $dd->[1] ],
              [LocationWithinContainer => $rep->{"$k._ElementName"} ],
              ]);
   push (@pil, @$dd);
   push (@pil, $a) if ($needContainer);
   return \@pil;
}

#
# return the NO if the fru
# example: ctrl.1 => fru.2 , returns '2'
#
sub getFruId {
  my($class, $rep, $comp) = @_;
  my $serial = $rep->{"$comp._Realized"};  # SerialNo
  return undef if (!$serial);
  my $FRUMAP = COMMON->fruMap($rep) if (!$FRUMAP);
  
  return $FRUMAP->{$serial}{_id};
}

#
# return the NO if the fru
# example: ctrl.1 => fru.2 , returns '2'
#
sub getFruNum {
  my($class, $rep, $comp, $FRUMAP) = @_;
  my $serial = $rep->{"$comp._Realized"};  # SerialNo
  return undef if (!$serial);
  
  return $FRUMAP->{$serial}{_id};
}


#  $comp = "ctrl.1"
sub getKey {
  my($class, $rep, $comp) = @_;

  return $rep->{"$comp._Realized"} ||  $rep->{"$comp._DeviceID"};
}


#  return the class for the component
sub cimClass {
  my($class, $comp0) = @_;
  my($comp, $rest) = split(/\./, $comp0);

  my $mapping = $class->component_cim_mapping();
  
  return $mapping->{$comp};

}
  

# LOGICAL
#
sub newLogical {
  my($class, $rep, $index) = @_;

  my $p  = $index;

  # This is counterintuitive, so the following comment applies:
  # VolID is to be the descriptive name if possible, the system assigned
  # name otherwise.
  # VolName is to be the system assigned name if possible, otherwise the
  # system assigned name is to be used.
  my $volID   = $rep->get("$p._ElementName");
  my $volName = $rep->get("$p._Name");

  if (!$volID) {
     $volID = $volName;
  }
  if (!$volName) {
     $volName = $volID;
  }

  my $vol= CIM::Instance->new('NWS_StorageVolume', [
                    [ SystemName        => $rep->get("$p._Caption") ],
                    [ DeviceID          => $rep->get("$p._DeviceID")  ],
                    [ VolId             => $volID ],
                    [ VolName           => $volName ],
                    [ VolWWN            => $rep->get("$p._DeviceID")  ],
                    [ VolRaidLevel      => $rep->get("$p._RaidLevel") ],
                    [ Capacity          => $rep->get("$p.capacity") ],
                    [ VolStatus         => $rep->get("$p._Status")    ],
                    ]);
   return $vol;
}

#
# DISK
#
sub newDisk {
  my($class, $rep, $index) = @_;
  my(@il, $p1, $c1, $a1, $c2, $a2);

  my @L   = split(/\./, $index);
  my $FRUMAP = COMMON->fruMap($rep) if (!$FRUMAP);

  my $serial_no = $rep->{"$index._Realized"};
  return undef if (!$serial_no);
  my $FRU = $FRUMAP->{$serial_no};

  my $status = $rep->get("$index._Status");

  $p1 = CIM::Instance->new('NWS_DiskDrive', [
                [SystemName     => $rep->get("$index._Caption") ],
                [DeviceID 	=> $serial_no],
                [Name     	=> $serial_no],
                [FruDiskCapacity=> $rep->get("$index._usableCapacity")],
                [StatusInfo     => $rep->get("$index._Status") ],
                [Status         => 0 ],
                 ]);
  push(@il,$p1);

  $c1 = $class->Card($rep, $FRU, $index);

  push(@il, $c1);
  $a1 = CIM::Instance->new('CIM_Realizes', [
                    [Antecedent => $c1],
                    [Dependent => $p1],
                    ]);
                    
  push(@il,$a1);

  return Ilist->new(\@il);

}


#
#   CIM_CARD
#
sub Card {
  my($class, $rep, $FRU, $index) = @_;

#  my $tag = $rep->{"$index._Realized"} ||  $rep->{"$index._DeviceID"};
  my $tag = $rep->{"$index._Realized"};
  if (!$tag) {
     $tag = $rep->get('id.device_key').".".$rep->get("$index._DeviceID");

  }

  return CIM::Instance->new('CIM_Card', [
                [Removable      => "Yes"],
                [Tag            => $tag ],
                [WWN            => $rep->{"$index._WWN"} ],
                [Name           => $tag           ],
                [SerialNumber   => $FRU->{serial} ],
                [Manufacturer   => $FRU->{vendor} ],
                [Model          => $FRU->{model}  ],
                [Version        => $FRU->{fwRev}  ],
                [HwVersion      => $FRU->{hwRev}  ],
                    ]);
}


sub newFRU {
  my($class, $rep, $cd) = @_;
  my(@il, $p1, $c1, $a1, $c2, $a2);

  my $serial_no = $rep->{"$cd._Realized"};

#  return undef if (!$serial_no);

  my ($deviceID, $name);
  if ($serial_no) {
     $deviceID = $serial_no;
     $name     = $serial_no;
  }
  else {	

     # Some FRUs have no asset info, so _Realized is not set.  Use deviceID
     # and the system key for the identifier. 
     # If this is on the list of non frus, don't create classes for it.
     my($comp, $rest) = split(/\./, $cd);
     my $nonFRUs = $class->nonFRUList();
     my $skip = $nonFRUs->{$comp};
     return undef if ($skip);

     $deviceID = $rep->get('id.device_key').".".$rep->get("$cd._DeviceID");
     $name     = $rep->get('id.device_key').".".$rep->get("$cd._DeviceID");
  }

  my $FRUMAP = COMMON->fruMap($rep) if (!$FRUMAP);
  my $FRU    = $FRUMAP->{$serial_no};

  $p1 = CIM::Instance->new("NWS_Fru", [
                [SystemName         => $rep->get("$cd._Caption") ],
                [DeviceID           => $deviceID],
                [Name               => $name],
                [Status             => $rep->get("$cd._Status")  ],
                [Type               => $rep->get("$cd._Caption") ],
                [FruId              => $rep->get("$cd._ElementName")    ],
                [OtherIdentifyingInfo => $rep->get("$cd._Description") ],
                 ]);
  push(@il,$p1);
  $c1 = $class->Card($rep, $FRU, $cd);

  push(@il, $c1);
  $a1 = CIM::Instance->new('CIM_Realizes', [
                    [Antecedent => $c1],
                    [Dependent => $p1],
                    ]);
  
  push(@il,$a1);

  return Ilist->new(\@il);

}

# Non FRUs Returns an empty hash.  Should be subclassed
sub nonFRUList
{
   return {}
}


sub newPort {
  my($class, $rep, $cd) = @_;
  my(@il, $p1, $c1, $a1);

  my $status    = $rep->get("$cd._Status");
  my $serial_no = $rep->{"$cd._DeviceID"};

  my $FRUMAP = COMMON->fruMap($rep) if (!$FRUMAP);
  my $FRU = $FRUMAP->{$serial_no};

  my $type = $rep->get("id.device_type");
  my $map  = PDM->getDeviceStateMap("$type.availability");

  $p1 = CIM::Instance->new('NWS_SwitchPort',  [
             [Admin        => $rep->get("$cd._Status")],
             [Operational  => $rep->get("$cd._linkStatus")],
             [SystemName   => $rep->get("$cd._Caption") ],
             [DeviceID     => $serial_no ],
             [Name         => $rep->get("$cd._ElementName") ],
             [StatusInfo   => $status],
             [Status       => 1      ],

                    ]);

  push(@il,$p1);

  $c1 = $class->Card($rep, $FRU, $cd);

  push(@il, $c1);
  $a1 = CIM::Instance->new('CIM_Realizes', [
                [Antecedent   => $c1],
                [Dependent    => $p1],
                    ]);

  push(@il,$a1);

  return Ilist->new(\@il);

}


sub newController {
  my($class, $rep, $index) = @_;
  my(@il, $p1, $c1, $a1);
  
  my $serial_no = $rep->get("$index._Realized");
  return undef if (!$serial_no);

  my $FRUMAP = COMMON->fruMap($rep) if (!$FRUMAP);
  my $FRU = $FRUMAP->{$serial_no};

  $p1 = CIM::Instance->new('NWS_Controller', [
                    [SystemName  =>  $rep->get("$index._Caption") ],
                    [DeviceID     => $serial_no],
                    [Name         => $rep->get("$index._ElementName")   ],
                    [StatusInfo   => $rep->get("$index._Status") ],
                    [Status       => 1 ],
                    ]);
  push(@il,$p1);

  $c1 = $class->Card($rep, $FRU, $index);

  push(@il, $c1);
  $a1 = CIM::Instance->new('CIM_Realizes', [
                [Antecedent => $c1],
                [Dependent => $p1],
                    ]);
                    
  push(@il,$a1);

  return Ilist->new(\@il);

}

sub newPower {
  my($class, $rep, $cd) = @_;
  my(@il, $p1 ,$c1, $a1);
  
  my $serial_no = $rep->{"$cd._Realized"};
  return undef if (!$serial_no);
  my $FRUMAP = COMMON->fruMap($rep) if (!$FRUMAP);

  my $FRU = $FRUMAP->{$serial_no};

  $p1 = CIM::Instance->new('NWS_PowerUnit', [
               [SystemName   => $rep->get("$cd._Caption") ],
               [DeviceID     => $serial_no],
               [Name         => $rep->get("$cd._ElementName")   ],
               [StatusInfo   => $rep->get("$cd._Status") ],
               [Status       => 1],
                    ]);
  push(@il,$p1);

  $c1 = $class->Card($rep, $FRU, $cd);

  push(@il, $c1);
  $a1 = CIM::Instance->new('CIM_Realizes', [
               [Antecedent 		=> $c1],
               [Dependent 		=> $p1],
                    ]);
                    
  push(@il,$a1);

  return Ilist->new(\@il);
}

sub newMidplane {
  my($class, $rep, $cd) = @_;
  my(@il, $p1 ,$c1, $a1);
  
  my $serial_no = $rep->{"$cd._Realized"};
  return undef if (!$serial_no);
  my $FRUMAP = COMMON->fruMap($rep) if (!$FRUMAP);

  my $FRU = $FRUMAP->{$serial_no};

  $p1 = CIM::Instance->new('NWS_Midplane', [
               [SystemName   => $rep->get("$cd._Caption") ],
#               [DeviceID     => $serial_no.".mpn"],
               [DeviceID     => $serial_no],
               [Name         => $rep->get("$cd._ElementName")   ],
               [StatusInfo   => $rep->get("$cd._Status") ],
               [Status       => 1],
                    ]);
  push(@il,$p1);

  $c1 = $class->Card($rep, $FRU, $cd);

  push(@il, $c1);
  $a1 = CIM::Instance->new('CIM_Realizes', [
               [Antecedent 		=> $c1],
               [Dependent 		=> $p1],
                    ]);
                    
  push(@il,$a1);

  return Ilist->new(\@il);
}


1;
