package Client::InstrReport;
use System;
use Util;
use Http;
use Client;
use CIM;
use PDM::ConfigFile;
use Report;
use strict;
use NWS::Schema;
use Modules;

sub revision {
   my $rev = '$Revision: 1.22 $';
   $rev =~ s/\$//g;
   return $rev;
}

sub help {
   print Client->http_OK;
   print <<EOF;
<b>StorADE Client::InstrReport syntax</b><br>
<pre>
 This url can be used to retrieve a list of available reports or a specific
 report from a StorADE agent using different formats and filters.

<b>Examples:</b>
 http://hostname:7654/rashttp?GO=Client::InstrReport::list   # tab format
 http://hostname:7654/rashttp?GO=Client::InstrReport::list&format=xml   # xml format

 http://hostname:7654/rashttp?GO=Client::InstrReport::report&key=se:6910.80a3738d   
 http://hostname:7654/rashttp?GO=Client::InstrReport::report&key=se:6910.80a3738d&format=xml
 http://hostname:7654/rashttp?GO=Client::InstrReport::report&key=se:6910.80a3738d&include=slot.   

<b>Args:</b>
   format: valid formats are string,tab,xml,cim, default is 'tab'.
  include: include only entries that starts with the following.
  exclude: exclude entries that starts with the following.
      key: key is a key returned by InstrReport::list.
    level: s=system, d=device. Used in 'list' to return only system-level or device-level
           reports. System-level are currently 3900/6900 series.

<b>Errors:</b>
  Errors are returned in string/tab format with the following format:

#ERROR&lt;tab>ERR_NO&lt;tab>Text

  and in XML format:

&lt;?xml version="1.0"?>
&lt;ERROR no="ERR_NO">TEXT
&lt;/ERROR>

<b>Comments:</b>
  In tab/string format, entries that with a '#' are comments/error information.
  Basic Authentication is required (user=peer, password=peer).
     http://user:password\@hostname:7654/rashtp?GO=Client::...
  When querying a SE solution rack, the rack is returned by default when no key is specified.

  local Perl programs can be written using storade libraries  and the following equivalent syntax:
  #!/usr/bin/perl -I/iopt/SUNWstade/lib
  use System;
  use Client::InstrReport;

  Client::InstrReport::list({ format => "string"} );
  Client::InstrReport::report({key => "se:6910.80a3738d", format => "cim"}) ;
EOF
}


# level = s : system, d = devices
# host=1    : include 'host' or 'sp'.

sub list {
  my($q, $level, $host, $format) = @_;
  my (%WWN);

  if (Http->isSOAP()) { # pass arguments, don't print
     $q = {};
     $q->{level} = $level;
     $q->{host}  = $host;
     $q->{format} = $format;
     $q->{RETURN} = 1;
     $q->{SOAP}   = 1;
  }

  #------

  my $format = $q->{format} || "tab";
  my $level  = $q->{level};

  my $out;
  $out = Client->http_OK() if (!$q->{SOAP});

  if ($format eq "xml" || $format eq "cim") {
     if(!$q->{noheader}) {
       $out .= &xml_head();
     }
     $out .= "<REPORTLIST>\n";
  } else {
     $out .= "#<pre>\n";
     $out .= "#FORMAT\thost\tkey\ttype\tdate\tname\twwn\n";
  }
     
  my($renv, $devs, $hosts, $notifs) = PDM::ConfigFile->read();
  my($config_wwn_list);
  foreach my $d (@$devs) {
     $WWN{$d->{key}} = $d;
     $config_wwn_list .= "$d->{wwn},$d->{wwn2},$d->{wwns},";
  }
  my $list = Report->reportList();

  foreach my $key (sort keys %$list) {
     my $v = $list->{$key};
     my $info;
     if ($v->[5]) {
       my $x1 = "\$info= " . $v->[5];
       eval $x1;
     }
     my $type = $v->[1];
     my $display_type = $info->{userLabel} || $type;
     next if ($type eq "san" || $type eq "topo");
     next if ($level eq 'd' && $type =~ /se\d*/);
     next if ($level eq 's' && $type !~ /se\d*/);
     my($type0, $key0) = split(/\:/, $key, 2);
     $key0 = substr($key0,2) if (substr($type0,0,4) eq "hbas");

     if (index(",host,sp,", ",$type,") >= 0) {
       next if (!$q->{host});
     } else {
       next if ( (!$WWN{$key0} && substr($type,0,4) ne "hbas") || # not monitored anymore
                 ( substr($type,0,4) eq "hbas") ); # already there.
     }
     #next if (&already_in_config($type, $config_wwn_list, $info));

     my $wwn;
     if ($WWN{$key0}) {
       $wwn = $WWN{$key0}{wwn};
     } elsif ($info->{port_wwns}) {
       ($wwn) = split(/\,/, $info->{port_wwns});
     } else {
        $wwn = $key0;
     }

     if ($format eq "xml" || $format eq "cim") {
        $v->[4] = Client->xmlEncode($v->[4]);
        $out .= " <REPORT host=\"$v->[0]\" key=\"$key\" type=\"$display_type\" date=\"$v->[2]\" name=\"$v->[4]\" wwn=\"$wwn\" />\n";
     } else {
        $out .= "$v->[0]\t$key\t$display_type\t$v->[2]\t$v->[4]\t$wwn\n";
     }
  }
  if ($format eq "xml") {
      $out .= "</REPORTLIST>\n";
  } else {
      $out .= "#DONE\n";
  }
  if ($q->{RETURN}) {
    return $out;
  } else {
    print $out;
  }
}

sub already_in_config {
  my($type, $config_wwn_list, $info) = @_;

  my($found);
  if ($type =~ /^hbas/ && $info) {
     my @L = split(/,/, $info->{port_wwns} );
     foreach my $w (@L) {
       if (index(",$config_wwn_list,", ",$w,") >= 0) {
          $found = 1; last;
       }
     }
  }
  return $found;
}

# url=rashttp?GO=Client::InstrReport::fruList&key=6130:SUN.348-0046776.0412071149
# filter=disk

sub fruList {
  my($q) = @_;
  my $key    = $q->{key};
  my $filter = $q->{filter}; 

  my $list = Report->reportList();
  my $v = $list->{$key};
  my $host = $v->[0];

  my ($err, $report) = Report->readReport($key, $host);
  if ($err) {
     print Client->error("xml", 101, "Error reading report $key: $err");
     return;
  }
  print Client->http_OK();

  my($device_type, $key0) = split(/\:/, $key);

  my $module = "DeviceReport::" . uc($device_type);
  my $rc = Modules->loadOne($module);
  my($S, $out) = $module->xmlFruList($report, $q);
  print $out;
  
}


sub summary {
  my($q) = @_;
  my $key     = $q->{key};
  my $summary = $q->{summary};
  my $normal  = $q->{normal};  # normalized format

  my $renv = System->get_renv();

  # if the host is not passed in
  # check the report to see which host/agent is monitoring
  # this device
  my $host;
  if (defined($q->{host})) {
    $host = $q->{host};
  } else {
    my $list = Report->reportList();
    my $v = $list->{$key};
    $host = $v->[0];
  }

  my ($err, $report) = Report->readReport($key, $host);
  my $key1 = $key;
  if (!$report) {
    my @K = split(/\:/, $key);
    $key = "$K[0]:IB$K[1]";
    ($err, $report) = Report->readReport($key, $host);
  }


  print Client->http_OK;

  if ($err) {
     print Client->error("xml", 101, "Error reading report $key1: $err");
     return;
  }
  my $id = $report->id();
  my $rep = $report->content();

  if (!$report) {
     print Client->error("xml", 102, "No report for $key1 on $host");
     return;
  }
  my $out =  Client->http_OK();
  my($device_type, $key0) = split(/\:/, $key);

  my $module = "DeviceReport::" . uc($device_type);
  my $rc = Modules->loadOne($module);
  my($hash, $out1) = $module->xmlSummary($report, $q);
  $out .= $out1;
  print $out;
}


sub report {
  my($q) = @_;
  my $key     = $q->{key};

  my $renv = System->get_renv();
  if (!$key && $renv->{solution_model}) {
     $key  =  "se:" . $renv->{solution_model} . "." . System->hostid();
  }

  my $format = $q->{format} || "tab";
  my ($err, $report) = Report->readReport($key, $q->{host});

  if ($err) {
     print Client->error($format, 101, "Error reading report $key: $err");
     return;
  }
  my $id = $report->id();
  my $rep = $report->content();

  if (!$report) {
     print Client->error($format, 102, "No report for $key on $q->{host}");
     return;
  }
  my $host = $q->{host} || $renv->{hostname};
  if ($format eq "xml") {
     my $out =  Client->http_OK();
     $out .= "<?xml version=\"1.0\"?>\n";
     $out .= "<REPORT host=\"$host\" key=\"$key\">\n";
     $out .= $report->toXML();
     $out .= "</REPORT>\n";
     print $out;

  } elsif ($format eq "cim") {
     print Client->http_OK();
     print "<?xml version=\"1.0\"?>\n";
     my($type, $k) = split(/\:/, $key);
     my $cim_class = "NWS::" . uc($type);
     Modules->loadOne($cim_class);

     NWS::Schema->init();
     CIM->version("1.1");
     my $cim_object = $cim_class->newSystem($rep);
     print "<CIMObject key=\"$key\">\n";
     print $cim_object->toXML();
     print "</CIMObject>\n";

  } elsif ($format eq "string") {
    print Client->http_OK();
    print "#<pre>\n";
    print "#revision = " . &revision() . "\n";
    print $report->toString({exclude => $q->{exclude}}, include => $q->{include} );
    print "#DONE\n";

  } else {
    print Client->http_OK();
    print "#<pre>\n";
    print "#revision\t" . &revision() . "\n";
    print $report->toTab({exclude => $q->{exclude},  include => $q->{include} } );
    print "#DONE\n";
  }

}


#
# Client::InstrReport::attributeInfo&key=6020:fruStatus
#
sub attributeInfo {
  my($q) = @_;
  my $attr = $q->{key};
  require DeviceGrid;
  my $info = DeviceGrid->read($attr);
  if (!$info) {
     print Client->error("xml", 401, "No information for $attr");
     return;
  }
     
  print Client->http_OK();
  print <<EOF;
<INFO>
  <KEY>$attr</KEY>
  <CATEGORY>$info->{cat}</CATEGORY>
  <ACCESS>$info->{access}</ACCESS>
  <DESC>$info->{desc}</DESC>
</INFO>
EOF

}

  


#########
#  XML
#########
# <!DOCTYPE RAIDBaseView SYSTEM "Raid.dtd">

sub xml_head {
  return <<EOF;
<?xml version="1.0"?>
EOF
}



1;
