package Client::SEControl;
use Html;
use strict;
use MG::T3;
use MG::DSP;
use MG::Util;
use PDM::ConfigFile;
use Service::Fru;
use Process;
use Client;
use Inventory;
use Diags::DSPUtils;

sub runArrayCommand {
 my($q) = @_;
 my $command = $q->{command};
 my $key = $q->{deviceID};

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

 print Client->http_OK();

 if(!$dev) {
   print Client->error("xml", 1415, "cannot find this device $key");
   return;
 }

 if (!Util->ping($dev->{ipno})) {
   print Client->error("xml", 1416, "cannot ping the array " . $dev->{ipno});
   return;
 }
 my $t3 = MG::T3->new($dev); 
 my($err, $t) = $t3->connect();

 if ($err) {
   print Client->error("xml", 1417, $err);
   return;
 }

 my($rc);
 my @L = split(/,/, $command);
 $rc = $t3->runCommand(\@L);

 my $rep = $rc->report();
 my $nlines;

 foreach my $s (@$rep) {
   my $lines = $s->[1];
   $nlines = join("", @$lines);
   $nlines = $nlines . "<br>";
 }

 print "<SEACTION>" . Client->xmlEncode($nlines) . "</SEACTION>";
 $t3->runCommand(["exit"]);

}

sub runDSPCommand {
 my($q) = @_;
 my $command = $q->{command};
 my $key = $q->{deviceID};

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

 print Client->http_OK();

 if(!$dev) {
   print Client->error("xml", 1415, "cannot find this device $key");
   return;
 }

 if (!Util->ping($dev->{ipno})) {
   print Client->error("xml", 1416, "cannot ping the dsp " . $dev->{ipno});
   return;
 }
 my $dsp = MG::DSP->new($dev); 
 my($err, $t) = $dsp->connect();

 if ($err) {
   print Client->error("xml", 1417, $err);
   return;
 }

 my($rc);
 my @L = split(/,/, $command);
 $rc = $dsp->runCommand(\@L);

 my $rep = $rc->report();
 my $nlines;

 foreach my $s (@$rep) {
   my $lines = $s->[1];
   $nlines = join("", @$lines);
   $nlines = $nlines . "<br>";
 }

 print "<SEACTION>" . Client->xmlEncode($nlines) . "</SEACTION>";
 $dsp->runCommand(["exit"]);

}

sub runHostCommand {
 my($q) = @_;
 my $command = $q->{command};
 my ($err, $com) = Util->run_command($command, undef, 30, {cache => 0} );

 print Client->http_OK();

 if ($err) {
   print Client->error("xml", 1417, $err);
 } else {
   print "<SEACTION>" . Client->xmlEncode(join("\n", @$com)) . "</SEACTION>";
 }

}

sub getAllArrays {

  my ($l);
  open(O, "/etc/hosts");

  print Client->http_OK();
  while ($l = <O>) {
     my($ip0, $name, $rest) = split(/\s+/, $l);
     if ($name =~ /^array/) {
       print "<ARRAY ID=\"$name\">$name</ARRAY> \n";
     }
  }
}

sub getNewArrays {
  my($renv, $devs) = PDM::ConfigFile->read();
  my(%TAKEN);
  foreach my $d (@$devs) {
    if ($d->{name} =~ /^array(\d+)/) {
      $TAKEN{$d->{name}} = 1;
    }
  }
  my $new ;
  my ($l);
  open(O, "/etc/hosts");

  print Client->http_OK();
  while ($l = <O>) {
     my($ip0, $name, $rest) = split(/\s+/, $l);
     if ($name =~ /^array/ && !$TAKEN{$name}) {
       print "<ARRAY ID=\"$name\">$name</ARRAY> \n";
     }
  }
}

sub getBootStatus {
  my $ID = "array_boot";
  my $status = Process->status(undef, $ID);
  my $info   = Process->read(undef, $ID);
  my $trace  = $info->{data}{trace};

  print Client->http_OK();

  print "$status";

}

sub boot_w {
  my($q) = @_;

  my $ID = "array_boot";
  my $INFO;

  my $time = $q->{time} + 15;
  $time = 60 if ($time > 60);

  my $status = Process->status(undef, $ID);
  my $age = Process->age($ID);

  if($status =~ /Running/) {
    print Client->error("xml", 1405, "the boot process is running");
    return;
  }

  my $array = $q->{array};
  my $password = $q->{password};
  

#  my $array = $q->{array}; # diag78
  my $cmd = System->get_home() . 
    "/sysbin/array_boot -i $array -p \"$password\"";
  system("$cmd&");
# don't let it return too fast to unsync with job status
  sleep(4);
  print Client->http_OK();
  print "<SEACTION>OK</SEACTION>";
}


sub arrayLocate {
  my($q) = @_;
  my $fru = $q->{fruID};
  my $key = $q->{deviceID};
 
  my $Config = PDM::ConfigFile->read();
  my $dev = $Config->deviceByKey($key);

  print Client->http_OK();

  if (!$dev) {
    print Client->error("xml", 1401, "device not found");
    return;
  }

  my $t3 = MG::T3->new($dev);
  
  my $rc;
  if ($q->{NOLOCATE}) {
     $rc = $t3->array_nolocate($fru);
  } else {
     $rc = $t3->array_locate($fru);
  }

  if ($rc->error()) {
    print Client->error("xml", 1402, $rc->error());
  } elsif ($rc->warning()) {
    print Client->error("xml", 1403, $rc->warning());
  } else {
    print "<SEACTION>OK</SEACTION>";
  }
}

sub allStat {
  my($q) = @_;
  my $command = $q->{fruID};

  my $renv = System->get_renv();
  my ($renv2, $devs) = PDM::ConfigFile->read();

  print Client->http_OK();

  foreach my $d (@$devs) {
     next if ($d->{type} ne "6020");
     my $t3 = MG::T3->new($d);
     my $rc = $t3->fru_stat($command);
     print $rc->report2html();
  }
}

sub arrayDisk {
  my($q) = @_;
  &arrayFRU($q, "disk");
}

sub arrayController {
  my($q) = @_;
  &arrayFRU($q, "controller");
}

sub arrayLoopcard {
  my($q) = @_;
  &arrayFRU($q, "loopcard");
}

sub arrayPower {
  my($q) = @_;
  &arrayFRU($q, "arraypower");
}

sub arrayBattery {
  my($q) = @_;
  &arrayFRU($q, "arraybattery");
}

sub fruStat {
  my($q) = @_;
  &arrayFRU($q, "fru");
}

sub arrayFRU {
  my($q, $type) = @_;
  my $fru = $q->{fruID};
  my $key = $q->{deviceID};

  my $Config = PDM::ConfigFile->read();
  my $dev = $Config->deviceByKey($key);
 
  print Client->http_OK();

  if (!$dev) {
    print Client->error("xml", 1401, "device not found");
    return;
  }

  my $t3 = MG::T3->new($dev);
  my $rc;

  if ($type eq "disk") {
    $rc = $t3->pre_disk_disable($fru);
  } elsif ($type eq "controller") {
    $rc = $t3->pre_controller_disable($fru);
  } elsif ($type eq "loopcard") {
    $rc = $t3->pre_loopcard_disable($fru);
  } elsif ($type eq "arraypower") {
    $rc = $t3->pre_arraypower_disable($fru);
  } elsif ($type eq "arraybattery") {
    $rc = $t3->pre_arraybattery_disable($fru);
  } elsif ($type eq "fru") {
    $rc = $t3->fru_stat($fru);
  }

  print $rc->report2html();

  if ($rc->error()) {
    print $rc->error();
  }

  if ($rc->warning()) {
    print $rc->warning();
  }
}

sub dsp {
  my($q) = @_;
  my $fru = $q->{fruID};
  my $key = $q->{deviceID};
 
  my $Config = PDM::ConfigFile->read();
  my $dev = $key ? $Config->deviceByKey($key) : $Config->deviceByType("dsp");
 
  print Client->http_OK();

  if (!$dev) {
    print Client->error("xml", 1401, "device not found");
    return;
  }

  my $dsp = MG::DSP->new($dev);
  my $rc = $dsp->pre_disable($fru);

  print $rc->report2html();

  if ($rc->error()) {
    print $rc->error();
  }

  if ($rc->warning()) {
    print $rc->warning();
  }

}

sub getArrays {
  my($renv, $devs, $host,$notifs, $Config) = PDM::ConfigFile->read();

  print Client->http_OK();
  foreach my $d (@$devs) {
    next if ($d->{type} !~ /6[01]20/);
    print "<ARRAY ID=\"$d->{ipno}\">" . $d->{name} . "</ARRAY>\n";
  }

}

sub configure {
  my($q) = @_;
  
  my $ipno = $q->{ipno};
  
  my $command = "configure";
  $command = "unconfigure" if($q->{UNCONF});

  my ($err, $rc) = Inventory->run_vmcfg0($ipno, $command);

  print Client->http_OK();
  if($err) {
    print Client->error("xml", 1412, Client->xmlEncode("Error on '$command': $err"));
  } else {
    print "<SEACTION>" . Client->xmlEncode("'$command' command executed on device $ipno:@$rc") . "</SEACTION>";
  }
}


sub saveInventory {
  my($q) = @_;
  my $inv = Inventory->readInventory($q->{F});

  print Client->http_OK();
  if ($inv) {
    $inv->writeInventory(undef, 1);
    $inv->writeConfig("write"); 
    unlink $q->{F};

    open(OSTATE, ">/tmp/inventory_state");
    print OSTATE "saved";
    close(OSTATE);

    print "XMLSTART\n";
    print "<SEACTION>OK</SEACTION>";
  } else {
    print "XMLSTART\n";
    print Client->error("xml", 1410, "file $q->{F} not found");
  }
}

sub compareInventory {

# run it at background since it needs long time for big configuration
  my $pid="0";

  my $pid = fork();
  if ($pid){ #parent
    print Client->http_OK();
    print "$pid";
    sleep(1);
    return;
  }

  if (defined $pid) {  # child
    open(OSTATE, ">/tmp/inventory_state");
    print OSTATE "running";
    close(OSTATE);
    &compareInventory2($pid);
    open(OSTATE, ">/tmp/inventory_state");
    print OSTATE "done";
    close(OSTATE);
  }

}

sub getCompareInventoryResult() {
  open (REVOUT, "/tmp/inventory_out");
  my @L = <REVOUT> ; close(REVOUT);
  print Client->http_OK();
  foreach my $l (@L) {
    print "$l";
  }
}
    
sub getCompareInventoryState() {
  open (REVOUT, "/tmp/inventory_state");
  my @L = <REVOUT> ; close(REVOUT);
  print Client->http_OK();
  foreach my $l (@L) {
    print "$l";
  }
  open (REVOUT2, "/tmp/inventory_trace");
  my @L = <REVOUT2> ; close(REVOUT2);
  foreach my $l (@L) {
    print "$l";
  }
}


sub compareInventory2 {

  my $renv = System->get_renv();
  my $model = $renv->{solution_model};
  my $short = System->hostname();

#  print Client->http_OK();

  my $oinv = Inventory->readInventory();
  my($trace_out, $inv) = Inventory->readMaserati($short, undef, 1, 1, $model, 1);

  $inv->{model} = $model;
  my $F = "/tmp/inv_upd_$$";
  $inv->writeInventory($F, 1, 1);

  open(INVOUT, ">/tmp/inventory_out");
  print INVOUT "XMLSTART\n";
  print INVOUT "<trace>" . Client->xmlEncode($trace_out) . "</trace>\n";
  print INVOUT "<file>$F</file>\n";

  my ($devs, $odevs);

  if($inv) {
    $devs = $inv->getKeys();
  }

  if($oinv) {
    $odevs = $oinv->getKeys();
  }

  foreach my $k (keys %$devs) {
    my $d = $devs->{$k};
    if (exists($odevs->{$k})) {
      print INVOUT "<device id=\"$k\" name=\"$d->{name}\" type=\"$d->{type}\" ipno=\"$d->{ipno}\"  change=\"update\"> \n";
      my $frus = $d->frus();
      my $ofrus   = $odevs->{$k}{frus};
      my $changes;
      foreach my $fruid (keys %$frus) {
	my $fru = $frus->{$fruid};
	my $ofru = $ofrus->{$fruid} || {};
	foreach my $entry (keys %$fru){
	  if (!exists($ofru->{$entry})) {
	    #$changes .= "-Fru $fruid:$entry has been added.<br>";
	    print INVOUT "<fru change=\"add\">\n";
	    print INVOUT "<id>$fruid</id>\n";
            print INVOUT "<entry>$entry</entry>\n";
            print INVOUT "</fru>\n";
	    last;
	  }elsif ($fru->{$entry} ne $ofru->{$entry}) {
	    #$changes .= "-$entry of $fruid changed from '$ofru->{$entry}' to '$fru->{$entry}'<br> ";
            print INVOUT "<fru change=\"update\">\n";
	    print INVOUT "<id>$fruid</id>\n";
            print INVOUT "<entry>$entry</entry>\n";
            print INVOUT "<from>$ofru->{$entry}</from>\n";
            print INVOUT "<to>$fru->{$entry}</to>\n";
            print INVOUT "</fru>\n";
	  }
	}
      }
      foreach my $fruid (keys %$ofrus) {
	my $ofru = $ofrus->{$fruid};
	my $fru = $frus->{$fruid} || {};
	
	foreach my $entry (keys %$ofru){
	  if (!exists($fru->{$entry})) {
	    #$changes .= "-Fru $fruid:$entry has been removed.<br>";
	     print INVOUT "<fru change=\"remove\">\n";
	    print INVOUT "<id>$fruid</id>\n";
            print INVOUT "<entry>$entry</entry>\n";
            print INVOUT "</fru>\n";
	    last;
	  } # else we have already compared versions above
	}
      }
      print INVOUT "</device> \n";    
      
    } else {
      print INVOUT "<device id=\"$k\" name=\"$d->{name}\" type=\"$d->{type}\" ipno=\"$d->{ipno}\" change=\"add\" /> \n";
    }
  }

  foreach my $k (keys %$odevs) {
    if (!exists($devs->{$k})) {
      my $d = $odevs->{$k};
      print INVOUT "<device id=\"$k\" name=\"$d->{name}\" type=\"$d->{type}\" ipno=\"$d->{ipno}\" change=\"remove\" /> \n";
    }
  }

  close(INVOUT);
}

sub pingDefaultGateway {
  my($q) = @_;
  my $cardNumber = $q->{cardNumber};
  my ($err, $result) = DSPUtils::pingDefaultGateway({card=>$cardNumber});
  print Client->http_OK();
  if($err) {
    print Client->error("xml", 210, $err);
  }
  print "<LINKS> \n";
  if($result) {
    print "<LINK> \n";
    foreach my $n (keys %$result) {
      print "<VALUE ID=\"" . $n . "\">" . Client->xmlEncode($result->{$n}) . "</VALUE> \n";
    }
    print "</LINK> \n";
  }
  print "</LINKS>";

}

sub pingAllLinks {
  my($q) = @_;
  my $cardNumber = $q->{cardNumber};
  my ($err, $links) = DSPUtils::pingAllLinks({card=>$cardNumber});

  print Client->http_OK();
  if($err) {
    print Client->error("xml", 210, $err);
  }
  print "<LINKS> \n";
  if($links) {
    foreach my $link (@$links) {
      print "<LINK> \n";
      foreach my $n (keys %$link) {
	print "<VALUE ID=\"" . $n . "\">" . Client->xmlEncode($link->{$n}) . "</VALUE> \n";
      }
      print "</LINK> \n";
    }
  }
  print "</LINKS>";
}

sub showNetworkConfig {
  my($q) = @_;
  my $cardNumber = $q->{cardNumber};
  my ($err1, $links) = DSPUtils::replicationLinkStatus({card=>$cardNumber});
  my ($err2, $config) = DSPUtils::networkConfig({card=>$cardNumber});
  my ($err3, $port) = DSPUtils::portStatus({card=>$cardNumber});

  print Client->http_OK();
  print "<LINKS> \n";

  if($links) {
    foreach my $link (@$links) {
      print "<VALUE ID=\"" . $link->{IPAddress} . "\">" . $link->{LinkState} . "</VALUE> \n";
    }
  }
  print "</LINKS> \n";
  print "<CONFIG> \n";
  if($config) {
    foreach my $n (keys %$config) {
      print "<VALUE ID=\"" . $n . "\">" . $config->{$n} . "</VALUE> \n";
    }
  }
  print "</CONFIG> \n";
  print "<PORT> \n";
  if($port) {
    foreach my $m (keys %$port) {
      print "<VALUE ID=\"" . $m . "\">" . $port->{$m} . "</VALUE> \n";
    }
  }
  print "</PORT>";
}

sub getARP() {

  my($q) = @_;
  my $cardNumber = $q->{cardNumber};
  my ($err, $result) = DSPUtils::showCurrentARPTable({card=>$cardNumber});

  print Client->http_OK();
  if($err) {
    print Client->error("xml", 210, $err);
  }
  print "<ARP>\n";
  if($result) {
    foreach my $m (keys %$result) {
      print "<VALUE ID=\"" . $m . "\">" . $result->{$m} . "</VALUE> \n";
    }
  }
  print "</ARP>";

}

sub deleteARP() {

  my($q) = @_;
  my $cardNumber = $q->{cardNumber};
  my ($err, $result) = DSPUtils::deleteCurrentARPTable({card=>$cardNumber});

  print Client->http_OK();
  if($err) {
    print Client->error("xml", 210, $err);
  }
  if($result) {
    print "<SEACTION>" . $result->{Status} . "</SEACTION>";
  }
}

1;
