package Client::Upgrade;
use Inventory;
use PPRO;
use strict;
use Client;
use Process;

#
# Clear Patch Upgrade Report
#
sub clearReport {
  print Client->http_OK();
  my $D = System->get_home() . "/DATA/tmp";
  unlink "$D/Patchlist";
  unlink "$D/Patchlist_pid";
  return "OK";
}

#
# Generate Patch Upgrade Report
#
sub generateReport {
  print Client->http_OK();
  my $SID = "storade";
  my $renv = System->get_renv();
  my $cd = "";
  if($renv->{"ppro.patch_server"} eq "CD") {
    $cd = "-c";
  }

  my ($status1, $pid1) = Process->status(undef, "Patchlist");

  my $command = System->get_home() . "/bin/ras_patchlist $cd -S $SID -b";
  system($command);
  sleep(1);

  # get the status of the process
  my ($status2, $pid2) = Process->status(undef, "Patchlist");

  if ($pid1 eq $pid2) {
    # the process id did not change, so the process was not able to start
    my $error = "error.patchlist.1";
    print "<STATUS>$error</STATUS>\n";
  } else {
    print "<STATUS>OK</STATUS>\n";
  }

}

#
# Apply Patches
#
sub applyPatches {
  my($q) = @_;

  print Client->http_OK();

  my $cli  = PPRO->cli_path();
  my $renv = System->get_renv();

  my $info;
  my $list;
  my $SID  = "storade";
  my $rep  = Process->read(undef, "Patchlist");
  my $ppro = PPRO->parse($rep->{data}{report});

  my (%DEV, $err);
  foreach my $el (keys %$q) {
    if (substr($el,0,4) eq "sel_") {
      my $k = substr($el,4);
      $list .= "$k:";
      $DEV{$k} = 1;
    }
  }
  foreach my $el (keys %$q) {
    if (substr($el,0,6) eq "patch_") {
      my($ip0, $patch0) = split(/\#/, substr($el,6));
      my $ip1 = $DEV{$ip0};
      if (!$ip1) {
        $list .= substr($el,6) . ":";
      } else {
        # ignore it
        $err .= "error";
      }
    }
  }
  chop($list) if ($list);

  if (defined($q->{ALL})) {
    $list = "_ALL_";
  }

  if (!$list) {
    $info .= "select one";
  } else {
    my $renv = System->get_renv();
    my $cd = "";
    if($renv->{"ppro.patch_server"} eq "CD") {
      $cd = "-c";
    }

    my ($status1, $pid1) = Process->status(undef, "Upgrade");

    my $command =  System->get_home() . "/bin/ras_upgrade $cd -m S -S $SID -i \"$list\" -b";
    system($command);
    sleep(1);

    # get the status of the process
    my ($status2, $pid2) = Process->status(undef, "Upgrade");

    if ($pid1 eq $pid2) {
      # the process id did not change, so the process was not able to start
      $err = "process did not start";
    }

    $info .= "task started: $command";
  }
  print "<ERROR>$err</ERROR>";
  print "<INFO>$info</INFO>";
}

#
# List Patches
# if no parameters are passed, retrieve the current list of patches.
# Otherwise read the process of the given id (and possibly from the archive)
#
sub listPatches {
  my($q) = @_;
 
  print Client->http_OK();

  my $Config = PDM::ConfigFile->read();

  my $rep;
  my $isArchive = $q->{archive};

  my($host, $id);
  if (defined($q->{id})) {

    if (index($q->{id}, ":") != -1) {
      ($host, $id) = split(/\:/, $q->{id});
    } else {
      $id = $q->{id};
    }

    if ($isArchive eq "yes") {
      $rep  = Process->read($host, $id, 1);
    } else {
      $rep  = Process->read($host, $id);
    }
  } else {
    if ($isArchive eq "yes") {
      $rep  = Process->read(undef, "Patchlist", 1);
    } else {
      $rep  = Process->read(undef, "Patchlist");
    }
  }

  my $val;
  my $arr = $rep->{data}->{stdout};
  foreach my $v (@$arr) {
    $val .= "$v \n";
  }
  $val = Client->xmlEncode($val);


  my $ppro;
  # archived upgrade and downgrade have a timestamp after the name
  # to make thme unique
  if (index($id, "Upgrade") == 0 || index($id, "Downgrade") == 0) {
    $ppro = $rep->{data}{report};
  } else{
    $ppro = PPRO->parse($rep->{data}{report});
  }

  my $trace = $rep->{data}->{trace};
  if (!defined($rep->{data}->{trace})) {
    # try to get the trace from the log file as the 
    # log file is updated as progress becomes available.
    open(O, System->get_home() . "/DATA/tmp/$id.log");
    my @lines = <O>;
    close(O);
    $trace = "@lines";
  }

  print "<DATE>$rep->{date}</DATE>\n";
  if ($ppro->{ERRORS}) {
    print "<ERROR>$ppro->{ERRORS}</ERROR>\n";
    # do not return if there are info for other patches
  }

  my $inv = Inventory->readInventory();
  my %IP; # map devives by ipno
  foreach my $d (@{$inv->getDevices()}) {
    $IP{$d->{ipno}} = $d;
  }

  my $State = State->getComponentState(0);

  my $trace = Client->xmlEncode($trace);

  print "<PATCH_UPGRADE_REPORT>\n";
  print "  <ERROR_COUNT>$rep->{error_cnt}</ERROR_COUNT>\n";
  print "  <STDOUT>$val</STDOUT>\n";
  print "  <TRACE>$trace</TRACE>\n";
  print "  <DATE>$rep->{date}</DATE>\n";

  if (!defined($rep->{data}->{report})) {
    # the report file is not available yet.
    print "</PATCH_UPGRADE_REPORT>\n";
    return;
  }
  my $renv = System->get_renv();

  foreach my $pp (@{$ppro->devices()}) {
    my $inv_d = $IP{$pp->key()};
    my $ip    = $pp->key();
    my $name  = $inv_d->{name};
    my $dev   = $Config->deviceByIP($ip);

    my $devKey  = $dev->{key};
    my $devType = $dev->{type};

    my ($k, $sev);
    my $type = lc($pp->type());
    if ($type eq "sunos") {
      $k = "sp:" . System->hostid();
      $devType = "sp";
      $devKey  = System->hostid();
    } elsif ($dev) {
      $k = "$dev->{type}:$dev->{key}"
    } 

    if($dev->{type} =~ /pseq/){
	$devKey = $renv->{solution_model} . "." . System->hostid();
	$devType = "se2";
    }
    if($dev->{type} =~ /ntc/){
       if($renv->{solution_model} eq "6940"){
          $devKey = $renv->{solution_model} . "." . System->hostid();
	  $devType = "se2";
       }
    }
    print "  <DEVICE>\n";
    print "    <NAME>$name</NAME>\n";
    print "    <IP>$ip</IP>\n";
    print "    <KEY>$devKey</KEY>\n";
    print "    <TYPE>$devType</TYPE>\n";

    my $P = $pp->patches();

    $sev = 0;
    if (exists $State->{$k}) {
      $sev = int($State->{$k}[0] + 0.5);
    }
    print "    <ALARM_SEVERITY>$sev</ALARM_SEVERITY>\n";

    foreach my $patch (@$P) {
      my $pid = $patch->{patchID};
      my $syn = $patch->{synopsis};
      my $err = $pp->error($patch->{error});
      my $frus;
      print "    <PATCH_DATA>\n";
      print "      <PATCHID>$pid</PATCHID>\n";
      print "      <PATCH_SYNOPSIS>$syn</PATCH_SYNOPSIS>\n";
      print "      <ERROR>$patch->{error}</ERROR>\n";
      foreach my $fru (@{$patch->frus()}) {
        my $fruname  = "$fru->{locator}";
        my $fruclass = "$fru->{class}";
        print "      <FRU>";
        print "<NAME>$fruname</NAME>";
        print "<CLASS>$fruclass</CLASS>";
        print "</FRU>\n";
      }
      print "    </PATCH_DATA>\n";
    }
    print "  </DEVICE>\n";
  }
  print "</PATCH_UPGRADE_REPORT>\n";

}

#
# Clear Patch Backout Report
#
sub clearBackoutReport {
  print Client->http_OK();
  my $D = System->get_home() . "/DATA/tmp";
  unlink "$D/Downgrade";
  unlink "$D/Downgrade_pid";
  unlink "$D/Patchdowngrade";
  unlink "$D/Patchdowngrade_pid";
  return "OK";
}

#
# Generate Patch Upgrade Report
#
sub generateBackoutReport {
  print Client->http_OK();
  my $SID = "storade";
  my $command = System->get_home() . "/bin/ras_patchdowngrade -S $SID -u -b";
  system($command);
  sleep(1);
  return "OK";
}

#
# List Backout Patches
#
sub applyBackoutPatches {
  my($q) = @_;
 
  print Client->http_OK();

  my $SID  = "storade";
  my $command =  System->get_home() . "/bin/ras_downgrade -S $SID -U -b";
  system($command);
  sleep(1);

  print "OK";

}

#
# List Backout Patches
#
sub listBackoutPatches {
  my($q) = @_;
 
  print Client->http_OK();

  my $Config = PDM::ConfigFile->read();

  my $rep  = Process->read(undef, "Patchdowngrade");
  my $ppro = PPRO->parse($rep->{data}{report});

  if ($ppro->{ERRORS}) {
    print "<ERROR>$ppro->{ERRORS}</ERROR>\n";
    return;
  }

  my $inv = Inventory->readInventory();
  my %IP; # map devives by ipno
  foreach my $d (@{$inv->getDevices()}) {
    $IP{$d->{ipno}} = $d;
  }

  my $State = State->getComponentState(0);

  print "<PATCH_UPGRADE_REPORT>\n";
  print "  <TRACE>$rep->{data}->{trace}</TRACE>\n";
  print "  <DATE>$rep->{date}</DATE>\n";
  foreach my $pp (@{$ppro->devices()}) {
    my $inv_d = $IP{$pp->key()};
    my $ip    = $pp->key();
    my $name  = $inv_d->{name};
    my $dev   = $Config->deviceByIP($ip);

    my $devKey  = $dev->{key};
    my $devType = $dev->{type};

    my ($k, $sev);
    my $type = lc($pp->type());
    if ($type eq "sunos") {
      $k = "sp:" . System->hostid();
      $devType = "sp";
      $devKey  = System->hostid();
    } elsif ($dev) {
      $k = "$dev->{type}:$dev->{key}"
    } 

    print "  <DEVICE>\n";
    print "    <NAME>$name</NAME>\n";
    print "    <IP>$ip</IP>\n";
    print "    <KEY>$devKey</KEY>\n";
    print "    <TYPE>$devType</TYPE>\n";

    my $P = $pp->patches();

    $sev = 0;
    if (exists $State->{$k}) {
      $sev = int($State->{$k}[0] + 0.5);
    }
    print "    <ALARM_SEVERITY>$sev</ALARM_SEVERITY>\n";

    foreach my $patch (@$P) {
      my $pid = $patch->{patchID};
      my $syn = $patch->{synopsis};
      my $err = $pp->error($patch->{error});
      my $frus;
      print "    <PATCHID>$pid</PATCHID>\n";
      print "    <PATCH_SYNOPSIS>$syn</PATCH_SYNOPSIS>\n";
      foreach my $fru (@{$patch->frus()}) {
        my $fruname  = "$fru->{locator}";
        my $fruclass = "$fru->{class}";
        print "    <FRU>";
        print "<NAME>$fruname</NAME>";
        print "<CLASS>$fruclass</CLASS>";
        print "</FRU>\n";
      }
    }
    print "  </DEVICE>\n";
  }
  print "</PATCH_UPGRADE_REPORT>\n";

}

#
# kill a patch process
#
sub kill {
  my($q) = @_;

  print Client->http_OK();

  my $D = System->get_home() . "/DATA/tmp";
  if ($q->{kill}) {
    my ($status, $pid1) = Process->status(undef, $q->{kill});
    if ($pid1 && $pid1 =~ /^\d+$/) {
      Util->killPID($pid1);

      my $debug = "Killed $q->{kill} ($pid1).";

      # remove the lock
      my $lock  = LockManager->new();
      my $locki = $lock->exists("system", 1) || {};
      if ($locki->{info}) {
        $lock->unlock("system");
      }

    }
  }
  print "OK";
}

1;


