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

use Data::Dumper;
use System;
use strict;
use Revision;
use Util;

use vars qw($ERR);

# read latest matrix

sub defaultFile {
    my($class) = @_;
    my ($file, @files);
    opendir(OO, System->get_home() . "/System/Matrix");
    @files = readdir(OO); closedir(OO);
    foreach my $f (sort @files) {
       next if ($f !~ /^config-matrix/);
       $file = $f;
    }
    return $file;
}
  
#  $M = Matrix->read($matrixfile, 
#         {
#             HBA => {SOCAL => 1, IFP => 1, USOC => 1,  PCI => 1, QLC => 1 }
#         });
#
sub read {
    my($class, $matrixfile, $env) = @_;

    $matrixfile = $class->defaultFile()    if (!$matrixfile);
    $env        = Revision->hbas_present() if (!$env);

    my($M) = {}; # matrix
    $ERR = "";

    my ($parse_patches)  = "";
    my $RELEASE = System->os_version();   # 5.9 or 5.8 etc
    my $PLATFORM =  System->model();

    my ($f1, $f2, $f3)   = "";

    my $fname = substr($matrixfile,0,1) eq "/" ? $matrixfile : System->get_home() . "/System/Matrix/$matrixfile";

    if (!open(O, $fname)) {
       $ERR = "Cannot read $fname: $!";
       return undef;
    }
    my($line, $section, $last_command , $sec_name);
    my $index = 0;
    while ($line=<O>) {
        chop($line);
        $line = Util->ltrim($line);
        # Skip blank lines
        next if ($line =~ /^\s*$/);
        next if ($line =~ /^=====/);

        # Skip Comments
        next if ($line =~ /^\s*#/);

        # Set flags if we detect a new section identifier

        # first section sets flags for parsing data
        if ($line =~ /^\[(.*)\]\s*(.*)/) {
           $section = $1;
           $sec_name= $2;
           if ($sec_name) {
             $M->{map}{$section} = $sec_name;
           }
           next;
        }
        if ($section eq "PATCH_LIST") {

           my($temp_os, $patch, $storage, $patch_description) = split(/\s*:\s*/, $line);
           my($storage1, $storage2, $storage3) = split(/,/, $storage);
           my $sname;
           if ($storage1 eq "!SR") {
              $storage1 = ""; $storage2 = "!SR";
           }
           $sname =  ($storage1 || "DEFAULT");

            if ($temp_os eq $RELEASE) {
                # Found a patch, we can do a patch check
                # $PATCH_CHECK_REQUIRED{$temp_os} = "TRUE";

                $M->{info}{PATCH_CHECK_REQUIRED} = 1;

                # Some of the patches are platform specific
                if ($patch =~ /103346/) { 
                    if ($PLATFORM eq "SUNW,Ultra-Enterprise") {
                        $M->{$sname}{$patch} = [1, $patch_description];
                    }
                # 105298 has been obsoleted by 105029
                } elsif ($patch =~ /105298|105029/) {
                    if ($PLATFORM eq "SUNW,Ultra-Enterprise-10000") {
                        my $aprcount = `/bin/pkginfo SUNWapr 2> /dev/null' | /bin/wc -l`;
                        my $apucount = `/bin/pkginfo SUNWapu 2> /dev/null' | /bin/wc -l`; 

                        if (($aprcount !~ /0/) and ($apucount !~ /0/)) {
                            $M->{PATCH}{$sname}{$patch} = [1,$patch_description];
                        }
                    }
                } else {
                    my $flag = 1;
                    $flag = 0 if (index($storage1.$storage2.$storage3,"!SR") >= 0);
                    if ((($storage1 eq "SOCAL") and ($env->{HBA}{SOCAL})) ||
                        (($storage1 eq "USOC") and ($env->{HBA}{USOC}))  || 
                        (($storage1 =~ /PCI/i) and (($env->{HBA}{IFP}) || ($env->{HBA}{QLC}))) ||
                        (($storage1 =~ /IFP/i) and ($env->{HBA}{IFP})) ||
                        (($storage1 eq "QLC") and ($env->{HBA}{QLC})) || ($storage1 eq "")) {
                        $M->{PATCH}{$sname}{$patch} = [$flag, $patch_description];

                    } elsif (($storage1 eq "T3")|| ($storage1 eq "T3B") || ($storage1 eq "A5000") || ($storage1 eq "6120") || ($storage1 eq "3510") || ($storage1 eq "3310") || ($storage1 eq "3120") || ($storage1 eq "3310D") || ($storage1 eq "3320")) {
                        $M->{STORAGE_PATCH}{$sname}{$patch} = [$flag, $patch_description];
                    }
                }
            }

        } elsif ($section eq "DISK_FW") {

            # all disks are now in a matrix                                 #
            # Manufacturer      ID       lvl    Enclosure   limit   patches #

            my ($manuf, $prod_id, $prod_level, $encl_type, $limit, $patch_list);
            ($manuf, $prod_id, $prod_level, $encl_type, $limit, $patch_list) = split(/\s*:\s*/, $line);
            $patch_list =~ s/(.*)#.*$/$1/; # strip comments

            my $cur_id = "$manuf" . ":" . "$prod_id" . ":" . "$encl_type";
            # $M->{DISK_FW}{info}[$index++] = $line;
            $M->{DISK_FW}{$cur_id} = [$prod_level, $limit, Util->rtrim($patch_list)];

            #$DISK_FW_MATRIX{$cur_id} = "$prod_level";
            #$DISK_FW_INFO{$index++} = $line;
            #$DISK_FW_PATCHES{$cur_id} = "$patch_list";
            next;
       } elsif ($section eq "DAKTARI_DISK_FW") {

            # Manufacturer      ID       lvl    Enclosure   limit   patches #

            my ($manuf, $prod_id, $prod_level, $encl_type, $limit, $patch_list);
            ($manuf, $prod_id, $prod_level, $encl_type, $limit, $patch_list) = split(/\s*:\s*/, $line);
            $patch_list =~ s/(.*)#.*$/$1/; # strip comments

            my $cur_id = "$manuf" . ":" . "$prod_id" . ":" . "$encl_type";
            $M->{DAKTARI_DISK_FW}{$cur_id} = [$prod_level, $limit, Util->rtrim($patch_list)];

            next;

       }  elsif ($section eq "D2_DISK_FW") {
          # Manufacturer      ID       lvl    Enclosure   limit   patches #

            my ($manuf, $prod_id, $prod_level, $encl_type, $limit, $patch_list);
            ($manuf, $prod_id, $prod_level, $encl_type, $limit, $patch_list) = split(/\s*:\s*/, $line);
            $patch_list =~ s/(.*)#.*$/$1/; # strip comments

            my $cur_id = "$manuf" . ":" . "$prod_id" . ":" . "$encl_type";
            $M->{D2_DISK_FW}{$cur_id} = [$prod_level, $limit, Util->rtrim($patch_list)];
            next;
       }  elsif ($section =~ /T3_FOR_SPIMAGE/) {
            my ($manuf, $prod_id, $prod_level, $encl_type, $limit, $patch_list);
            ($manuf, $prod_id, $prod_level, $encl_type, $limit, $patch_list) = split(/\s*:\s*/, $line);
            $patch_list =~ s/(.*)#.*$/$1/; # strip comments

            my $cur_id = "$manuf" . ":" . "$prod_id" . ":" . "$encl_type";
            $M->{$section}{$cur_id} = [$prod_level, $limit, Util->rtrim($patch_list)];

       } elsif ($section eq "INTERNAL_DISK_FW"){

            my ($manuf, $prod_id, $prod_level, $encl_type, $limit, $patch_list);
            ($manuf, $prod_id, $prod_level, $encl_type, $limit, $patch_list) = split(/\s*:\s*/, $line);
            $patch_list =~ s/(.*)#.*$/$1/; # strip comments

            my $cur_id = "$manuf" . ":" . "$prod_id" . ":" . "$encl_type";
            $M->{INTERNAL_DISK_FW}{$cur_id} = [$prod_level, $limit, Util->rtrim($patch_list)];
            next;

       }elsif ($section eq "HBA_FCODE") {
            # all FC hba's are now in a matrix                              #
            # OS | Name | Type | Version | Register | Revision | Patch List #

            my ($sun_os, $hba_name, $version, $reg, $fw_rev, $patch_list);
            ($sun_os, $hba_name, $version, $reg, $fw_rev, $patch_list) = split(/\s*\|\s*/, $line);
            
            next if ($sun_os ne $RELEASE);

            $M->{HBA_FCODE}{$hba_name} = [$version, $reg, $fw_rev, $patch_list];
            #$HBA_FCODE{$hba_name} = $line;

        } elsif ($section eq "SEVM") {
           # Veritas changed in Solaris 2.7 to pkg VRTSvxvm

           my ($temp_os, $temp_ver, $temp_patch, $temp_comment) = split(/\s*:\s*/, $line);

           # if $temp_patch is null then Veritas is supported but no patch required
           if ($RELEASE eq $temp_os) {
               if ($temp_patch) {
                  $M->{SEVM}{$temp_ver} = [$temp_patch, $temp_comment];
               }
           }

        } elsif ($section eq "SDS") {
           my ($temp_os, $temp_sds, $temp_patch, $temp_comment) = split(/\s*:\s*/, $line);

           # if $temp_patch is null then SDS Release is supported but no patch required

           if ($RELEASE eq $temp_os) {
               if ($temp_patch) {
                  $M->{SDS}{$temp_sds} = [$temp_patch, $temp_comment];
               }
           }
        } elsif ($section eq "IB_FIRMWARE") {
            # OS     Enclosure   IB firmware    patch

            my ($temp_os, $temp_enclosure, $temp_ib_fw, $temp_patch) = split(/\s*:\s*/, $line);
            next if ($RELEASE ne $temp_os);

            $M->{IB_FIRMWARE}{$temp_enclosure} = [$temp_ib_fw, $temp_patch];

        } elsif ( $section =~ /SPIMAGE/ ) {
            my($type, $firm, $patch, $comment) = split(/\s*\|\s*/, $line);
            $M->{$section}{$type} = [$firm, $patch, $comment];
        } else {
            my($type, $firm, $patch, $comment) = split(/\s*\|\s*/, $line);
            $M->{$section}{$type} = [$firm, $patch, $comment];
        }  
        
    }
    close(O);


    # If we haven't parsed any data there is nothing to print (4186926)
    if (!$M->{info}{PATCH_CHECK_REQUIRED} && ($RELEASE ne "5.10")) {

       $ERR = "Nothing Parsed (101)";
       return undef;
    }
    bless($M, "Matrix");
    return $M;
}



sub toString {
    my($M) = @_;

    $Data::Dumper::Indent = 1;
    return Dumper($M);
}
    


1;
