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

#  $Name: bld21_017 $ 
#  $Id: Report.pm,v 1.14 2005/02/12 21:08:52 kdesai Exp $

use Carp;
use ReportContent;
use strict;

sub revision {'$Revision: 1.14 $'}

use vars qw($ERROR_LOG $WARNING_LOG $NOTICE_LOG  $DEVICE_ERROR $HOST_CONFIG $HOST_DISK_INQ $HOST_DATA_PING $SYSTEM_ERROR $ERR $REMLIST %ISSWITCH $EXCLUDE);

$EXCLUDE = ",3120jbodmessage,3310jbodmessage,3511message,3510message,3310message,t3message,backup,message,san,topo,mpxio,master,";

#
#  $rep = Report->new( { $type, $id, $value, $log_value , $status });
#  Interface:
#   $rep->name
#   $rep->type
#   $rep->category
#   $rep->content
#   $rep->id
#   $rep->created
#   $rep->key


sub STATUS_CANNOT_CONNECT  {'CC'};
sub STATUS_OK              {'OK'};
sub STATUS_DONT_SAVE       {'DONT_SAVE'};

sub CAT_A3500FC          {'a3500fc'};
sub CAT_HBASWITCH        {'hbaswitch'};
sub CAT_HBASTORAGE       {'hbastorage'};
sub CAT_MASTER           {'master'};
sub CAT_DOMAIN           {'domain'};
sub CAT_A1000            {'a1000'};
sub CAT_A2000            {'a2000'};
sub CAT_A3000            {'a3000'};
sub CAT_INTERNAL         {'internal'};
sub CAT_T3               {'t3'};
sub CAT_6120             {'6120'};
sub CAT_6020             {'6020'};
sub CAT_9900             {'9900'};
sub CAT_SE               {'se'};   # indy
sub CAT_SE2              {'se2'};  # maserati
sub CAT_A5K              {'a5k'};
sub CAT_SWITCH           {'switch'};
sub CAT_SWITCH2          {'switch2'};
sub CAT_QLOGICSW         {'qlogicsw'};
sub CAT_V880DISK         {'v880disk'};
sub CAT_BROCADE          {'brocade'};
sub CAT_HOST             {'host'};
sub CAT_DATAHOST         {'datahost'};
sub CAT_BACKUP           {'backup'};
sub CAT_ST4              {'st4'};
sub CAT_MESSAGE          {'message'};
sub CAT_T3MESSAGE        {'t3message'};
sub CAT_DSPMESSAGE       {'dspmessage'};
sub CAT_TRAPMESSAGE       {'trapmessage'};
sub CAT_SAMLOG           {'samlog'};
sub CAT_SAMAGENT         {'samfs'};
sub CAT_EMAILMESSAGE       {'emailmessage'};
sub CAT_3310MESSAGE      {'3310message'};
sub CAT_5210MESSAGE      {'5210message'};
sub CAT_5310MESSAGE      {'5310message'};
sub CAT_3510MESSAGE      {'3510message'};
sub CAT_3511MESSAGE      {'3511message'};
sub CAT_3250NMESSAGE     {'3250Nmessage'};
sub CAT_SAN              {'san'};
sub CAT_TOPO             {'topo'};
sub CAT_TAPE             {'tape'};
sub CAT_SP               {'sp'};
sub CAT_WHAT             {'what'};
sub CAT_D2               {'d2'};
sub CAT_VE               {'ve'};
sub CAT_SVE              {'sve'};     # SUN VE
sub CAT_SVE2             {'sve2'};
sub CAT_DSP              {'dsp'};
sub CAT_MCDATA           {'mcdata'};
sub CAT_HITACHI          {'hitachi'};
sub CAT_3310             {'3310'};
sub CAT_3310JBOD         {'3310jbod'};
sub CAT_5210             {'5210'};
sub CAT_5310             {'5310'};
sub CAT_3120JBOD         {'3120jbod'};
sub CAT_3510             {'3510'};
sub CAT_3511             {'3511'};
sub CAT_3250N            {'3250N'};
sub CAT_LEGACY           {',a1000,a3500fc,a5k,internal,v880disk,tape,d2,3310'}

%ISSWITCH = (
    switch    => 1,
    switch2   => 1,
    brocade   => 1,
    mcdata    => 1,
    ve        => 1,
    sve       => 1,
    sve2      => 1,
    );


$ERROR_LOG       = 'L1';
$WARNING_LOG     = 'L2';
$NOTICE_LOG      = 'L3';
$DEVICE_ERROR    = 'x';
$HOST_CONFIG     = 'y';
$HOST_DISK_INQ   = 'h';
$HOST_DATA_PING  = 'p';
$SYSTEM_ERROR    = 'e';

#$id = { 
#        deviceName => $wwn,
#        name        => $device->{name},
#        category    => Report::CAT_T300,
#        ip          => $device->{ip},
#      };



sub new {
  my($class, $id, $report, $warn_log, $error, $err_log) = @_;

  my(%id2);
  $id2{_id}         = $id;
  croak("Id need deviceName") if (!exists($id->{deviceName}));
  $id2{_created}    = Util->get_today;
  $id2{_value}      = $report || {};
  $id2{_log}        = $warn_log;
  $id2{_logErr}     = $err_log;
  $id2{_status}     = $error || 'OK';

  my($r) = \%id2;
  bless($r, "Report");
  return $r;
  
}



# 
# PUSH ReportsList to Master
#
sub pushReportsList {
  my($class, $master, $force) = @_;
  require Util::Http;
  my($url, $err, $ans, $list);
  $master = Util->findMaster();
  my($renv) = System->get_renv;

  if ($master) { # you are a slave
    my($hostname) = $renv->{hostname};
    $list = Report->makeLocalReportList();
    ($err, $ans)  = Util::Http->saveFile($master, "REMOTE_LISTS/$hostname", $list, 20);
    if ($err) {
      Debug->print2("Cannot push reportList: $err");
    }
  } else { # save reportList locally
    $list = Report->makeLocalReportList();
    open(O, ">" . System->get_home() . "/DATA/REMOTE_LISTS/$renv->{hostname}");
    print O $list;
    close(O);
  }
}


sub list {
  my($class, $filter, $details) = @_;

  my($D) = System->get_home() . "/DATA/OLD_REPORTS";
  opendir(O, $D);
  my(@dirs) = readdir(O); closedir(O);
  my(@out);

  foreach my $d (@dirs) {
     my @bb = split(/:/, $d);
     next if ($#bb != 1 || (index(",sp,host,san,topo,", ",$bb[0],") >= 0));
     next if ($filter && index(",$filter,", ",$bb[0],") < 0);
     open(O, "$D/$d");
     my(@a) = <O>; close(O);
     my($VAR1);
     eval "@a";
     if ($VAR1) {
       my($name)   = $VAR1->{_id}{name};
       my($created) = $VAR1->{_created};
       my($type, $key) = split(/:/, $d);
       my $dd = $VAR1->{_value} if ($details);
       push(@out, [$type, $key,$created, "AccessName", $name, $dd]);
     }
  }
  return \@out;
}

#  filename=date=XX=name

sub makeLocalReportList {
  my($report) = @_;
  my($VAR1);
  my($D) = System->get_home() . "/DATA/OLD_REPORTS";
  opendir(O, $D);
  my(@dirs) = readdir(O); closedir(O);
  my($out);

  foreach my $d (@dirs) {
     my @bb = split(/:/, $d);
     next if ($#bb != 1);
     open(O, "$D/$d");
     my(@a) = <O>; close(O);
     eval "@a";
     if ($VAR1) {
       my($name)   = $VAR1->{_id}{name};
       my($created) = $VAR1->{_created};
       my $info     = $VAR1->{_value}{'info.remote_list_info'};
       $out .= "$d=$created=AccessName=$name=$info\n";
     }
  }
  return $out;
}


#
# looks in OLD_REPORTS and REMOTE_LISTS for the host of a report.
#
sub findReportHost {
  my($class, $key) = @_;
  my($l);
  if (-f System->get_home() . "/DATA/OLD_REPORTS/$key") {
     return ""; # LOCAL
  }
 
  my $D =  System->get_home() . "/DATA/REMOTE_LISTS";

  opendir(O, $D); my @files = readdir(O); closedir(O);
  foreach my $f (@files) {
    next if (substr($f,0,1) eq ".");
    open(O, "$D/$f");
    while ($l = <O>) {
      chop($l);
      my @a = split(/=/, $l);
      if ($a[0] eq $key) {
         close(O);
         return $f;
      }
    }
    close(O);
  }
  return undef;
}

sub copyFromOld {
  my($class, $key, $report, @prefix) = @_;
  my $old = $class->readLocal($key);
  my $old_v = $old->value();
  foreach my $el (keys %$old_v){ 
     foreach my $p (@prefix) {
       if ($el =~ /^$p/) {
          $report->{$el} = $old_v->{$el};
          last;
       }
     }
  }
}

# replace a sequenceid with an actual value
# works only in position #2
# fcserver.1.anything = fcserver.(fcserver.1.Wwn).anything
# NOT USED YET
#
sub convert {
  my($class, $rep, $prefix, $key) = @_;
  my $new = {};
  foreach my $e (keys %$rep) {
      next if (substr($e,0,length($prefix)) ne $prefix);
      my ($name, $replace, $rest) = split(/\./, $e, 3);
      if ($rest) {
        my $replaced = $rep->{"$name.$replace.$key"};
        $new->{"$name.$replaced.$rest"} = $rep->{$e};
      } else {
        $new->{$e} = $rep->{$e};
      }
  }
  return $new;
}


#  read report from a file
#  $rep1 = Report->readLocal("a5k:12321321");

sub readLocal {
  my($class, $file) = @_;
  my($VAR1);

  my($D) = System->get_home() . "/DATA/OLD_REPORTS";

  if (open(O, "$D/$file")) {
    my(@a) = <O>; close(O);
    eval "@a";
    return $VAR1;
  } else {
    return undef;
  }
}
$REMLIST = undef;
#   ALL REPORTS (local and remote by key)
#   $rm = Report->reportList(); 
#   $rm->{"t3:11232132"} = [host, type, date, name, name2] # no type in the key
#
sub reportList {
  my($class) = @_;
  my (@R, %RM);
 # return $REMLIST if ($REMLIST);

  my $RM = System->get_home() . "/DATA/REMOTE_LISTS";
  opendir(O, $RM);
  my @L = readdir(O); closedir(O);
  foreach my $l (@L) {
     next if (substr($l,0,1) eq ".");
     open(O, "$RM/$l");
     my $r;
     while ($r = <O>) {
        chop($r);
        my($key, $date, $name, $name2, $wwns) = split(/\=/, $r, 5);
        next if (!$key);
        next if ($key =~ /^hbaswitch\:switches/);
        next if ($key =~ /^hbastorage\:hbas/);
        my($type, $k) = split(/\:/, $key);
        $RM{$key} =  [$l, $type, $date, $name, $name2, $wwns];
     }
     close(O);
  }
  $REMLIST = \%RM;
  return $REMLIST;
}

sub deleteFromList {
  my($class, $file, $key) = @_;
  my $RM = System->get_home() . "/DATA/REMOTE_LISTS/$file";
  my($new, $l);
  open(O, $RM);
  while ($l = <O>) {
     my(@els) = split(/\=/, $l);
     if ($els[0] ne $key) {
        $new .= $l;
     }
  }
  close(O);
  open(W, ">$RM");
  print W $new;
  close(W);
}


#
#  host = "*" means find the host
#  ($err, $report) = Report->readReport("121212", "*"); # no type required if "*" is used
#  ($err, $report) = Report->readReport("121212" ); # * automatic if type is missing
#  ($err, $report) = Report->readReport("ve:1231232131", [ host ]);

sub readReport {
  my($class, $key, $host, $to, $arg) = @_;
  my($type, $VAR1, $data);
  require Util::Http;
  my($renv) = System->get_renv();
  $to = 10 if (!$to);
  $ERR = undef;
  $host = "*" if (index($key, ":") < 0);

  if (!$host || $host eq $renv->{hostname} ) { # local
    if (-f System->get_home() . "/DATA/OLD_REPORTS/$key") {
      $data = &get_instr_report({file  => $key});
    } else {
      $data = "ERR No report available!";
    }
  } elsif ($host eq "*") { # find the host
    my $rm = Report->reportList();
    if (!$rm->{$key}) {
       $data = "ERR No report available!";
    } else {
      my $dev = $rm->{$key};
      $host = $dev->[0];
      if ($host eq $renv->{hostname}) {
        $data = &get_instr_report({file  => $key});
      } else {
        $data = Util::Http->readFile($dev->[0], "OLD_REPORTS/$key", $to, $arg);
      }
    }
  } else {
    $data = Util::Http->readFile($host, "OLD_REPORTS/$key", $to, $arg);
  }

  if (substr($data,0,3) eq "ERR") {
     $ERR = $data;
     return ($ERR, undef);
  } elsif (!$data) {
     $ERR = "No Report available!";
     return ($ERR, undef);
  } else {
     if ($data =~ /\s*\$VAR1 =/) {
       eval $data;
       return (undef, $VAR1, $host);
     } else {
       return ("ERR: $data", undef, $host);
     }
  }
}
        


# static
# use host to call remote machine
# use fileName, wwn or enc-name in this order

#  Report->readNet({ host     => 'ccdev',  
#                          timeout => 20,
#                          file     => 'asdsad',
#                          wwn      => '123213',
#                          name     => 'diag189'}
#                        );

sub readSpecial {
  my($report, $arg) = @_;
  my($host) = $arg->{host};
  require Util::Http;
  my($data, $q);
  my($to) = $arg->{timeout} || $main::TO;
  my($CD) = System->get_home() . "/DATA/remote";
  my($url);

  if (!$arg->{name} && !$arg->{file} && !$arg->{wwn}) {
     return "ERR No argument (name, wwn, filename) ";
  }
  if ($host) {
      my $command ;
      if ($arg->{file}) {
        $command = "FILER&file=OLD_REPORTS/$arg->{file}";
      } else {
        $command = "Report::instr_report&file=$arg->{file}&name=$arg->{name}&wwn=$arg->{wwn}&HTTP=1";
      }
      $data = Util::Http->getCommand($host, $command, $to);
      if ($arg->{file}) {
        my($cache) = $CD . "/$arg->{file}";
        mkdir $CD, 0777 if (!-d $CD);
        open(O, ">$cache");
        print O $data; close(O);
      }
  } else {
      $q->{HTTP} = undef;
      $q->{file} = $arg->{file};
      $q->{wwn} = $arg->{wwn};
      $q->{name} = $arg->{name};
      $data = &get_instr_report($q);
  }

  if (!$data) {
    return ("Cannot retrieve $arg->{name} $arg->{file} from $host ($Util::Http::ERROR)<br>",undef)
  }
  if (substr($data,0,3) =~ "ER") {
    return ($data, undef);
  }
  my($VAR1);
  eval $data;

  if (!$VAR1) {
    return ("$arg->{name} $arg->{file} not found on $host!<br>", undef);
  }
  if ($host && !$arg->{file}) {
    my($id) = $VAR1->{_id};
    my($cache) = "$CD/" . $id->{category} . ":" . $id->{deviceName};
    mkdir $CD, 0777 if (!-d $CD);
    open(O, ">$cache");
    print O $data; close(O);

  }
  return (undef, $VAR1);

}

# called locally or remotely 

sub get_instr_report {
  my($q) = @_;
  my($l);
  my($P) = System->get_home() . "/DATA/OLD_REPORTS";
  my($out);

  if ($q->{file}) {   #got a file name
    if (open(O, "$P/$q->{file}")) {
      while ($l = <O>) {
        $out .= $l;
      }
      close(O);
    } else {
      $out = "ERR File $q->{file} does not exist!";
    }
  } elsif ($q->{name} || $q->{wwn}) { # got an enclosure name
     my($wwn);
     if (!$q->{wwn}) {
        $wwn = PDM->name2wwn($q->{name});
     } else {
        $wwn = $q->{wwn};
     }
     $out = "ERR $q->{name}/$q->{wwn} not found";
     opendir(O, $P);
     my(@dirs) = readdir(O); closedir(O);
     foreach my $d (@dirs) {
        if ($d =~ /$wwn/) {
           $out = Util->readf("$P/$d");
           last;
        }
     }
  }

  if ($q->{HTTP}) {
    print "\n$out";
  } else {
    return $out;
  }
}
  

sub writeReport {
  my($report, $r) = @_;
require Data::Dumper;

  $Data::Dumper::Indent = 1;
  my($key) = $report->fileKey();
  open(O, ">" . System->get_home() . "/DATA/OLD_REPORTS/$key");
  print O Data::Dumper::Dumper($r);
  close(O);
}


# returns a hash only
#
sub readTest {
  my($class, $dev) = @_;
  my $VAR1;
  my $key = "$dev->{type}:$dev->{key}";

  my $D = System->get_home() . "/DATA/TEST_REPORTS/$key";
  if (-f $D) {
    open(O, $D); my @l = <O>; close(O);
    eval "\$VAR1 = { @l };";
    $VAR1->{'rc.error'} = $VAR1->{'id.connect_errs'};
    return $VAR1;

  } else {
    Debug->err(TEXT => "Cannot find test report for $dev->{name}/$dev->{ipno}");
    my $r = {};
    bless($r, "Report");
    return $r;
  }
}


sub copyToOld {
  my($class) = @_;
  my $D = System->get_home() . "/DATA";
  my $OR = "$D/OREPORTS";
  mkdir $OR, 0777 if (!-d $OR);

  system("/bin/cp -r $D/OLD_REPORTS/* $OR");
}

sub readNew {
  my($class, $key) = @_;
  return Util->deserialize("/OLD_REPORTS/$key");
}
  

sub readOld {
  my($class, $key) = @_;
  my $VAR1;
  my $D = System->get_home() . "/DATA/OREPORTS/$key";
  if (-f $D) {
    open(O, $D); my @l = <O>; close(O);
    eval "@l";
    return $VAR1;

  } else {
    return undef;
  }
}

sub newReportList {
  my($class, $filter) = @_;
  my $D = System->get_home() . "/DATA/OLD_REPORTS";
  opendir(O2, $D);
  my @list = readdir(O2); closedir(O2);
  my @L;
  foreach my $f (@list) {
     next if (substr($f,0,1) eq ".");
     my($type, $key) = split(/\:/, $f);
     next if ($filter  && index(",$filter,", ",$type,") < 0);
     push(@L, $f);
  }
  return \@L;
}
  


# will return a new report or the old one if communication was lost
# uses deviceName as Key

sub saveNew {
  my($report) = @_;
  my $key = $report->fileKey();
  my $renv = System->get_renv();

  if ($key) {
     Util->serialize("OLD_REPORTS/$key", $report);
     if ($renv->{report_trace_dir} && -d $renv->{report_trace_dir} ) {
       my $ts = Util->get_today();
       $ts =~ s/[ \:]//g;
       require Data::Dumper;
       $Data::Dumper::Indent = 1;
       my $out = Data::Dumper::Dumper($report);
       if (open(OO, ">$renv->{report_trace_dir}/$key.$ts")) {
          print OO $out;
          close(OO);
       }
     }
  }
}

#
# copy _value section from OLD_REPORT into $report
#
sub copyOld {
  my($report) = @_;
  my($old_report) = Report->readLocal($report->fileKey() );

  my $old  = $old_report->{_value};
  my $new  = {};
  foreach my $v (keys %$old) {
     $new->{$v} = $old->{$v};
  }
  $report->{_value} = $new;
}



# used when communication is lost and no instr-report was generated
# will merge information from rasagent with last good instr-report.

sub updateStatus {
  my($report) = @_;
  my ($x);
  my($old_report) = Report->readLocal($report->fileKey() );
  if ($old_report) {
    $old_report->{_status} = $report->{_status};
    my($val) = $old_report->{_value};
    my($new)  = $report->{_value};
    foreach my $v (keys %$new) {    # update all information from the new report
       $val->{$v} = $new->{$v};
    }

    $old_report->saveNew();
    # $report->writeReport($r);
  } else {
    my $display = $report->displayName();
    Debug->errNoRepeat(CANNOT_READ_OLD => $report->fileKey(), 24, 
        "Device $display needs to be deleted from the configuration (Maintain_Devices)" );
  }
}

sub setStatus {
  my($report, $val) = @_;
  $report->{_status} = $val;
}

sub status {
  my($report) = @_;
  return $report->{_status};
}

#  remove this once patch for brocade is out
sub accessName {
  my($report) = @_;
  return $report->{_id}{accessName};
}

  
sub deviceName {
  my($r) = @_;
  return  $r->{_id}{deviceName};
}

sub displayName {
  my($r) = @_;
  my $name;
  $name = $r->{_id}{category};
  $name .= ":" . $r->{_id}{name};
  $name .= "($r->{_id}{ip})" if ($r->{_id}{name});
  return $name;
}
  

#
# used to store this report in the file-system

sub fileKey {
  my($r) = @_;
  return  lc($r->{_id}->{category}) . ":" . $r->{_id}{deviceName};
}

sub makeFileKey {
  my($r, $cat, $deviceName) = @_;
  return lc($cat) . ":$deviceName";
}
  

sub name {
  my($report) = @_;
  return $report->{_id}{name};
}


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

sub value {
  my($report, $id, $value) = @_;
  if (defined($value) && $id) {
    $report->{_value}{$id} = $value;
    return $value;
  } elsif ($id) {
    return $report->{_value}{$id};
  } else {
    return $report->{_value};
  }
}

sub subset {
  my($report, $val) = @_;
  $report = $report->content();
  return $report->subset($val);
}

sub content {
  my($report) = @_;
  
  return ReportContent->new($report->{_value});
}

sub logError {
  my($report) = @_;

  return $report->{_logErr};
}

sub log {
  my($report) = @_;

  return $report->{_log};
}

sub toTab {
  my($r, $arg) = @_;
  my $summary = $arg->{summary};
  my $exclude = $arg->{exclude};
  my $include = $arg->{include};
  my $id  = $r->id();
  my $rep = $r->content();
  my $out = "header.created\t$r->{_created}\n";
     $out .= "header.status\t$r->{_status}\n";
     $out .= "header.status_details\t$rep->{'id.connect_errs'}\n";

  foreach  my $v (sort keys %$id) {
     $out .= "header.$v\t$id->{$v}\n";
  }
  my $last;
  foreach my $v (sort keys %$rep) {
      my($tag, $rest) = split(/\./, $v, 2);
      next if ($summary && $rest =~ /\.stats\./);
      next if ($exclude && substr($v,0,length($exclude)) eq $exclude);
      next if ($include && substr($v,0,length($include)) ne $include);
      $out .= "$v\t$rep->{$v}\n";
  }
  return $out;
}

sub toString {
  my($r, $arg) = @_;
  my $summary = $arg->{summary};
  my $exclude = $arg->{exclude};
  my $include = $arg->{include};
  my $id  = $r->id();
  my $rep = $r->content();
  my $out .= "HEADER\n";
  $out .= sprintf("  %-30s: %s\n", "created", $r->{_created});
  $out .= sprintf("  %-30s: %s\n", "status",  $r->{_status});
  $out .= sprintf("  %-30s: %s\n", "status_details",  $rep->{'id.connect_errs'});

  foreach  my $v (sort keys %$id) {
     $out .= sprintf("  %-30s: %s\n", $v, $id->{$v});
  }
  my $last;
  foreach my $v (sort keys %$rep) {
      my($tag, $rest) = split(/\./, $v, 2);
      if ($tag ne $last) {
         $out .= "SECTION_$tag" . "\n";
         $last = $tag;
      }
      next if ($summary && $rest =~ /\.stats\./);
      next if ($exclude && substr($v,0,length($exclude)) eq $exclude);
      next if ($include && substr($v,0,length($include)) ne $include);
      $out .= sprintf("  %-30s: %s\n", $rest, $rep->{$v});
  }
  return $out;
}

# by default, toXML will not include the <REPORT> ... </REPORT> tags
#
sub toXML {
  my($r, $arg) = @_;
  my $out;
  my $header  = $arg->{header};
  my $summary = $arg->{summary};

  $out = "<REPORT>\n" if ($header);
  my $id  = $r->id();
  my $rep = $r->content();

  $out .= "  <HEADER>\n";
  $out .= "    <VALUE ID=\"created\">$r->{_created}</VALUE>\n";
  foreach my $v (sort keys %$id) {
      $out .= "    <VALUE ID=\"$v\">$id->{$v}</VALUE>\n";
  }
  $out .= "  </HEADER>\n";
  my $last;
  $out .= "  <CONTENT>\n";
  foreach my $v (sort keys %$rep) {
      my($tag, $rest) = split(/\./, $v, 2);
      next if ($summary && $rest =~ /\.stats\./);
      $out .= "    <VALUE ID=\"$v\">$rep->{$v}</VALUE>\n";
  }
  $out .= "  </CONTENT>\n";
  return $out;
}
  


sub deviceInfo {
  my($r, $key) = @_;

  if (exists($r->{_value})) {
    return $r->{_value}{"id.device_$key"};

  } elsif (exists($r->{"id.device_$key"})) {
    return $r->{"id.device_$key"};
  } 
  return undef;
}

sub id {
  my($r, $key, $value) = @_;

  if ($key && $value) {
     my $save = $r->{_id}{$key};
     $r->{_id}{$key} = $value;
     return $save;

  } elsif ($key) {
     return $r->{_id}{$key};
  }
  return $r->{_id};
}

sub created {
  my($r) = @_;
  return $r->{_created};
}

#################################################################
#
#  xml2report
#  translate a xml report into a . delimited report
# 
# $report = {};
# $prefix = "";
# $array_list = ",devent,ident_data,";   # which tag is an array
# $word_map   = { "msg_response" => "resp" }; # word translation

# $error = Report->xml2report( $report, $xml_text, $prefix, 
#                              $array_list, $word_map);
# 


sub xml2report {
  my($class, $report, $text, $prefix, $array_list, $word_map)  = @_;

  require XML::LibXML;
  my $dom;
  my $parser = XML::LibXML->new();
  eval {
     $dom  = $parser->parse_string("<ROOT>$text</ROOT>");
  };
  if ($@) {
     return $@;
  }
  my(%MAP);

  my $elem  = $dom->getDocumentElement();
  $class->xml2report_($report, $elem, $prefix, 0, \$array_list, $word_map, \%MAP);
  foreach my $el (sort keys %MAP) {
    $report->{"$el.COUNT_"} = $MAP{$el};
  }
  return undef;
}

sub xml2report_ {
  my($class, $report, $node, $prefix, $level, $array_list, $word_map, $MAP)  = @_;
  my $prefix0 = "$prefix." if ($prefix);
  require XML::LibXML;

  foreach my $el ($node->getChildNodes()) {
    next if ($el->getType() != &XML::LibXML::ELEMENT_NODE() );
    my $name0 = $el->getName();
    my $name  = $word_map->{$name0} || $name0;
    my $pr;
    my @ch1 = $el->getChildNodes();

    # try to define $pr
    # IS it an attribute that should be mapped to an array
    if (index("$$array_list,", ",$name,") >= 0) {
      $MAP->{"$prefix0$name"}++;
      $pr = "$prefix0$name." . $MAP->{"$prefix0$name"};

    # on the first level, add 'info'.
    } elsif ($level == 0 && $#ch1 == 0) {
      $pr = "info.$name";

    # else, add the prefix that was passed recursively.
    } else {
      $pr = "$prefix0$name";
    }
    my @attributes = $el->attributes();
    foreach my $att (@attributes) {
        my $t = $att->getType();
        my $name = $att->name();
        my $val  = $att->value();
        if ($name) {
          $report->{"$pr.$name"} = $val;
        }
    }

    if ($#ch1 == 0) {
       $report->{$pr} = $el->textContent();
    } else {
       $class->xml2report_($report, $el, $pr, $level+1, $array_list, $word_map, $MAP);
    }
  }
}




                          
1;



# 1;
#


__END__

=head1 NAME

Report.pm - Class that contains instrumentation reports


=head3 SYNOPSIS

 use Report;

 $rep = Report->new({ ... });


=head3 DESCRIPTION

This module create reports from instrumention or from saved files.



=head3 CONSTRUCTOR

=over 4

=item new( <type>, <device_id>, <report_hash> );

 Example:
   $id = {
           acceName     => $dev_name,
           deviceName   => $dev_name,
           category     => Report::CAT_A3500FC,
           ip           => 'NOIP',
           key_type     => "ctrl_id",
           key_value    => $internal_name,
         };

   $report = Report->new($id, $sys_report);


=back 4


=head3 METHODS

=over 4

=item status();

return the status of the Report.

=item name();

returns the name of the device report.

=item category();

returns the category of the report.

=item content();

returns a ReportContent object.

 Example:
  print $content->get('disk.u1d1.state');

=item log();

returns loglines from the message files.


=item created();

returns creation date of the report.

=item deviceKey();

returns category . ":" . name ;

=item key();

returns type . ":" . category . ":" . name ;


=back 4

=head3 SEE ALSO




=head3 AUTHOR

 Christian Cadieux (ccadieux@central.sun)



=head3 COPYRIGHT

Copyright (c) 2000 Sun Microsystems

=cut
