#!/pkg/bin/perl

# This script does polling for the OHS.

use Hierarchy_interface;
use Test_script;
use Clog;
use Mod_utility;
use Grdbm;
use IPC::Open2;  # For the Pipe

#-------------------- Globals Necessary --------------------------------#

$use_polling = 0; # Should we do the polling or not.

$SIG{ALRM} = 'catch_alarm';

sub catch_alarm {
  # We do not do anything when the alarm goes off.
}

my %sms; #The current status for all known Software Managers.
my %mcs; #The current status for all known Module Controllers.

my @depts; # The departments (SM's) which still need to be polled this round.
my @hosts; # The hosts (MC's) which still need to be polled this round.

my $init = 0; # Has the list of departments to be polled been updated.
my $time = 0; # Tracks time between rounds.

select STDOUT; $| = 1; # Turn on buffering for the pipe.
select STDIN;  $| = 1;

my $activated = 1; # Assume we will be able to activate polling.

my $return_msg; # this variable return error messages from liveness calls.

#-------------------- Preliminary setup --------------------------------#

  $user = $ARGV[0]; # Given from the exec
  $pass = $ARGV[1];

#  local $grids_db = $Hierarchy_interface::grids_db; # Hierarchy configuration
#  $nlogs = 5;  # Number of old log directories to keep around
#  $default_rs_name = 'sweep';

  $dept = "null";

  my ($ohs_host,$ohs_port) = split(/:/,$Hierarchy_interface::ohs_location);

  $log = new Clog('polling','N/A',"son.ohs.polling"); # Set up our log
  $log->{'central_log'} = 0; # No central logging - presently broken.

  # Attempt to establish a hierarchy.

  # We will make our own hierarchy, so that we do not need to contact the OHS.
  my $info = "";
  my $tmp_h = new Hierarchy($log,\$info);

  ($ok, $h) = new Hierarchy_interface($user,$pass,$dept,$log,'comm','main::FILE',1);
  unless ($ok)
   {
    $log->warn("done!\nok=$ok\nhi=$hierarchy\n");
    $log->warn("Polling not activated, proceed with caution.\n");
    print STDERR "Polling not activated, unable to communicate with OHS.  Please restart GrIDS.\n";
    exit(1);
   }
  else
   {
    print STDERR "Polling is now activated, ";
    print STDERR "and it is in use.\n" if $use_polling == 1;
    print STDERR "but it is NOT in use.\n" if $use_polling == 0;
   }


#-------------------- Begin Communicating with OHS --------------------------------#

  my $round_length = 15;  # This is the length between polling rounds.

  while(1)
   {
    $time += 1;
    if($time >= $round_length)
     {
      if($init == 0) {
        initialize();
      }
      my $ret_mcs = 1; # Completed all of the polling?
      my $ret_sms = 1; 
      if ($use_polling == 1)
       {
        $ret_mcs = poll_mcs(); # Completed all of the polling?
        $ret_sms = poll_sms(); 
       }
 
      if($ret_sms == 1 && $ret_mcs == 1) # Finished the round, start over.
       {
        $time = 0;
        $init = 0;
       }
     }

    alarm 1; # This ends the blocking of the next line.

    if($buf = <STDIN>) { # We have received a message from the OHS.
      @trans = split(/#/,$buf);
      foreach $msg (@trans){

        $log->separator();
        $log->warn("Received from OHS : $msg"); 

	my @this_trans = split(/,/,$msg);
	my $header = shift @this_trans;
        
        if($header eq 'htr'){ # We must check the liveness of this transaction.

          my $msg_tmp = shift @this_trans;
          my $msg_ref;
          @$msg_ref = split(/ /,$msg_tmp); # there will only ever be one htr in the buffer at a time.

          my $type = @$msg_ref[0];

          my $function_call = $type.'_is_live';
          if(eval "$function_call".'($msg_ref)')
           {
            print STDOUT ("@$msg_ref[1],1,_");
            $log->warn("All necessary componants are alive.");
           }
          else
           {
            print STDOUT ("@$msg_ref[1],0,$return_msg");
            $log->warn("All necessary componants are NOT alive.");
            $log->warn("$return_msg");
           }
         }# end if htr

        if($header eq 'htc'){
          my $type = shift @this_trans;
          my $htr_tmp = shift @this_trans;
          my $htc_tmp = shift @this_trans;
          my $view = pop @this_trans; 

          my $htr;
          my $htc;
          @$htr = split(/ /,$htr_tmp);
          @$htc = split(/ /,$htc_tmp);

          #my $function_call = '$h->{"hierarchy"}->'.$type;
          my $function_call = '$tmp_h->'.$type;

          unless(eval "$function_call".'($htr,$htc,$view)')
          {
            $log->warn("Unexpected error evaluating $function_call.\n");
          } # end unless

          $log->warn("htc complete:  Change to hierarchy has been made, must re-initialize.");
          initialize(); # There has been a change to the Hierarchy.

         }# end if htc
       } # end foreach 
    } # end if
  }

#============================================================================#
#
# Function Name: initialize
#
#  This function pulls all of the hosts and departments from the hierarchy
#  and stores them in the appropriate global variables.
#
# Return Value(s):
#
# Global variable modifications:
#  sms, mcs
#
#----------------------------------------------------------------------------#

sub initialize
{

  my @tmp_dept;
  my @tmp_host;
  my $key;

  $log->separator();
  $log->warn("Initializing the list of Departments and Hosts to poll.");

  #foreach $key (keys %{$h->{'hierarchy'}}) {
  foreach $key (keys %{$tmp_h}) {
        if(ref $tmp_h->{$key} eq 'Department'){
                push(@tmp_dept,$key);
        }
        if(ref $tmp_h->{$key} eq 'Host'){
                push(@tmp_host,$key);
        }
  }

  @depts = @tmp_dept;
  @hosts = @tmp_host;

  my $len = scalar(@hosts);
  my $len1 = scalar(@tmp_host);

  my %tmp_sm;
  my %tmp_mc;

  foreach $key (@tmp_dept) {
      $tmp_sm{$key} = 1;
  }
  foreach $key (@tmp_host) {
      $tmp_mc{$key} = 1;
  }

  # Keep values we already have.
  foreach $key (keys %sms) {
    if(exists $tmp_sm{$key}){
      $tmp_sm{$key} = $sms{$key};
    }
  }

  foreach $key (keys %mcs) {
    if(exists $tmp_mc{$key}){
      $tmp_mc{$key} = $mcs{$key};
    }
  }

  %sms = %tmp_sm;
  %mcs = %tmp_mc;

  foreach $key (keys %sms) {
      $log->warn("Department $key added with current value of $sms{$key}.");
  }
  foreach $key (keys %mcs) {
      $log->warn("Host $key added with current value of $mcs{$key}.");
  }

  $init = 1;

}

#============================================================================#
#
# Function Name: poll_sms
#
#  This function polls the software managers from the hierarchy.  If there are
#  more than 10, it will only poll ten at a time.  It returns between these 
#  ten so that it can service any requests which may have come from the OHS.
#  It will then be called again and it will continue until all have been
#  polled.
#
# Return Value(s):
#   
#  0/1
#
# Global variable modifications:
#  sms 
#
#----------------------------------------------------------------------------#

sub poll_sms
{

  $log->separator();
  $log->warn("Polling SM's.");

  my $len = scalar(@depts);
  my $start = 0;
  my $end = 10;
  $end = $len if $len < 10;
  my $i; 
 
  my $sm_messages;

  for ($i = $start; $i < $end; $i += 1){
 
    my $gdv_ref1 = [@depts[$i], 'parent','_' ];

    $log->warn("Polling $depts[$i].");

    #my($dept_object) = $h->{'hierarchy'}{@depts[$i]};
    my($dept_object) = $tmp_h->{@depts[$i]};
    my $man_host = $dept_object->{'manager_host'};
    my $man_port = $dept_object->{'manager_port'};

    push( @$sm_messages, [$man_host,$man_port,'gdv',$gdv_ref1]);

  }

  my @done;
  ($err,$replies,@done) = $h->communicate_with_sms($sm_messages,2);

  $len = scalar(@done);
  $start = 0;
  $end = $len;

  for ($i = $start; $i < $end; $i += 1)
   {   
    $sms{$depts[$i]} = $done[$i];
   }   

  for ($i = $start; $i < $end; $i += 1)
   {   
    shift @depts;
   }
  $len = scalar(@depts);

  foreach $key (keys %sms) {
    #print STDERR ("Current status for $key is $sms{$key}.\n");
  }

  return 0 if $len > 0;
  return 1;

}
 
#============================================================================#
#
# Function Name: poll_mcs
#
#  This function polls the module controllers from the hierarchy.  If there are
#  more than 10, it will only poll ten at a time.  It returns between these
#  ten so that it can service any requests which may have come from the OHS.
#  It will then be called again and it will continue until all have been
#  polled.
#
# Return Value(s):
#  0/1
#
# Global variable modifications:
#  mcs 
#
#----------------------------------------------------------------------------#


sub poll_mcs
{

  $log->separator();
  $log->warn("Polling MC's.");
 
  my $len = scalar(@hosts);
  my $start = 0;
  my $end = 10;
  $end = $len if $len < 10;
  my $i;

  my $sm_messages;
 
  for ($i = $start; $i < $end; $i += 1){

    $log->warn("Polling $hosts[$i].");

    my $parent = $tmp_h->{$hosts[$i]}{"parent"};
    my $ghv_ref = [$parent,$hosts[$i],'module_controller','v.v',$parent,"parent",0 ];
 
    #my($dept_object) = $h->{'hierarchy'}{$parent};
    my($dept_object) = $tmp_h->{$parent};
    my $man_host = $dept_object->{'manager_host'};
    my $man_port = $dept_object->{'manager_port'};

    push( @$sm_messages, [$man_host,$man_port,'ghv',$ghv_ref]);
  }
  my @done;
  ($err,$replies,@done) = $h->communicate_with_sms($sm_messages,2);
 
  $len = scalar(@done);
  $start = 0;
  $end = $len;
 
  for ($i = $start; $i < $end; $i += 1)
   { 
    $mcs{$hosts[$i]} = $done[$i];
   }

  for ($i = $start; $i < $end; $i += 1)
   {
    shift @hosts;
   }

  $len = scalar(@hosts);

  foreach $key (keys %mcs) {
    #print STDERR ("Current status for $key is $mcs{$key}.\n");
  }

  return 0 if $len > 0;
  return 1;

}

#============================================================================#
#
# Function Name: *_is_live 
#
#  These functions determine if all of the hosts and departments which are
#  necessary for the specified function are alive.
#
# Return Value(s):
#  0/1
#
# Global variable modifications:
#  mcs
#
#----------------------------------------------------------------------------#

sub new_root_is_live
{
  my($hdr,$trans_id,$user,$pass,$dept) = @{$_[0]};
  # No checking is done here.  Everything is assumed to be running.
  return 1;
}
sub change_user_is_live
{
  my($hdr,$trans_id,$user,$pass,$serial,$user2,$pass2,$dept) = @{$_[0]};
  $return_msg = "Department $dept is not alive.";
  return 0 unless $sms{$dept} == 1;
  return 1;
}
sub add_host_is_live
{
  my($hdr,$trans_id,$user,$pass,$serial,$dept,$host,$port) = @{$_[0]};
  $return_msg = "Department $dept is not alive.";
  return 0 unless $sms{$dept} == 1;
  return 1;
}
sub add_dept_is_live
{
  my($hdr,$trans_id,$user,$pass,$serial,$parent,$dept,$manhost,
                                                $aghost) = @{$_[0]};
  $return_msg = "Department $parent is not alive.";
  return 0 unless $sms{$parent} == 1;
  return 1;
}
sub change_variable_is_live
{
  my($type,$trans_id,$user,$pass,$serial,$dept) = @{$_[0]};
  $return_msg = "Department $dept is not alive.";
  return 0 unless $sms{$dept} == 1;
  return 1;
}
sub move_dept_is_live
{
  my($type,$trans_id,$user,$pass,$serial,$parent,$dept) = @{$_[0]};
 
  # If we are going to move a department, then the department must be live.
  # If we are going to move a department, then the new parent must be live.

  $return_msg = "Department $dept is not alive.";
  return 0 unless $sms{$dept} == 1;
  $return_msg = "Department $parent is not alive.";
  return 0 unless $sms{$parent} == 1;

  return 1;
}
sub remove_dept_is_live
{
  my($type,$trans_id,$user,$pass,$serial,$dept) = @{$_[0]};
  #my $old_parent = $h->{'hierarchy'}->{$dept}->{'parent'};
  my $old_parent = $tmp_h->{$dept}->{'parent'};
 
  # If we are going to remove a department, then its parent must be live.

  $return_msg = "Department $old_parent is not alive.";
  return 0 unless $sms{$old_parent} == 1;

  return 1;
}
sub move_host_is_live
{
  my($type,$trans_id,$user,$pass,$serial,$dept,$host) = @{$_[0]};
  #my $old_parent = $h->{'hierarchy'}->{$host}->{'parent'};
  my $old_parent = $tmp_h->{$host}->{'parent'};
 
  $return_msg = "Department $dept is not alive.";
  return 0 unless $sms{$dept} == 1;
  $return_msg = "Host $host is not alive.";
  return 0 unless $mcs{$host} == 1;

  return 1;
}
sub remove_host_is_live
{
  my($type,$trans_id,$user,$pass,$serial,$host) = @{$_[0]};
  #my $old_parent = $h->{'hierarchy'}->{$host}->{'parent'};
  my $old_parent = $tmp_h->{$host}->{'parent'};
 
  # If we are going to remove a host, then its parent must be live.

  #return 0 unless $mcs{$host} == 1;
  $return_msg = "Department $old_parent is not alive.";
  return 0 unless $sms{$old_parent} == 1;

  return 1;
}
sub move_manager_is_live
{
  my($type,$trans_id,$user,$pass,$serial,$dept,$host) = @{$_[0]};
 
  $return_msg = "Department $dept is not alive.";
  return 0 unless $sms{$dept} == 1;
  $return_msg = "Host $host is not alive.";
  return 0 unless $mcs{$host} == 1;

  return 1;
}
sub move_aggregator_is_live
{
  my($type,$trans_id,$user,$pass,$serial,$dept,$host) = @{$_[0]};
 
  $return_msg = "Department $dept is not alive.";
  return 0 unless $sms{$dept} == 1;
  $return_msg = "Host $host is not alive.";
  return 0 unless $mcs{$host} == 1;

  return 1;
}
