package MG::T3;

use Parse;
use Agent::T3;
use MG::RC;
use Net::Telnet;
use strict;


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

  my $obj = { dev => $dev , READONLY => 1};
  bless($obj, "MG::T3");
  return $obj;
}

sub dev {
  my($obj) = @_;
  return $obj->{dev};
}


# retrn (error, $t);
sub connect {
  my($obj, $force) = @_;
  return (undef,$obj->{connect}) if ($obj->{connect} && !$force);

  my $dev = $obj->{dev};
  my $t  = new Net::Telnet (
              errmode   => "return",
              Timeout   => 30,
              Prompt    => '/<\d+\>/'
               );

   if (!defined($t->open($dev->{ipno}))) {
      return ("Cannot open $dev->{ipno}");
   }
   $t->login("root", System->getDevicePassword($dev, "array") || "X");
   if ($t->errmsg()) {
      return ($t->errmsg());
   }
   $obj->{connect} = $t;
   return (undef, $t);
}

# return a range of frus in same unit.
sub fruGroup {
  my($obj, $fru) = @_;

  my $dev = $obj->dev();

  $fru =~ /u(\d)(\D+)(\d+)/;
  my $u    = $1;
  my $type = $2;
  if ($type eq "d") {
     return "u$u" . ($dev->{type} =~ /6[01]20/ ? "d1-14" : "d1-9");
  } elsif ($type eq "pcu") {
     return "u$u" . "pcu1-2";
  } elsif ($type eq "l") {
     return "u$u" . "l1-2";
  } elsif (substr($type,0,1) eq "c") {
     return "u$u" . "c1";
  }
}




sub fix_fru {
  my($obj, $fru) = @_;
  my $dev = $obj->dev();
  my $ix = index($fru, ".");
  $fru = substr($fru,$ix+1) if ($ix > 0);  # remove [disk.]u1d1

  if ($fru =~ /u(\d)ctr/) {
     $fru = "u$1" . "c1";

  } elsif ($fru =~ /u(\d)d(\d+)/) {
     my $u = $1;
     my $d = $2+0;
     $d = "0$d" if ($d < 10 && $dev->{type} =~ /6[01]20/);
     $fru = "u${u}d$d";
  }
  return $fru;
}



# >vol list
# volume            capacity raid data       standby
# v0              168.613 GB    5 u1d01-06     u1d14   
# >proc list
# VOLUME          CMD_REF PERCENT    TIME COMMAND    

# $VAR1 = {
#     'v0' => {
#          'data'     => 'u1d01-06',
#          'standby ' => 'u1d14',
#          'volume'   => 'v0',
#          'raid'     => 5,
#          'capacity' => '168.613 GB'
#        },                            

sub fru_stat {
  my($obj, $fru, $command) = @_;
  my $warn;
  $command = "fru" if (!$command);
  my $dev = $obj->dev();
  $fru = $obj->fix_fru($fru);
  my ($err, $t) = $obj->connect();
  my $rc = MG::RC->new();
  $rc->{err} = $err;
  return $rc if ($err);

#  FRU STAT
#

  my $fru_group = $obj->fruGroup($fru);
  my @o2 = $t->cmd("$command stat $fru_group");
  my $h = Parse->pos(\@o2,['DISK']);
  if ($h->{$fru}{state} ne "enabled") {
    $rc->{warn} .= "Fru $fru is not enabled\n";
  }

  $rc->{report} =  [
     [ucfirst($command) . " Stat", \@o2],
     ];
  
  return MG::RC::end($rc);

}
  


# called with fru=u1d01
# returns { err => "", warn => "", report => [ .. ]

sub pre_disk_disable {
  my($obj, $fru) = @_;
  my $warn;
  my $dev = $obj->dev();
  $fru = $obj->fix_fru($fru);
  my ($err, $t) = $obj->connect();
  my $rc = MG::RC->new();
  $rc->{err} = $err;
  return $rc if ($err);
  
#  VOL LIST
#
  my @o = $t->cmd("vol list");
  $#o = $#o-1;
  my $h = Parse->pos(\@o, ['volume'], [1,-5]);
  delete $obj->{current_volume};
  foreach my $v (keys %$h) {
    my $vol = $h->{$v};
    if ($vol->{raid} != 1 && $vol->{raid} != 5) {
       $rc->{err} .= "Volume $v is raid $vol->{raid}\n";
    }
    my @fd = split(/\-/, $vol->{data});
    my $fdisk = $fd[0];
    my $ldisk = substr($fd[0],0, -length($fd[1])) . $fd[1];
    if ( ($fru ge $fdisk) && ($fru le $ldisk)) {
       $obj->{current_volume} = $vol;
       if (!$vol->{standby}) {
         $rc->{warn} .= "No configured spare for $v\n";
       }
    }
  }
  if (!$obj->{current_volume}) {
     $rc->{err} .= "Disk $fru is not in any volume\n";
  }

#  FRU STAT
#

  my $fru_group = $obj->fruGroup($fru);
  my @o2 = $t->cmd("fru stat $fru_group");
  my $h = Parse->pos(\@o2,['DISK']);
  if ($h->{$fru}{state} ne "enabled") {
    $rc->{warn} .= "Fru $fru is not enabled\n";
  }

# VOL STAT
#
  my @o3  = $t->cmd("vol stat");  #  does not work on t3 the same way
  $#o3 = $#o3-1;
  if ($dev->{type} eq "t3") {
    my $vv = $obj->parse_t3_vol_verify(\@o3);
    foreach my $id (keys %$vv) {
      my $vol = $vv->{$id};
      foreach my $d (keys %$vol) {
         next if (substr($d,0,1) ne "u");
         if ($vol->{$d} ne "mounted" && substr($vol->{$d},0,1) ne "0") {
             $rc->{err} .= "Volume $id, disk $d is not mounted ($vol->{$d})\n";
         }
      }
    }
  } else {                   
    my $found;
    foreach my $l (@o3) {
      $found = 1 if ($l =~ /$fru/);
      if (index($l, ":") > 0 && index($l, ": mounted") < 0) {
        $rc->{err} .= "NOT MOUNTED: $l \n";
      }
    }
    if (!$found) {
      $rc->{err} .= "Disk $fru not mounted\n";
    }
  }

  my @o4 = $t->cmd("proc list");
  $t->cmd("exit");
  if ($#o4 > 2) {
    $rc->{err} .= "Active reconstruct in proclist\n";
  }

  $rc->{report} =  [
     ["Vol List", \@o ],
     ["Fru Stat", \@o2],
     ["Vol Stat", \@o3],
     ["Proc List", \@o4]
     ];
  
  return MG::RC::end($rc);

}

sub runCommand {
  my($obj, $list) = @_;
  
  my ($err, $t) = $obj->connect();
  my $rc = MG::RC->new();
  $rc->{err} = $err;
  return $rc if ($err);
  my(@RC);
  foreach my $l (@$list) {
     my @o1 = $t->cmd($l);
     push(@RC, [$l, \@o1]);
  }
  $rc->{report} = \@RC;
  return $rc;
}

sub parse_t3_vol_verify {
   my($obj, $o) = @_;

   my(@L2, $vol, $done);
   foreach my $l (@$o) {
      my(@w) = split(/\s+/, $l);
      if ($l =~ /u\dd\d/) {
         $vol = $w[0];
         if (!$done) {
           push(@L2, "Volume  Status " . join(" ", @w[1..$#w]));
           $done = 1;
         }
      } elsif ($l =~ /\d/) {
         push(@L2, "$vol  " . join(" ",  @w) );
      }
  }
  return Parse->words(\@L2, ['Volume']);                
}


sub do_disk_disable {
  my($obj, $fru) = @_;

  my $dev = $obj->dev();
  $fru = $obj->fix_fru($fru);
  my ($err, $t) = $obj->connect();
  my $rc = MG::RC->new();
  $rc->{err} = $err;
  return $rc if ($err);
  
  my $v = $obj->{current_volume};
  my(@o1);
  if (!$obj->{READONLY}) {
    if ($v->{standby}) {
     @o1 = $t->cmd("vol disable $fru to_standby");
    } else {
     @o1 = $t->cmd("vol disable $fru");
    }
  }
  my @o2 = $t->cmd("fru stat $fru");
  my $h = Parse->pos(\@o2,['DISK']);
  if ($h->{$fru}{state} ne "disabled") {
    $rc->{err} .= "Fru $fru is not disabled\n";
  }

  my @o3 = $t->cmd("vol stat");
  my @o4 = $t->cmd("proc list");
  $t->cmd("exit");
 
  $rc->{report} = [ 
       [ "Vol disable",   \@o1 ],
       [ "Fru Stat $fru", \@o2 ],
       [ "Vol Stat",      \@o3 ],
       [ "Proc List",     \@o4 ],
       ];
  return $rc;

}

sub post_disk_disable {


}

#####################
# CONTROLLER
#####################

sub pre_controller_disable {
  my($obj, $fru) = @_;
  my $warn;
  my $dev = $obj->dev();
  $fru = $obj->fix_fru($fru);
  my ($err, $t) = $obj->connect();
  my $rc = MG::RC->new();
  $rc->{err} = $err;
  return $rc if ($err);

#  FRU STAT
#
  my $fru_group = $obj->fruGroup($fru);
  my @o4 = $t->cmd("fru list $fru_group");
  $#o4 = $#o4-1;

  my @o3 = $t->cmd("fru stat $fru_group");
  $#o3 = $#o3-1;
  my $h = Parse->pos(\@o3,['CTLR']);
  foreach my $v (keys %$h) {
    my $u = $h->{$v};
    if ($u->{state} ne "enabled") {
      $rc->{warn} .= "Fru $fru is not enabled\n";
    }
  }
  
#  SYS STAT
#
  my @o = $t->cmd("sys stat");
  $#o = $#o-1;
  my $h = Parse->pos(\@o, ['Unit']);

  foreach my $v (keys %$h) {
    my $u = $h->{$v};
    $rc->{err} .= "Unit $u->{unit} is $u->{state},\n" if ($u->{state} ne "ONLINE");
  }

  my @o2 = $t->cmd("proc list");
  if ($#o2 > 2) {
     $rc->{err} .= ($#o2 - 2) . " process(es) are currently running,\n";
  }
  
  $t->cmd("exit");

  $rc->{report} =  [
     ["fru list ", \@o4 ],
     ["fru stat",  \@o3 ],
     ["sys stat",  \@o  ],
     ["proc list", \@o2 ],
     ];
  return MG::RC::end($rc);
}


#####################
# LOOPCARD
#####################

sub pre_loopcard_disable {
  my($obj, $fru) = @_;
  my $warn;
  my $dev = $obj->dev();
  $fru = $obj->fix_fru($fru);
  my ($err, $t) = $obj->connect();
  my $rc = MG::RC->new();
  $rc->{err} = $err;
  return $rc if ($err);

#  FRU STAT
#
  my $fru_group = $obj->fruGroup($fru);

  my @o4 = $t->cmd("fru list $fru_group");
  $#o4 = $#o4-1;

  my @o3 = $t->cmd("fru stat $fru_group");
  $#o3 = $#o3-1;
  my $h = Parse->pos(\@o3,['LOOP']);
  foreach my $v (keys %$h) {
    my $u = $h->{$v};
    if ($u->{state} ne "enabled") {
      $rc->{warn} .= "Fru $fru is not enabled\n";
    }
  }
  
  my @o2 = $t->cmd("proc list");
  if ($#o2 > 2) {
     $rc->{err} .= ($#o2 - 2) . " process(es) are currently running,\n";
  }
  
  $t->cmd("exit");

  $rc->{report} =  [
     ["fru list",  \@o4 ],
     ["fru stat",  \@o3 ],
     ["proc list", \@o2 ],
     ];
  return MG::RC::end($rc);
}

#####################
# ARRAYPOWER
#####################

sub pre_arraypower_disable {
  my($obj, $fru) = @_;
  my $warn;
  my $dev = $obj->dev();
  $fru = $obj->fix_fru($fru);
  my ($err, $t) = $obj->connect();
  my $rc = MG::RC->new();
  $rc->{err} = $err;
  return $rc if ($err);

#  FRU STAT
#
  my $fru_group = $obj->fruGroup($fru);
  my @o4 = $t->cmd("fru list $fru_group");
  $#o4 = $#o4-1;

  my @o3 = $t->cmd("fru stat $fru_group");
  $#o3 = $#o3-1;
  my $h = Parse->pos(\@o3,['LOOP']);
  foreach my $v (keys %$h) {
    my $u = $h->{$v};
    if ($u->{state} ne "enabled") {
      $rc->{warn} .= "Fru $fru is not enabled\n";
    }
  }
  
  my @o2 = $t->cmd("proc list");
  if ($#o2 > 2) {
     $rc->{err} .= ($#o2 - 2) . " process(es) are currently running,\n";
  }
  
  $t->cmd("exit");

  $rc->{report} =  [
     ["fru list $fru_group",  \@o4 ],
     ["fru stat",  \@o3 ],
     ["proc list", \@o2 ],
     ];
  return MG::RC::end($rc);
}

#####################
# ARRAYBATTERY
#####################

sub pre_arraybattery_disable {
  my($obj, $fru) = @_;
  my $warn;
  my $dev = $obj->dev();
  $fru = $obj->fix_fru($fru);
  my ($err, $t) = $obj->connect();
  my $rc = MG::RC->new();
  $rc->{err} = $err;
  return $rc if ($err);

#  FRU STAT
#
  my $fru_group = $obj->fruGroup($fru);
  my $bats = substr($fru,0,2) . "bat1-2";
  my @o4 = $t->cmd("fru list $bats");
  $#o4 = $#o4-1;

  my @o5 = $t->cmd("fru list $fru_group");
  $#o5 = $#o5-1;

  my @o3 = $t->cmd("fru stat $fru_group");
  $#o3 = $#o3-1;
  my $h = Parse->pos(\@o3,['LOOP']);
  foreach my $v (keys %$h) {
    my $u = $h->{$v};
    if ($u->{state} ne "enabled") {
      $rc->{warn} .= "Fru $fru is not enabled\n";
    }
    if ($u->{fan1} ne "normal") {
      $rc->{warn} .= "Fan1 on Fru $fru is $u->{fan1}\n";
    }
    if ($u->{fan2} ne "normal") {
      $rc->{warn} .= "Fan2 on Fru $fru is $u->{fan2}\n";
    }
  }
  
  my @o2 = $t->cmd("proc list");
  if ($#o2 > 2) {
     $rc->{err} .= ($#o2 - 2) . " process(es) are currently running,\n";
  }
  
  $t->cmd("exit");

  $rc->{report} =  [
     ["fru list pcu",  \@o5 ],
     ["fru list batt", \@o4 ],
     ["fru stat",      \@o3 ],
     ["proc list",     \@o2 ],
     ];
  return MG::RC::end($rc);
}


####################
#  BOX
####################

sub array_locate {
  my($obj, $fru) = @_;
  my $warn;
  my $dev = $obj->dev();
  $fru = $obj->fix_fru($fru);
  my ($err, $t) = $obj->connect();
  my $rc = MG::RC->new();
  $rc->{err} = $err;
  return $rc if ($err);
  
  my $grp = substr($fru,1,1);

  my @o = $t->cmd("led -e $grp -f box -l nolocate");

  my @o = $t->cmd("led -e $grp -f box -l locate");
  push(@o, "\nCommand executed.");

  $t->cmd("exit");

  $rc->{report} =  [
     ["led -e $grp -f box -l locate",  \@o ],
     ];

  return MG::RC::end($rc);
}

sub array_nolocate {
  my($obj, $fru) = @_;
  my $warn;
  my $dev = $obj->dev();
  $fru = $obj->fix_fru($fru);
  my ($err, $t) = $obj->connect();
  my $rc = MG::RC->new();
  $rc->{err} = $err;
  return $rc if ($err);
  
  my $grp = substr($fru,1,1);

  my @o = $t->cmd("led -e $grp -f box -l nolocate");
  push(@o, "\nCommand executed.");

  $t->cmd("exit");

  $rc->{report} =  [
     ["led -e $grp -f box -l nolocate",  \@o ],
     ];

  return MG::RC::end($rc);
}




1;



  
