# $Id: COMMON.pm,v 1.1 2004/11/11 19:52:14 jkremer Exp $
# Copyright 2004 Sun Microsystems, Inc., All Rights Reserved.
# Sun Proprietary/Confidential: For Internal Use Only
package Agent::COMMON;

use strict;
use Catalog::Implementation;
use Health::Catalog;
use Data::Dumper;
use Debug;
use Agent;
use base 'Agent';

sub revision { '$Revision: 1.1 $ '}

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

  my $this = { type => $type };
  bless($this, "Agent::COMMON");
  $this->load($type);

  return $this;
}

sub load {
  my($this, $type) = @_;

  my $impl = new Catalog::Implementation($type);
  $this->{impl} = $impl;
}

sub devType {
  my($this) = @_;
  return $this->{type};
}

sub category { 
  my($this) = @_;
  return $this->{category};
}

sub RUN {
  my($this, $static_list, $pass) = @_;

  my $locks = System->get_se_conflict();
  my $report;
  my $processed_list;
  my $dc;

  my @adevs = $this->deviceList($static_list, $this->{type});
  my $devs  = \@adevs;
  if ($this->{forceStatic}){
	 $devs = $static_list;
  }
  foreach my $dev ( @$devs ) {
    next if ($dev->{active} eq "N");
	 Debug->print2("Monitor " . $dev->{key} . " using " .
						$this->{type} . " plug-in agent.");
	 if ($locks && index(",$locks,", ",$dev->{name},") >= 0 ) {
       Debug->print2( "-> $dev->{type}: skipping $dev->{name}, " .
							 "detected device lockfile");
       next;
    }
	 $dc++;
	 my $sys_report = $this->INSTRUMENTATION($dev);
	 my $warn_lines = $this->MESSAGELOG($dev);

	 if (($warn_lines) && ($#$warn_lines >= 0)){
    	my $id =
		  {
			deviceName  =>  $dev->{key},
			active      => "Y",
			display     => $dev->{name},
			name        => $dev->{name},
			class       => $dev->{class},
			category    => $dev->{type} . "message",
			ip          => $dev->{ip}
		  };
    	$report->{"id.name"} = $dev->{name};
    	my $new_rep = Report->new($id, $report , $warn_lines, Report::STATUS_OK);
    	require Health::Message;
    	Health::Message->all_logic($new_rep);
    	PDM->saveReport( $new_rep );
    }

    my $wwn = $dev->{key};
    my $connect_errs = $sys_report->{"rc.error"} ||
		$sys_report->{"error._Description"};

    # SAVE EVENT POINTER.
    my $problems = PDM->get_last_event();

    # CREATE A REPORT HEADER with identification for this report.
    my $agentClass = $this->category() . "." . $this->devType();
    my $report_header = {
			 deviceName => $wwn,
			 active     => $dev->{active},
			 class      => $agentClass,
			 name       => $dev->{name},
			 display    => $dev->{name},
			 category   => $this->devType(),
			 ip         => $dev->{ipno},
			};
    $sys_report = {} if (!$sys_report);
    $this->copyDev($dev, $sys_report);
    my $new_rep;
    if ($connect_errs) {
      $new_rep = Report->new($report_header, $sys_report, undef,
			     Report::STATUS_CANNOT_CONNECT );
    } else {
      Discover->updateTopoDevice($dev, {report => $sys_report});
      Agent->setIdSection($sys_report, $dev->{name},
			  $dev->{mgmtLevel}, $dev->{ip}, $dev->{ipno}, 
			  $dev->{key});
      $new_rep = Report->new($report_header, $sys_report);
    }

    # CALL HEALTH MODULE, generate EVENTS
	 my $health_module = new Health::Catalog($this->{type});
    $health_module->LOGIC($new_rep, $dev);

    # SAVE INSTRUMENTATION REPORT
	 $DB::single=1;
    PDM->saveReport($new_rep);

    # ABORT THE INSTRUMENTATION LOOP if a problem was found.
    my ($broke, $abort) = $this->new_events($problems, $dev, 1);
    push(@$processed_list, $dev);
    last if ($broke && $pass == 1 || $abort);
  }

  # ALWAYS END RUN by returning a list of processed devices.
  return $processed_list;

}


sub INSTRUMENTATION {
  my($this, $device) = @_;

  my $renv = System->get_renv();
  return Report->readTest($device) if (System->get_testMode());

  my $devType = $device->{type};
  my $devKey  = $device->{key};

  Debug->print2("Obtaining Report for $devType $devKey.\n");

  require Java::Report;
  my $R = Java::Report->instrument($device);

  # ADD Site Identification data to the report
  $this->addIdentification($R);

  # ADD 'rc.key' to the report
  $R->{'rc.key'} = $R->{"id.wwn"};
  Timelapse->stopDev( $device);

  # RETURN a pointer to the HASH
  return $R;
}


sub MESSAGELOG {
  my($this, $device) = @_;

  my $type   = $device->{type};
  my $key    = $device->{key};
  my $name   = $device->{name};
  my $ipno   = $device->{ipno};
  my $devKey = "$type:$key";
  my $renv   = System->get_renv();
  my (@err, $l);
  my ($index, @lines, $dev, $marker, $msgList);

  my $LOGName = "messages." . $this->devType();
  my $LOGFile = $renv->{"$LOGName"} || "/var/adm/$LOGName";

  if (System->get_testMode()) {
     # READ FROM messages.<type>
     open(O, $LOGFile);
     while ($l = <O>) {
       chop($l);
       push(@lines, $l);
     }
     close(O);

  } else {
    # READ LOGS FROM DEVICE, SAVE TO messages.<type>
    use DevDB;
    $dev = DevDB->read($devKey);
    $marker = $dev->{log_file_marker};
	 if (!$marker){
		
	 }
    $msgList = Java::Report->message($marker, $device);
	 my $msgs = $msgList->{messages};
		
	 if ($msgs){
		open(O, ">>$LOGFile");
		for($index = 0; $index <= $#$msgs; $index++) {
		  my $msg = $msgs->[$index];
		  my $L = "$msg->{line}";
		  push(@lines, $L);
		  print O "$L\n";
		}
		close(O);
	 }
  }

  # PROCESS LOG ENTRIES, COMING FROM EITHER THE DEVICE OR messages.log
  # Log line format:
  # MMM dd HH:mm:ss device component: [ID 101] ERROR: Description
  my $policies = Policies->new($type . "_policies");
  for ($index = 0; $index <= $#lines; $index++ ) {
	 my $line = $lines[$index];
    my ($mo, $day, $time, $dev, $comp, $ID, $id) = split(/ /, $line);
	 my $cindex = rindex($comp, ":");
	 my $component;
	 if ($cindex > 0){
		$component = substr($comp, 0, $cindex);
	 }
	 my $compKey   = $devKey;
	 if ($component){
		$compKey = "$devKey:$component";
	 }
	 $policies->run(\@err, \@lines, \$index,
		 $component, $name, $compKey, $ipno, $devKey, 1);
  }

  if (!System->get_testMode()) {
    # SAVE MARKER IF NOT IN TEST-MODE
	 if ($msgList->{marker}){
		$dev->{log_file_marker} = $msgList->{marker};
		DevDB->write($devKey, $dev);
	 }
  }

  return (\@err);
}

####################################################################
#
# sub FRUS
# this function returns a standard data-structure for any device
# INPUT : the Instrumentation Report (lib/Report.pm)
# the device name
# OUTPUT: a pointer to a table of frus with one run per fru.
# [
# [ "name", "device_type", "FruType", "FruId",
# "Vendor", "Model", "Serial", "Revision", "Status" ],
# [ "name", "device_type", "FruType", "FruId",
# ]
####################################################################
sub FRUS {
  my($class, $r, $name) = @_;

  my(@F);
  my $devtype = $r->category();
  if (!-f System->get_home() . "/lib/DeviceReport/$devtype.pm") {
    return [];
  }
  require "DeviceReport/$devtype.pm";

  my $pk = "DeviceReport::$devtype";

  my $R = $pk->hash($r);
  my $FRUS = $R->{FRU};


  foreach my $id (keys %$FRUS) {
    my $fru = $FRUS->{$id};
    push(@F, [$name, $devtype, $fru->{type},
		 $fru->{name},
		 $fru->{vendor},
		 $fru->{model},
		 $fru->{serial},
		 $fru->{revision},
              ]);
  }

  return \@F;
}


####################################################################
# sub REPORT: returns html used in GUI to display device Report.
#
# Since the Java framework will use Standard Reports this is all that
# needs to be done.
####################################################################
#use DeviceReport;
#sub REPORT {
#  my($class, $host, $r, $arg) = @_;
#  return if (!$r);
#
#  DeviceReport->standardReport($r, {
#       skipSections => "diskExtent",
#       skipColumns  => "unit.\$caption,disk.\$caption,ctrl.\$caption",
#      }
#  );
#}

1;
