package Catalog::Matrix;
use Catalog::RF;
use base 'Catalog::RF';
use strict;

###################################################
# MATRIX FILE
#
# Revision Matrix
# Author: Christian Cadieux
# Transform back and forth between storade resource files and XML documents.

# Matrix      : System/Matrix
#               $matrix = Catalog::RF->parseMatrixFile(
#                        "System/Matrix/config-matrix");
#               print $matrix->toMatrix($matrix);

# [PATCH_LIST]
#  #       OS      Patches   Storage       Comments
#       ---     -------   -------       --------
#       5.5.1 : 103346    : !SR       : Ultra Enterprise 
#       5.5.1 : 104708-21 :           : ssd, pln, soc, 
#       5.5.1 : 105310-14 :           : SunOS 5.5.1: Patch 
#       5.5.1 : 105324-04 :           : ses driver patch
# [HBA_FCODE]
# OS      Name       Version          Reg       Rev    Patch
# ---     ----       -------          -------   -----  ------
# 5.5.1 | Soc+  | @\(#\) FCode  | !0000000d | 1.13 | 109400-03

# <matrix>
#  <section name=PATCH_LIST titles="OS,Patches,Storage,Comments">
#    <entry>
#      <value name=OS>5.5.1</value>
#      <value name=Patches>103346</value>
#    </entry>
#    <entry no=2>
#      <value...>
#    </entry>
# </section>
# <section ...>
#
###################################################

sub info {
  return { ROOT => "matrix",
          hash  => { section => "name" },
          array => { entry => 1, value => 1 }};
}

sub toCatalog {
  my($class, $arg) = @_;
  my $D = System->get_home() . "/System/Matrix/config-matrix";

  my $diag = $class->parseFile("/System/Matrix/config-matrix");
  my $tests = $diag->{matrix}{section};
  my(%D2);
  foreach my $name (keys %$tests) {
      next if ($name eq "_ATT");
      my $type = lc($name);
      if (index(",PATCH_LIST,DISK_FW,IB_FIRMWARE,HBA_FCODE,",",$name,") >= 0) {
         $type = "hba";
      } elsif ($name eq "T3B") {
         $type = "t3";
      } elsif ($name =~ /SWITCH/) {
         $type = "switch";
      } elsif ($name =~ /(.+)_DISK_FW/) {
         $type = lc($1);
      } elsif ($name =~ /SPIMAGE/) {
         $type = "sp";
      }

      if ($type) {
        $D2{$type}{$name} = $tests->{$name};
      } else {
        print "Error: no devType for Matrix:$name \n";
      }
  }

  my $C = System->get_home() .  Catalog->device_path();
  foreach my $t (keys %D2) {
      mkdir "$C/$t",0777 if (!-d "$C/$t");
      my $d = $class->new( $D2{$t});
      open(W, ">$C/$t/matrix.xml");
      print W $d->toXML();
      close(W);
  }
}

sub new {
  my($class, $rep) = @_;
  my $d =  {matrix => {  _ATT => { revision => "\$" . "Revision:\$" },
                      section => $rep },  _ARG => $class->info()};

  bless($d, "Catalog::Matrix");
  return $d;
}

sub fromCatalog {
  my($class, $arg) = @_;
  my $base = $arg->{BASE_DIR} ||  System->get_home() ;
  my $D = $base .  Catalog->device_path();
  chdir $D;
  my @files = `ls */matrix.xml`;

  my $DATA =  Catalog->system_path() . "/Matrix";
  mkdir $DATA,0777 if (!-d $DATA);

  my(%D2);
  open(W, ">$DATA/config-matrix");

  foreach my $f (@files) {
     chomp($f);
     my $rep =  Catalog::XML->parseFile("$D/$f", $class->info());
     if (!$rep) {
         print "Error reading Catalog/device/$f\n";
         last;
     }
     print W $class->toText($rep);
  }
  close(W);
}




sub parseFile {
  my($class, $file, $arg) = @_;

  my $D = $arg->{BASE_DIR} || System->get_home();
  if (open(O, "$D/$file")) {
     my @l = <O>; close(O);
     return $class->parse(\@l, $class->file_name($file));
  } else {
     $class->err("opening $file: $! \n");
     return undef;
  }
}

sub parse{
  my($class, $array, $file_name) = @_;

   my %MAP = (
        PATCH_LIST => [1, "OS,Patches,Storage,Comments" ],
           DISK_FW => [1, "Manufacturer,Model,lvl,Enclosure,limit,patches"],
   DAKTARI_DISK_FW => [1, "Manufacturer,Model,lvl,Enclosure,limit,patches"],
        D2_DISK_FW => [1, "Manufacturer,Model,lvl,Enclosure,limit,patches"],
  INTERNAL_DISK_FW => [1, "Manufacturer,Model,lvl,Enclosure,limit,patches"],
T3_FOR_SPIMAGE_233 => [1, "Manufacturer,Model,lvl,Enclosure,limit,patches"],

        IB_FIRMWARE=> [1, "OS,Enclosure,IB FIRM,patch"],
         HBA_FCODE => [0, "OS,Name,Version,Reg,Rev,Patch"],

             OTHER => [0, "Type,Firmware,Patch,Comments"],
    );


  my $colon_del = ",DISK_FW,PATCH_LIST,IB_FIRMWARE,DAKTARI_DISK_FW,D2_DISK_FW,INTERNAL_DISK_FW,T3_FOR_SPIMAGE_233,";
  my $out .= "<matrix file=\"$file_name\" revision=\"\$" . "Revision:\$\">\n";
  my($x,$section,$format, @labels);
  foreach my $l (@$array) {
    chomp($l);
    next if (substr($l,0,1) eq "=");
    if ($l =~ /^\s*#/) {
        $l =~ s/--/  /g;
        $out .= "<!-- $l -->\n";
        next;
    }
    if ($l =~ /^\[(.+)\]/) {
       $out .= "</section>\n" if ($section);
       $section = $1;
       $format = $MAP{$section} || $MAP{OTHER};
       @labels = split(/\,/, $format->[1]);
       my $del = $format->[0] ? ":" : "|";
       $out .= "<section name=\"$section\" delimiter=\"$del\" titles=\"$format->[1]\">\n";
    } else {
       $l =~ s/^\s+//;
       my @L;
       if ($format->[0]) {
          @L = split(/\s*\:\s*/, $l);
       } else {
          @L = split(/\s*\|\s*/, $l);
       }
       if ($#L > 0) {
         $out .= "  <entry>\n";
         for($x=0; $x <= $#L; $x++) {
           my $v = $L[$x];
           $v =~ s/\&/and/g if (lc($labels[$x]) eq "comments");
           $out .= "    <value name=\"$labels[$x]\">$v</value>\n";
         }
         $out .= "  </entry>\n";
       }
    }
  }
  $out .= " </section>\n";
  $out .= "</matrix>\n";
  my $report = Catalog::XML->parse($out, $class->info());
  bless($report, "Catalog::Matrix");
  return $report;
}

sub toText {
  my($class, $node) = @_;
  $node = $class if (ref($class));
  my $out;

  my $report = $node->{matrix}{section};
  foreach my $sec (sort keys %$report) {
    next if ($sec eq "_ATT");
    $out .= "\n\n[$sec]\n";
    my $del = $report->{$sec}{_ATT}{delimiter};
    $out .= "# $report->{$sec}{_ATT}{titles}\n";
    my $entries = $report->{$sec}{entry};
    foreach my $e (@$entries) {
      my $vs = $e->{value};
      my $line;
      foreach my $v (@$vs) {
        $line .= " $del " if ($line);
        $line .= $v->{_VAL};
      }
      $out .= "$line\n";
    }
  }
  return $out;
}


1;
