# $Id: STD_REPORT.pm,v 1.8 2005/05/23 22:28:21 sbrooks Exp $
# Copyright 2004 Sun Microsystems, Inc., All Rights Reserved.
# Sun Proprietary/Confidential: For Internal Use Only
package NWS::STD_REPORT;

use strict;

use Catalog::Model;
use Catalog::ReportClass;
use CIM::Instance;
use Ilist;
use Report;

sub new {
  my ($class, $type) = @_;

  my $this = {
				  type  => $type,
				  model => new Catalog::Model($type),
				 };
  bless($this, "NWS::STD_REPORT");
  return $this;
}

sub newSystem {
  my ($class, $report, $type) = @_;
  my $system = createFromReport Catalog::ReportClass($report);
  my $std = new NWS::STD_REPORT($type);
  return $std->newSystemInst($system);
}

# Create a NWS_System with supporting association classes.
sub newSystemInst {
  my ($this, $system) = @_;
  my @instances;
  my $key  = $system->getKey();
  my $type = $this->{type};

  my $device = { type => $type, key => $key, name => $system->getDisplayName(),
					  ipno => $system->getProperty("_IPAddress")};
  my $nws_system = $this->NWS_System($system, $device);

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

  my $cim_computerSystemPackage = CIM::Instance->new
	 ('CIM_ComputerSystemPackage',
	  [
		[Antecedent => $nws_system],
		[Dependent  => $cim_physicalFrame],
	  ]
	 );
																	
  my $location = NWS->location();

  my $nws_physicalFrameLocation = CIM::Instance->new
	 ('NWS_PhysicalFrameLocation',
	  [
		[Element          => $cim_physicalFrame],
		[PhysicalLocation => $location],
	  ]
	 );

  push(@instances, $nws_system, $cim_physicalFrame,
		 $cim_computerSystemPackage, $location, $nws_physicalFrameLocation);


  my $components = $system->getSubComponents("logical", $this->{model});
  foreach my $component (@$components){
	 my $compInsts = $this->newComponent($component, $nws_system, $cim_physicalFrame);
	 if ($#$compInsts >= 0){
		push(@instances, @$compInsts);
	 }
  }

  my $licenses = $system->getSubComponents("license", $this->{model});
  foreach my $license (@$licenses){
	 my $licenseInsts = $this->newLicense($license, $nws_system, $key);
	 if ($#$licenseInsts >= 0){
		push(@instances, @$licenseInsts);
	 }
  }


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

#                                                    TEST
sub newLicense
{
  my ($class, $license, $nwssystem, $system_key) = @_;

  my $feature_license = $class->NWS_LicenseFeature($license, $nwssystem, $system_key);

  return $feature_license;

}

sub NWS_LicenseFeature {
  my($class, $license, $nws_system, $system_key) = @_;

  my $nws_feature = CIM::Instance->new
	 ("NWS_LicenseFeature",
	  [
                [AmountInUse    =>   $license->getComponentProperty("AmountInUse") ],
                [AmountLicensed =>   $license->getComponentProperty("AmountLicensed") ],
                [ClassName      =>   $license->getClassName() ],
                [KeyCount       =>   "0" ],
                [FeatureName    =>   $system_key.".".$license->getDisplayName() ],
                [InCompliance   =>   $license->getComponentProperty("_InCompliance") ],
                [Name           =>   $license->getDisplayName() ],
                [ProductName    =>   $license->getComponentProperty("_FeatureName") ],
                [Vendor         =>   $license->getComponentProperty("Vendor") ],
                [Version        =>   $license->getComponentProperty("Version") ],
	  ]
	 );

	if ($nws_system){
	  my $component = CIM::Instance->new
		 ('CIM_Component',
		  [
			[GroupComponent => $nws_system ],
			[PartComponent  => $nws_feature ]
		  ]
		 );
	  return Ilist->new( [$nws_feature, $component] );
	}

return Ilist->new( [$nws_feature]);

}

sub newComponent {
  my ($class,
		$device, # Catalog::ReportClass
		$nwssystem, $physicalFrame  # CIM::Instance
		) = @_;

  if ($device->isA("pool")){
	 my $pool = $class->NWS_StorageVolume($device, $nwssystem);
	 $class->addDiskMediaPresent($device, $pool);
	 return $pool;
  }

  if ($device->isA("vdisk")){
	 my $vdisk = $class->NWS_StorageVolume($device);
	 $class->addDiskMediaPresent($device, $vdisk);
	 return $vdisk;
  }

  if ($device->isA("volume")){
	 return $class->NWS_StorageVolume($device);
  }

  my $cim;
  if ($device->isA("disk")){
	 $cim = $class->NWS_DiskDrive($device);
  }
  elsif ($device->isA("ctrl")){
	 $cim = $class->CIM_LogicalDevice($device, "NWS_Controller");
  }
  elsif ($device->isA("pcu")){
	 $cim = $class->NWS_PowerUnit($device);
  }
  elsif ($device->isA("midplane")){
	 $cim = $class->NWS_Midplane($device);
  }
  else {
	 $cim = $class->CIM_LogicalDevice($device, "NWS_Fru");
  }
  if ($physicalFrame && $cim){
	 $class->addContainer($device, $cim, $physicalFrame);
  }
  return $cim;
}

sub addContainer {
  my ($class,
		$device,           # Catalog::ReportClass
		$component,        # CIM::Instance array
		$cim_physicalFrame # CIM::Instance
	  ) = @_;
  $DB::single=1;
  my $phyElem = $component->[1];
  if ($phyElem){
	 my $cim_container = CIM::Instance->new
		('CIM_Container',
		 [
		  [GroupComponent          => $cim_physicalFrame ],
		  [PartComponent           => $phyElem ],
		  [LocationWithinContainer => $device->getDisplayName() ]
		 ]
		);
	 push (@$component, $cim_container);
  }	
  return $component;
}

sub NWS_System {
  my ($class,
		$system, # Catalog::ReportClass
		$device  # rasagent.conf device hash
	  ) = @_;

  my $sys = CIM::Instance->new
	 ('NWS_System',
	  [
		[Name 		          => $device->{key}  ],
		[OtherIdentifyingInfo => $device->{ipno} ],
		[SystemName           => $device->{name} ],
		[LogInfo              => ""  ],
		[IP 		             => $device->{ipno} ],
		[FruCount 	          => $system->getComponentCount("fru") ],
		[FruCtlrCount         => $system->getComponentCount("ctrl") ],
		[FruDiskDriveCount    => $system->getComponentCount("disk") ],
		[FruPowerCount 	    => $system->getComponentCount("pcu")    ],
		[VolCount 		       => $system->getComponentCount("volume") ],
		[SysBootDelay 	       => $system->getProperty('_SysBootDelay')],
		[SysRevision 	       => $system->getProperty('_Version')],
		[SerialNo 	          => $system->getProperty('_IdentifyingNumber')],
		[Caption              => uc($device->{type}) ],
	  ]);

#  string HostId;
#  string SysRevision;
#  string IP;
#  string SystemName;
#  string SolutionId = "SOLUTIONID";
#  uint16 FruCount;
#  uint16 FruCtlrCount;
#  uint16 FruDiskDriveCount;
#  uint16 FruLoopCount;
#  uint16 FruPowerCount;
#  uint16 VolCount;
#  uint16 SysBootDelay;
#  string SysBootMode;
#  string SysCacheMirror;
#  string SysCacheMode;
#  string Thresholds;
#  string Fan0Revision;
#  string Fan0Status;
#  string Fan1Revision;
#  string Fan1Status;
#  string InterconnectRevision;
#  string InterconnectStatus;
#  string LogInfo;
#  string WWN;
#// Switch
#  string Flash;
#  string HW;
#  string MacAddress;
#  string PROM;
#  string Firmware;
#  string BootInfo;
#// A3500
#  string BootLevel;
#  string FibreLevel;
#  string FirmwareLevel;
#  string ProductRevision;
#// Vicom
#// Solution
#  string SolutionModel;
#  string RedundantController;
#  string SupportedRAIDType;
#  string SerialNo;
#  uint16 TotalCapacity;
#  string License;
#// 3510
#  string Cache;

  return $sys;
}


sub NWS_Card {
  my ($class, $device, $fru) = @_;

  my $removable = "Yes";
  my $removalConditions = $fru->getProperty("_RemovalConditions");
  if ($removalConditions){
	 if ($removalConditions !~ /4|Removable when on or off/){
		$removable = "No"
	 }
  }

  my $card = CIM::Instance->new
	 ('CIM_Card',
	  [
		[Removable         => $removable],
		[Tag               => $fru->getKey() ],
		[Type              => $device->getClassName() ],
		[CreationClassName => "CIM_Card" ],
		[Name              => $fru->getDisplayName() ],
		[SerialNumber      => $fru->getProperty("_SerialNumber") ],
		[Manufacturer      => $fru->getProperty("_Vendor") ],
		[Model             => $fru->getProperty("_Model")  ],
		[Version           => $device->getProperty("_FirmwareVersion") ||
		 $fru->getProperty("_Firmware")],
		[HwVersion         => $fru->getProperty("_Version") ],
	  ]
	 );
  $class->_setValue($device, $card, "WWN");

  #  datetime InstallDate
  #  string Status;
  #  string OtherIdentifyingInfo;
  #  string Caption;
  #  string Description;
  #  string PartNumber;
  #  boolean Replaceable;
  #  boolean HotSwappable;
  #  string Type;
  #  string Class;
  #  uint16 OperatingVoltages;
  return $card;
}

sub NWS_DiskDrive {
  my ($class, $disk) = @_;

  my $inst     = $class->CIM_LogicalDevice($disk, "NWS_DiskDrive");
  my $nws_disk = $inst->[0];

  $nws_disk->setValue("FruDiskCapacity", $disk->getProperty("_Capacity"));
#  string Port1State;
#  string Port2State;
#  string FruDiskRole = "dataDisk";
#  boolean FruDiskIsExpendable;
#  boolean FruDiskIsRebuildable;
#  uint16 FruDiskTemperature;
#  string FruDiskCapacity;
#  uint16 FruErrors;
#  string Wwn;
#  string PowerSupplyStatus;
#  string FanStatus;
#  string EnvironmentStatus;
  return $inst;
}

sub NWS_Controller {
  my ($class, $ctrl) = @_;
  my $inst     = $class->CIM_LogicalDevice($ctrl, "NWS_Controller");
# datetime TimeOfLastReset;
#  string Role;
#  uint16 FruErrors;
#  uint16 PortErrors;
#  string PortStatus;
#  string PortSunHost;
#  string PortType;
#  string PowerSupplyStatus;
#  string FanStatus;
#  string EnvironmentStatus;
#  string BatteryStatus;
#  string ProcessorStatus;
#  string BusStatus;
#  string CacheStatus;
  return $inst;
}

sub NWS_Module {
  my ($class, $module) = @_;
  my $inst = $class->CIM_LogicalDevice($module, "NWS_Module");
#  string Role;
#  string Type;
#  string Class;
  return $inst;
}

sub CIM_FibrePort {
  my ($class, $port, $classname) = @_;
  my $inst = $class->CIM_LogicalDevice($port, $classname ||
													"CIM_FibrePort");
  my $cim_port = $inst->[0];
  #CIM_FibrePort
#  uint32 Speed;
#  uint32 MaxSpeed;
#  uint32 AddressIdentifier;
#  uint16 CurrentPortType;
#  string CurrentVersion;
#  uint64 LossOfSignalCounter;
#  uint64 LossOfSyncCounter;
#  uint64 CRCErrors;
#  uint64 InvalidTransmissionWords;
#  uint64 FramesTooShort;
#  uint64 FramesTooLong;
#  uint64 ReceiverTransmitterTimeout;
#  uint16 BypassedState;
#  uint16 ConnectedMedia = "4";
  return $inst;

}
sub NWS_HBA {
  my ($class, $hba) = @_;

  my $inst = $class->CIM_FibrePort($hba, "NWS_HBA");
  my $port = $inst->[0];

#  string PortWWN;
#  string NodeWWN;
#  string Mode;
#  string RegisterName;
#  string LGroup;
#  uint16 HbaNumber;
#  string Path;
#  string FabricName;
#  string DriverVersion;
#  string FirmwareVersion;
#  string Vendor;
#  string Model;
#  string Serial;

  return $inst;
}

sub NWS_SwitchPort {
  my ($class, $port) = @_;

  my $inst     = $class->CIM_FibrePort($port, "NWS_SwitchPort");
  my $nws_port = $inst->[0];

  $nws_port->setValue("Admin", $port->getProperty("_Status"));
  $nws_port->setValue("Operational", $port->getProperty("_linkStatus"));

#NWS_SwitchPort
#  string Admin;
#  string Mode;
#  string Operational;
#  string PortType;
#  string RemoteWWN;
#  string TypeName;
#  string ModuleType;
#  string FcClass;
#  string FcSpeed;

#NWS_DevicePort
#  string LogicalInfo;
  return $inst;
}

sub NWS_PowerUnit {
  my ($class, $pcu) = @_;
  return $class->CIM_LogicalDevice($pcu, "NWS_PowerUnit");
#  uint32 FruBatLife;
#  uint16 FruErrors;
#  string Fan1State;
#  string Fan2State;
#  string Revision;
}

sub NWS_Midplane {
  my ($class, $midplane) = @_;
  return $class->CIM_LogicalDevice($midplane, "NWS_Midplane");
#string IsEnabled;
#string IsSubstituted;
}

sub NWS_Fan {
  my ($class, $fan) = @_;
  return $class->CIM_LogicalDevice($fan, "NWS_Fan");
}

sub NWS_Battery {
  my ($class, $battery) = @_;
  return $class->CIM_LogicalDevice($battery, "NWS_Battery");
}

sub _setValue {
  my ($class, $rc, $cim, $name) = @_;
  my $value = $rc->getProperty("_".$name);
  if ($value){
	 $cim->setValue($name, $value);
  }
}

sub CIM_LogicalDevice {
  my ($class, $device, $className) = @_;

  my $logical = CIM::Instance->new
	 ($className,
	  [
		[CreationClassName       => $className ],
		[SystemCreationClassName => "NWS_System"],
		[SystemName              => $device->getSystemKey() ],
		[DeviceID                => $device->getKey()],
		[Name                    => $device->getDisplayName() ],
		[Status                  => $device->getProperty("_Status")],
	  ]
	 );

  # StatusInfo 1=Other,2=Unknown,3=Enabled,4=Disabled,5=Not Applicable"
  my $enabledState = $device->getProperty("_EnabledState");
  if ($enabledState){
	 if ($enabledState =~ /2|Enabled/){
		$logical->setValue("StatusInfo", "3");
	 }
	 if ($enabledState =~ /3|Disabled/){
		$logical->setValue("StatusInfo", "4");
	 }
	 else {
		$logical->setValue("StatusInfo", "1");
	 }
  }
  else {
	 $logical->setValue("StatusInfo", "2");
  }

  $class->_setValue($device, $logical, "Caption");
  $class->_setValue($device, $logical, "Description");
  $class->_setValue($device, $logical, "Availability");
  $class->_setValue($device, $logical, "OtherIdentifyingInfo");
  $class->_setValue($device, $logical, "LastErrorCode");
  # datetime InstallDate = "NOW";
  # uint64 TotalPowerOnHours;

  my $fru = $device->getFRU();
  if (!$fru){
	 return Ilist->new( [$logical] );
  }
  my $nws_card     = $class->NWS_Card($device, $fru);
  my $cim_realizes = $class->CIM_Realizes($nws_card, $logical);

  return Ilist->new( [$logical, $nws_card, $cim_realizes] );
}

sub CIM_Realizes {
  my ($class, $physical, $logical) = @_;
  return CIM::Instance->new
	 ('CIM_Realizes',
	  [
		[Antecedent => $physical],
		[Dependent  => $logical],
	  ]
	 );
}


sub addDiskMediaPresent {
  my ($class, $extent, $nws_volume, $disks) = @_;

  my $volInst    = $nws_volume->[0];
  my $basedOn    = $extent->getProperty("_BasedOn");
  my $driveList  = Util->trim($basedOn);
  if (!$driveList){
	 return;
  }
  my @driveArray = split(/"\s*,\s*"/, substr($driveList,1,-1));
  my $sysName    = $extent->getSystemKey();

  foreach my $drive (@driveArray) {
	 if ($disks){
		my $nws_diskDrive = $disks->{$drive};
		if ($nws_diskDrive){
		  my $poolToDiskAssoc = CIM::Instance->new
			 ('CIM_MediaPresent',
			  [
				[Antecedent => $disks->{$drive} ],
				[Dependent  => $volInst ],
			  ]
			 );
		  push(@$nws_volume, $poolToDiskAssoc);
		}
	 }
	 else {
		my ($rclass, $rkey) = split(/\:/, $drive);
		my $diskRef = CIM::Key->new
		  (['NWS_DiskDrive',
			 DeviceID => $rkey,
			 CreationClassName => 'NWS_DiskDrive',
#			 SystemCreationClassName => 'NWS_System',
			 SystemName => $sysName
			]);
		my $poolToDiskAssoc = CIM::Instance->new
		  ('CIM_MediaPresent',
			[
			 [Antecedent => $diskRef ],
			 [Dependent  => $volInst ],
			]
		  );
		push(@$nws_volume, $poolToDiskAssoc);
	 }
  }
}

# Create a storage volume with optional association to a nws_system.

sub NWS_StorageVolume {
   my ($class, $extent, $nws_system) = @_;
	my $vol= CIM::Instance->new
	  ('NWS_StorageVolume',
		[
		 [ SystemCreationClassName => "NWS_System" ],
		 [ SystemName        => $extent->getSystemKey() ],
		 [ DeviceID          => $extent->getKey()  ],
		 [ VolId             => $extent->getDisplayName() ],
		 [ VolName           => $extent->getKey() ],
		 [ VolWWN            => $extent->getProperty("_WWN") ||
		                        $extent->getKey()],
		 [ VolRaidLevel      => $extent->getProperty("_RaidLevel") ],
		 [ Capacity          => $extent->getProperty("_Capacity") ],
		 [ VolStatus         => $extent->getProperty("_Status")    ],
		]
	  );
#  uint16 DataOrganization;
#  uint16 Access;
#  boolean IsBasedOnUnderlyingRedundancy = "false";

#  string VolWWN;
#  string VolName;
#  uint16 VolErrors;
#  uint16 VolFirmwareErrors;
#  uint16 VolIndex;
#  string VolId;
#  string VolCacheMirror;
#  string VolCacheMode;
#  string VolRaidLevel;
#  string VolStatus;
#  string Type;
#// A3500
#  string Capacity;
#  string LunGroup;


	if ($nws_system){
	  my $mediaPresent = CIM::Instance->new
		 ('CIM_MediaPresent',
		  [
			[Antecedent => $nws_system ],
			[Dependent  => $vol ]
		  ]
		 );
	  return Ilist->new( [$vol, $mediaPresent] );
	}
	return Ilist->new( [$vol]);
}

sub _getModel {
  my ($class);
  if (ref($class) eq "NWS::STD_REPORT"){
	 return $class->{model};
  }
  return undef;
}

sub _isA {
  my ($class, $className, $baseName);
  my $model = $class->_getModel();
  if ($model){
	 return $model->isA($className, $baseName);
  }
  return ($className eq $baseName);
}

1;
