#!/opt/p7perl/bin/perl

##############################################################################
#
# Copyright (c) Agilent Technologies 2001.  All rights reserved.
#
# THIS SOFTWARE IS FOR THE USE OF TRAINED AGILENT PERSONNEL ONLY to install and
# support customers system.  The presence of this software on customer's
# system does not grant customer any license, ownership or other rights in 
# this software or imply any degree of support for this software from Agilent.
# Agilent may remove this software at any time.
#
# AGILENT TECHNOLOGIES MAKES NO WARRANTY OF ANY KIND WITH REGARD TO THIS SOFTWARE,
# INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE.  Agilent Technologies shall not be liable
# for errors contained herein or direct, indirect, special, incidental, or 
# consequential damages in connection with furnishing, performance, or use of
# this software.
#
# RESTRICTED RIGHTS LEGEND  Use, duplication or disclosure by US Government is
# subject to restrictions as set forth in subdivision (c)(1)(ii) of the 
# Rights in Technical Data and Computer Software Clause 252.227.7013.
# Agilent Technologies.
#
############################################################################# 
# Script to parse platform7 central server eng_logging_C32 file (created by
# executing "p7dumpstatus c32.run") and print it in a more readable format.
#
# Author: Allan Kerr, CSG Solution Architect

use strict;
#uses real and integer math

# Fake boolean datatype
use constant TRUE  => 1;	# Boolean TRUE
use constant FALSE => 0;	# Boolean FALSE

#------------------------------------------------------------------------------
# Regular Expressions (REs) to parse comms status log file into components.
# See readLog() for details.  Tested and work for B.05.40 and B.07.10.

# Match header line indicating start of a log dump
# $1 = header portion to print
my $RE_HEADER     = '^(C32 status dump at .*)\s*$';

# Match remote site status line
# $1 = site number, $2 = Aux Site, $3=comms status
my $RE_SITE       = '^Site.*(?:number|site)[\W]+(\d+).*procNum[\W]+(\d+)[\W]+\sis[\W]+(.*)[\W]*$';

# Match IFPC status line
# $1 = site number, $2 = cage number, $3 = slot number, $4 = comms status
my $RE_IFPC       = '^IFPC.*site[\W]+(\d+)[\W]+cage[\W]+(\d+)[\W]+(?:slot|procNum)[\W]+(\d+)[\W]+is[\W]+(.*)[\W]*$';

# Match probe processor status line
# $1 = site number, $2 = probe processor number, $3 = comms status
my $RE_PROBEPROC  = '^ProbeProcessor.*site[\W]+(\d+).*procNum[\W]+(\d+)[\W]+is[\W]+(.*)[\W]*$';

# Match broadband probe processor status line
# $1 = site number, $2 = cage number, $3 = slot number, $4 = comms status
my $RE_BROADBANDPROBEPROC  = '^BroadbandProbeProcessor.*site[\W]+(\d+)[\W]+cage[\W]+(\d+)[\W]+.*procNum[\W]+(\d+)[\W]+is[\W]+(.*)[\W]*$';

# Match ethernet probe processor status line
# $1 = site number, $2 = cage number, $3 = slot number, $4 = comms status
my $RE_EPP  = '^EthernetPacketProcessor.*site[\W]+(\d+)[\W]+cage[\W]+(\d+)[\W]+.*procNum[\W]+(\d+)[\W]+is[\W]+(.*)[\W]*$';

# Match AMC status lin
# $1 = site number, $2 = card cage, $3= procNum, $4=Status
my $RE_AMC = '^AquisitionManagementCard.*site[\W]+(\d+)[\W]+cage[\W]+(\d+)[\W]+.*procNum[\W]+(\d+)[\W]+is[\W]+(.*)[\W]*$';

# Match DSP status lin
# $1 = site number, $2 = proc number, $3 = comms status
my $RE_DSP = '^Datastore.*site[\W]+(\d+).*procNum[\W]+(\d+)[\W]+is[\W]+(.*)[\W]*$';
# Match SDB status lin
# $1 = site number, $2 = proc number, $3 = comms status
my $RE_SDB = '^SDBProc.*site[\W]+(\d+).*procNum[\W]+(\d+)[\W]+is[\W]+(.*)[\W]*$';

# Match workstation/application server status line
# $1 = workstation/app server number, $2 = comms status
my $RE_GUI        = '^Workstation.*(?:number|procNum)[\W]+(\d+)[\W]+is[\W]+(.*)[\W]*$';

# Match other 'junk' lines that should be ignored as having no useful info
my @RE_IGNORE = map(m/$_/i, (
			      "^Workstation.*is registered for bad processor lists",
			     )
		   );

# Enumerated constants (0..n) for each RE above
my $LOG_HEADER    = 0;
my $LOG_SITE      = 1;
my $LOG_IFPC      = 2;
my $LOG_PROBEPROC = 3;
my $LOG_BROADBANDPROBEPROC = 4;
my $LOG_AMC       = 5;
my $LOG_EPP       = 6;
my $LOG_GUI       = 7;
my $LOG_DSP       = 8;
my $LOG_SDB       = 10;

my $LOG_UNMATCHED = 9;		# Log lines does not match any RE

#------------------------------------------------------------------------------
# Comms status states

# Enumerated constants (0..n) of comms status states
# Add new entries to @STATUS_CHAR, $COMMS_STATUS_KEY and %COMMS_STATUS
my $STATUS_NOT_LISTED   = 0;		# Entity not listed in comms log
my $STATUS_NOT_IN_COMMS = 1;		# Entity not in comms
my $STATUS_IN_COMMS     = 2;		# Entity in comms/configured
my $STATUS_UNKNOWN      = 3;		# Entity has a comms status not in %COMMS_STATUS

# Mapping from comms status text in comms log to internal comms status codes
my %COMMS_STATUS = (
		   "not in comms"	=> $STATUS_NOT_IN_COMMS,
		   "in comms"		=> $STATUS_IN_COMMS,
		   "not configured"	=> $STATUS_NOT_IN_COMMS,
		   "configured"		=> $STATUS_IN_COMMS,
		  );

# Map comms status states to display characters
my @STATUS_CHAR;
$STATUS_CHAR[$STATUS_NOT_LISTED]   = '.';
$STATUS_CHAR[$STATUS_NOT_IN_COMMS] = 'X';
$STATUS_CHAR[$STATUS_IN_COMMS]     = '|';
$STATUS_CHAR[$STATUS_UNKNOWN]      = '?';

# User readable description of comms status states to characters
my $COMMS_STATUS_KEY = "Comms status key:
  does not exist/not listed = '" . $STATUS_CHAR[$STATUS_NOT_LISTED  ] . "'  (cardcage is blank if no IFPCs listed)
  in comms/configured       = '" . $STATUS_CHAR[$STATUS_IN_COMMS    ] . "'
  not in comms              = '" . $STATUS_CHAR[$STATUS_NOT_IN_COMMS] . "'
  other comms status        = '" . $STATUS_CHAR[$STATUS_UNKNOWN     ] . "'";

#------------------------------------------------------------------------------
#

main();
exit(0);


###############################################################################
# Reads comms log from filehandle $FH_IN into @log data structure.  This is a
# complex structure: @log[commsLogInstance][commsLogLineType], with deeper
# levels being hashes/arrays as appropriate.  See code below and RE comments.

sub readLog(*\@) {
  my ($FH_IN, $log_ar) = @_;
  my $logInstance = 0;
  my $unmatchedIdx = 0;
  my $line;
  
  while (defined($line = <$FH_IN>)) {
    chomp($line);

    if ($line =~ /$RE_IFPC/io) {
      #print("IFPC site='$1' cage='$2' slot='$3' status='$4'\n");
      $$log_ar[$logInstance][$LOG_IFPC]{$1}{$2}{$3} = $4;

    } elsif ($line =~ /$RE_PROBEPROC/io) {
      #print("PROBEPROC site='$1' proc='$2' status='$3'\n");
      $$log_ar[$logInstance][$LOG_PROBEPROC]{$1}{$2} = $3;

    } elsif ($line =~ /$RE_BROADBANDPROBEPROC/io) {
      #print("BROADBANDPROBEPROC site='$1' cage='$2' slot='$3' status='$4'\n");
      $$log_ar[$logInstance][$LOG_BROADBANDPROBEPROC]{$1}{$2}{$3} = $4;
    
    } elsif ($line =~ /$RE_EPP/io) {
      #print("EPP site='$1' cage='$2' slot='$3' status='$4'\n");
      $$log_ar[$logInstance][$LOG_EPP]{$1}{$2}{$3} = $4;

    } elsif ($line =~ /$RE_AMC/io) {
      #print("AMC site='$1' cage='$2' procnum(10)='$3' status='$4' \n");
      $$log_ar[$logInstance][$LOG_AMC]{$1}{$2}{$3} = $4;
    
    } elsif ($line =~ /$RE_DSP/io) {
      #print("DSP site='$1' proc='$2' status='$3'\n");
      $$log_ar[$logInstance][$LOG_DSP]{$1}{$2} = $3;
    
    } elsif ($line =~ /$RE_SDB/io) {
      #print("SDB site='$1' proc='$2' status='$3'\n");
      $$log_ar[$logInstance][$LOG_SDB]{$1}{$2} = $3;

    } elsif ($line =~ /$RE_SITE/io) {
      #print("SITE site='$1' status='$2'\n");
      $$log_ar[$logInstance][$LOG_SITE]{$1}{$2} = $3;

    } elsif ($line =~ /$RE_GUI/io) {
      #print("GUI number='$1' status='$2'\n");
      $$log_ar[$logInstance][$LOG_GUI]{$1} = $2;
    
    } elsif ($line =~ /$RE_HEADER/io) {
      #print("HEADER line='$1'\n");
      if (defined($$log_ar[$logInstance])) {
	# Increment log instance on new header if current instance
	# is not empty
	$logInstance++;
	$unmatchedIdx = 0;
      }
      $$log_ar[$logInstance][$LOG_HEADER] = $1;

    } else {
      # UnrecordLineed line.  Check and discard junk lines, record rest
      my $discardLine = FALSE;
      foreach my $pattern (@RE_IGNORE) {
	$discardLine = TRUE, last if ($line =~ $pattern);
      }
      if (! $discardLine) {
	#print("Unmatched = '$line'\n");
	$$log_ar[$logInstance][$LOG_UNMATCHED][$unmatchedIdx++] = $line;
      }
    }
  }
}


###############################################################################
# Support routines to operate on log status structures

# Return numerically sorted unique array of all cardcage/probeproc numbers
# used across all sites.
sub getAllSubEntries(\%) {
  my $logEntry_hr = shift;
  if (defined($logEntry_hr)) {
    my %cardcages;
    foreach my $site (keys %{$logEntry_hr}) {
      foreach my $cardcage (keys %{$$logEntry_hr{$site}}) {
	$cardcages{$cardcage} = TRUE;
      }
    }
    return sort({$a <=> $b} keys %cardcages);
  } else {
    return undef;
  }
}

# Return numerically sorted unique array of all cardcage numbers used across
# all sites.  Call with ($log[instance]). 
sub getAllCardcages(\@) {
  my $logEntry_ar = shift;
  return getAllSubEntries(%{$$logEntry_ar[$LOG_IFPC]});
}

# Return numerically sorted unique array of all probe proc numbers used across
# all sites.  Call with ($log[instance]). 
sub getAllProbeProcs(\@) {
  my $logEntry_ar = shift;
  return getAllSubEntries(%{$$logEntry_ar[$LOG_PROBEPROC]});
}

sub getAllBroadBandProbeProcs(\@) {
  my $logEntry_ar = shift;
  return getAllSubEntries(%{$$logEntry_ar[$LOG_BROADBANDPROBEPROC]});
}
sub getAllAMC(\@) {
  my $logEntry_ar = shift;
  return getAllSubEntries(%{$$logEntry_ar[$LOG_AMC]});
}
sub getAllDSP(\@) {
  my $logEntry_ar = shift;
  return getAllSubEntries(%{$$logEntry_ar[$LOG_DSP]});
}
sub getAllSDB(\@) {
  my $logEntry_ar = shift;
  return getAllSubEntries(%{$$logEntry_ar[$LOG_SDB]});
}
sub getAllEPP(\@) {
  my $logEntry_ar = shift;
  return getAllSubEntries(%{$$logEntry_ar[$LOG_EPP]});
}

# Return numerically sorted unique array of all site numbers
# used across all IFPC/ProbeProc/Site entries
sub getAllSites(\@) {
  my $logEntry_ar = shift;
  if (defined($logEntry_ar)) {
    my %sites;
    foreach my $site (keys %{$$logEntry_ar[$LOG_SITE]}) {
      $sites{$site} = TRUE;
    }
    foreach my $site (keys %{$$logEntry_ar[$LOG_IFPC]}) {
      $sites{$site} = TRUE;
    }
    foreach my $site (keys %{$$logEntry_ar[$LOG_PROBEPROC]}) {
      $sites{$site} = TRUE;
    }
    foreach my $site (keys %{$$logEntry_ar[$LOG_BROADBANDPROBEPROC]}) {
      $sites{$site} = TRUE;
    }
    foreach my $site (keys %{$$logEntry_ar[$LOG_AMC]}) {
      $sites{$site} = TRUE;
    }
    foreach my $site (keys %{$$logEntry_ar[$LOG_DSP]}) {
      $sites{$site} = TRUE;
    }
    foreach my $site (keys %{$$logEntry_ar[$LOG_SDB]}) {
      $sites{$site} = TRUE;
    }
    foreach my $site (keys %{$$logEntry_ar[$LOG_EPP]}) {
      $sites{$site} = TRUE;
    }
    return sort({$a <=> $b} keys %sites);
  } else {
    return undef;
  }
}

# Map comms log status text into an internal comms status code
sub getStatusCode($) {
  my $statusText = shift;
  my $statusCode;
  if (defined($statusText)) {
    $statusCode = $COMMS_STATUS{$statusText};
    $statusCode = $STATUS_UNKNOWN if (! defined($statusCode));
  } else {
    $statusCode = $STATUS_NOT_LISTED;
  }
  return $statusCode;
}

# Map comms status code to printable comms status display character
sub getStatusChar($) {
  return $STATUS_CHAR[shift];
}


###############################################################################
# Generic print routines

# Print title for this log entry
sub printTitle($$) {
  my ($FH_OUT, $title) = @_;
  print($FH_OUT defined($title) ? $title : "Comms status:", "\n");
}

# Print key to comms status characters
sub printStatusKey(*) {
  my $FH_OUT = shift;
  print($FH_OUT "\n", $COMMS_STATUS_KEY, "\n");
}

# Print summary for entities in/out of comms
sub printSummary(*$$$) {
  my ($FH_OUT, $title, $total, $inComms) = @_;
  my $notInComms = $total - $inComms;
  printf($FH_OUT "%s: %4d total, %4d in comms (%5.1f%%), %4d not in comms (%5.1f%%)\n",
	 $title, $total,
	 $inComms, $inComms / $total * 100,
	 $notInComms, $notInComms / $total * 100);
}


###############################################################################
# Print map version of log entry
# Assumes 8 IFPCs/cardcage - makes formatting simpler!

sub printStatusMap(*\@) {
  my ($FH_OUT, $logEntry_ar) = @_;

  # Keep statistics count of total entities and entities in comms
  my $sitesTotal        = 0;
  my $sitesInComms      = 0;
  my $probeProcsTotal   = 0;
  my $probeProcsInComms = 0;
  my $BroadBandprobeProcsTotal = 0;
  my $BroadBandprobeProcsInComms = 0;
  my $AMCProcsTotal     = 0;
  my $AMCProcsInComms   = 0; 
  my $EPPProcsTotal     = 0;
  my $EPPProcsInComms   = 0; 
  my $ifpcsTotal        = 0;
  my $ifpcsInComms      = 0;
  my $guisTotal         = 0;
  my $guisInComms       = 0;
  my $DSPProcsTotal     = 0;
  my $DSPProcsInComms   = 0;
  my $SDBProcsTotal     = 0;
  my $SDBProcsInComms   = 0;

  # Print header lines
  printTitle($FH_OUT, $$logEntry_ar[$LOG_HEADER]);
  printStatusKey($FH_OUT);

  # Print site/IFPC map display
  if (defined($$logEntry_ar[$LOG_SITE]) && 
      (defined($$logEntry_ar[$LOG_IFPC]) || defined($$logEntry_ar[$LOG_PROBEPROC]))) {
    my @allSites      = getAllSites(@$logEntry_ar);
    my @allCardcages  = getAllCardcages(@$logEntry_ar);
    my @allProbeProcs = getAllProbeProcs(@$logEntry_ar);
    my @allBroadBandProbeProcs = getAllBroadBandProbeProcs(@$logEntry_ar);
    my @allAMC = getAllAMC(@$logEntry_ar);
    my @allDSP = getAllDSP(@$logEntry_ar);
    my @allSDB = getAllSDB(@$logEntry_ar);
    my @allEPP = getAllEPP(@$logEntry_ar);

    # Print header line
    my $header1 = "Site_";
    my $header2 = "     ";
    if (@allProbeProcs > 0) {
      foreach my $probeProc (@allProbeProcs) {
	$header1 .= " pp";
	$header2 .= sprintf( " %02d", $probeProc);
      }
    }
    if (@allAMC > 0) {
      foreach my $AMC (@allAMC) {
	$header1 .= "amc";
	$header2 .= sprintf( " %02d", $AMC);
      }
    }
    if (@allDSP > 0) {
      foreach my $DSP (@allDSP) {
	$header1 .= "dsp";
	$header2 .= sprintf( " %02d", $DSP);
      }
    }
    if (@allSDB > 0) {
      foreach my $SDB (@allSDB) {
	$header1 .= "sdb";
	$header2 .= sprintf( " %02d", $SDB);
      }
    }
    if (@allBroadBandProbeProcs > 0) {
      foreach my $BroadBandprobeProc (@allBroadBandProbeProcs) {
	$header1 .= " bp";
	$header2 .= sprintf( " %02d", $BroadBandprobeProc);
      }
    }
    if (@allEPP > 0) {
      foreach my $EPP (@allEPP) {
	$header1 .= " ep";
	$header2 .= sprintf( " %02d", $EPP);
      }
    }
    if (@allCardcages > 0) {
      foreach my $cardcage (@allCardcages) {
	$header1 .= sprintf(" __cc%02d__", $cardcage);
	$header2 .= " 01234567";
      }
    }
    print($FH_OUT "\n", $header1, "\n", $header2, "\n");

    # Print each site/ifpc
    foreach my $site (@allSites) {
      my $statusSite     = sprintf("%03d", $site);
      my $statusCodeSite = getStatusCode($$logEntry_ar[$LOG_SITE]{$site});
      $statusSite       .= ' ' . getStatusChar($statusCodeSite);
      $sitesTotal++;
      $sitesInComms++ if ($statusCodeSite == $STATUS_IN_COMMS);
      
      if (@allProbeProcs > 0) {
	foreach my $probeProc (@allProbeProcs) {
	  my $statusCodeProbeProc = getStatusCode($$logEntry_ar[$LOG_PROBEPROC]{$site}{$probeProc});
	  if ($statusCodeProbeProc == $STATUS_NOT_LISTED) {
	    $statusSite .= ' ' . ' ' . ' ';
	  } else {
	    $statusSite .= ' ' . ' ' . getStatusChar($statusCodeProbeProc);
	    $probeProcsTotal++;
	    $probeProcsInComms ++ if ($statusCodeProbeProc == $STATUS_IN_COMMS);
	  }
	}
      }
      if (@allAMC > 0) {
	foreach my $AMC (@allAMC) {
	  my $statusCodeAMC = getStatusCode($$logEntry_ar[$LOG_AMC]{$site}{$AMC});
	  if ($statusCodeAMC == $STATUS_NOT_LISTED) {
	    $statusSite .= ' ' . ' ' . ' ';
	  } else {
	    $statusSite .= ' ' . ' ' . getStatusChar($statusCodeAMC);
	    $AMCProcsTotal++;
	    $AMCProcsInComms ++ if ($statusCodeAMC == $STATUS_IN_COMMS);
	  }
	}
      }
      if (@allDSP > 0) {
	foreach my $DSP (@allDSP) {
	  my $statusCodeDSP = getStatusCode($$logEntry_ar[$LOG_DSP]{$site}{$DSP});
	  if ($statusCodeDSP == $STATUS_NOT_LISTED) {
	    $statusSite .= ' ' . ' ' . ' ';
	  } else {
	    $statusSite .= ' ' . ' ' . getStatusChar($statusCodeDSP);
	    $DSPProcsTotal++;
	    $DSPProcsInComms ++ if ($statusCodeDSP == $STATUS_IN_COMMS);
	  }
	}
      }
      if (@allSDB > 0) {
	foreach my $SDB (@allSDB) {
	  my $statusCodeSDB = getStatusCode($$logEntry_ar[$LOG_SDB]{$site}{$SDB});
	  if ($statusCodeSDB == $STATUS_NOT_LISTED) {
	    $statusSite .= ' ' . ' ' . ' ';
	  } else {
	    $statusSite .= ' ' . ' ' . getStatusChar($statusCodeSDB);
	    $SDBProcsTotal++;
	    $SDBProcsInComms ++ if ($statusCodeSDB == $STATUS_IN_COMMS);
	  }
	}
      }

      if (@allBroadBandProbeProcs > 0) {
	foreach my $BroadBandprobeProc (@allBroadBandProbeProcs) {
	  my $statusCodeBroadBandProbeProc = getStatusCode($$logEntry_ar[$LOG_BROADBANDPROBEPROC]{$site}{$BroadBandprobeProc});
	  if ($statusCodeBroadBandProbeProc == $STATUS_NOT_LISTED) {
	    $statusSite .= ' ' . ' ' . ' ';
	  } else {
	    $statusSite .= ' ' . ' ' . getStatusChar($statusCodeBroadBandProbeProc);
	    $BroadBandprobeProcsTotal++;
	    $BroadBandprobeProcsInComms ++ if ($statusCodeBroadBandProbeProc == $STATUS_IN_COMMS);
	  }
	}
      }
      if (@allEPP > 0) {
	foreach my $EPP (@allEPP) {
	  my $statusCodeEPP = getStatusCode($$logEntry_ar[$LOG_EPP]{$site}{$EPP});
	  if ($statusCodeEPP == $STATUS_NOT_LISTED) {
	    $statusSite .= ' ' . ' ' . ' ';
	  } else {
	    $statusSite .= ' ' . ' ' . getStatusChar($statusCodeEPP);
	    $EPPProcsTotal++;
	    $EPPProcsInComms ++ if ($statusCodeEPP == $STATUS_IN_COMMS);
	  }
	}
      }
      if (@allCardcages > 0) {
	foreach my $cardcage (@allCardcages) {
	  my $statusCardcage = "";
	  my $ifpcsInCardcage = 0;
	  
	  for (my $ifpc = 0; $ifpc <= 7; $ifpc++) {
	    my $statusCodeIfpc = getStatusCode($$logEntry_ar[$LOG_IFPC]{$site}{$cardcage}{$ifpc});
	    $statusCardcage   .= getStatusChar($statusCodeIfpc);
	    if ($statusCodeIfpc != $STATUS_NOT_LISTED) {
	      $ifpcsInCardcage++;
	      $ifpcsTotal++;
	      $ifpcsInComms++ if ($statusCodeIfpc == $STATUS_IN_COMMS);
	    }
	  }
	  # Print cardcages as spaces if no IFPCs found - cardcage does not exist
	  if ($ifpcsInCardcage == 0) {
	    $statusSite .= ' ' . '        ';
	  } else {
	    $statusSite .= ' ' . $statusCardcage;
	  }
	}
      }
      
      print($FH_OUT $statusSite, "\n");
    }
  }

  # Print workstation/app server log
  if (defined($$logEntry_ar[$LOG_GUI])) {
    my $guiStatus1 = "Wrkstn/ ";
    my $guiStatus2 = "AppSvr  ";
    foreach my $workstation (sort {$a <=> $b} keys %{$$logEntry_ar[$LOG_GUI]}) {
      my $statusCodeGui = getStatusCode($$logEntry_ar[$LOG_GUI]{$workstation});
      $guiStatus1 .= sprintf(" %02d", $workstation);
      $guiStatus2 .= '  ' . getStatusChar($statusCodeGui);
      $guisTotal++;
      $guisInComms++ if ($statusCodeGui == $STATUS_IN_COMMS);
    }
    print($FH_OUT "\n", $guiStatus1, "\n", $guiStatus2, "\n");
  }
  
  # Print any unknown log lines found in the file
  if (defined($$logEntry_ar[$LOG_UNMATCHED])) {
    print($FH_OUT "\n");
    foreach my $line (@{$$logEntry_ar[$LOG_UNMATCHED]}) {
      print($FH_OUT $line, "\n");
    }
  }

  # Print the summary
  print($FH_OUT "\n");
  printSummary($FH_OUT, "Sites         ", $sitesTotal, $sitesInComms)
    if ($sitesTotal > 0);
  printSummary($FH_OUT, "Probe Procs   ", $probeProcsTotal, $probeProcsInComms)
    if ($probeProcsTotal > 0);
  printSummary($FH_OUT, "AMC           ", $AMCProcsTotal, $AMCProcsInComms)
    if ($AMCProcsTotal > 0);
  printSummary($FH_OUT, "BPP           ", $BroadBandprobeProcsTotal, $BroadBandprobeProcsInComms)
    if ($BroadBandprobeProcsTotal > 0);
  printSummary($FH_OUT, "EPP           ", $EPPProcsTotal, $EPPProcsInComms)
    if ($EPPProcsTotal > 0);
  printSummary($FH_OUT, "IFPCs         ", $ifpcsTotal, $ifpcsInComms)
    if ($ifpcsTotal > 0);
  printSummary($FH_OUT, "Wrkstn/AppSvr ", $guisTotal, $guisInComms)
    if ($guisTotal  > 0);
  printSummary($FH_OUT, "DSP           ", $DSPProcsTotal, $DSPProcsInComms)
    if ($DSPProcsTotal  > 0);
  printSummary($FH_OUT, "SDB           ", $SDBProcsTotal, $SDBProcsInComms)
    if ($SDBProcsTotal  > 0);
}


###############################################################################
#

sub printNotInCommsList(*\@) {
  my ($FH_OUT, $logEntry_ar) = @_;

  # Keep statistics count of total entities and entities in comms
  my $sitesTotal        = 0;
  my $sitesInComms      = 0;
  my $probeProcsTotal   = 0;
  my $probeProcsInComms = 0;
  my $BroadBandprobeProcsTotal   = 0;
  my $BroadBandprobeProcsInComms = 0;
  my $AMCProcsTotal     = 0;
  my $AMCProcsInComms   = 0;
  my $EPPProcsTotal     = 0;
  my $EPPProcsInComms   = 0;
  my $ifpcsTotal        = 0;
  my $ifpcsInComms      = 0;
  my $guisTotal         = 0;
  my $guisInComms       = 0;
  my $DSPProcsTotal     = 0;
  my $DSPProcsInComms   = 0;
  my $SDBProcsTotal     = 0;
  my $SDBProcsInComms   = 0;

  my $overallStatus     = "";

  # Print header lines
  printTitle($FH_OUT, $$logEntry_ar[$LOG_HEADER]);

  # Print each site/ifpc
  if (defined($$logEntry_ar[$LOG_SITE])) {
    foreach my $site (sort {$a <=> $b} keys %{$$logEntry_ar[$LOG_SITE]}) {
      my $siteStatus      = "";
      my $probeProcStatus = "";
      my $BroadBandprobeProcStatus = "";
      my $AMCProcStatus = "";
      my $DSPProcStatus = "";
      my $SDBProcStatus = "";
      my $EPPProcStatus = "";
      my $cardcageStatus  = "";

      # Print site rsp out of comms
      if (defined($$logEntry_ar[$LOG_SITE]{$site})) {
	my $RSP=0;
	foreach my $auxsite (sort {$a <=> $b} keys % {$$logEntry_ar[$LOG_SITE]{$site}}) {
	 my $statusCode = getStatusCode($$logEntry_ar[$LOG_SITE]{$site}{$auxsite});
	 if ($statusCode != $STATUS_NOT_LISTED) {
	  $sitesTotal++;
	  if ($statusCode == $STATUS_IN_COMMS) {
	    $sitesInComms++;
	  } else {
	    my $tagline=(($auxsite == 1) ? "   RemoteSiteProcessor\n" : "   AuxRSP " . $auxsite);
 	    if (($siteStatus eq "") || $RSP) {
	       $siteStatus .= $tagline;
            } else {
	       $siteStatus .= ", " . $auxsite;
	    }  
	    if ($auxsite == 1) { 
               $RSP=1; 
 	    }
	  }
	}
      }
	$siteStatus .= "\n" if ($siteStatus ne "");
      }

      # Print probe procs out of comms
      if (defined($$logEntry_ar[$LOG_PROBEPROC]{$site})) {
	foreach my $probeProc (sort {$a <=> $b} keys %{$$logEntry_ar[$LOG_PROBEPROC]{$site}}) {
	  my $statusCode = getStatusCode($$logEntry_ar[$LOG_PROBEPROC]{$site}{$probeProc});
	  if ($statusCode != $STATUS_NOT_LISTED) {
	    $probeProcsTotal++;
	    if ($statusCode == $STATUS_IN_COMMS) {
	      $probeProcsInComms++;
	    } else {
	      $probeProcStatus .= (($probeProcStatus eq "") ? "    Probe Procs " : ", ") . $probeProc;
	    }
	  }
	}
	$probeProcStatus .= "\n" if ($probeProcStatus ne "");
      }
     
      # Print AMC out of comms
      if (defined($$logEntry_ar[$LOG_AMC]{$site})) {
	foreach my $cardcage (sort {$a <=> $b} keys %{$$logEntry_ar[$LOG_AMC]{$site}}) {
	  my $AMCProcStatus = "";
	  foreach my $AMC (sort {$a <=> $b} keys %{$$logEntry_ar[$LOG_AMC]{$site}{$cardcage}}) {
	    my $statusCode = getStatusCode($$logEntry_ar[$LOG_AMC]{$site}{$cardcage}{$AMC});
	    if ($statusCode != $STATUS_NOT_LISTED) {
	      $AMCProcsTotal++;
	      if ($statusCode == $STATUS_IN_COMMS) {
	        $AMCProcsInComms++;
	      } else {
		$AMCProcStatus .= (($AMCProcStatus eq "") ? "    LY CC " . $cardcage . " AMC " : ", ") . $AMC;
	      }
	    }
	  }
	  $cardcageStatus .= $AMCProcStatus . "\n" if ($AMCProcStatus ne "");
	}
      }

      if (defined($$logEntry_ar[$LOG_DSP]{$site})) {
	foreach my $DSP (sort {$a <=> $b} keys %{$$logEntry_ar[$LOG_DSP]{$site}}) {
	  my $statusCode = getStatusCode($$logEntry_ar[$LOG_DSP]{$site}{$DSP});
	  if ($statusCode != $STATUS_NOT_LISTED) {
	    $DSPProcsTotal++;
	    if ($statusCode == $STATUS_IN_COMMS) {
	      $DSPProcsInComms++;
	    } else {
	      $DSPProcStatus .= (($DSPProcStatus eq "") ? "    Datastore       " : ", ") . $DSP;
	    }
	  }
	}
	$DSPProcStatus .= "\n" if ($DSPProcStatus ne "");
      }
      if (defined($$logEntry_ar[$LOG_SDB]{$site})) {
	foreach my $SDB (sort {$a <=> $b} keys %{$$logEntry_ar[$LOG_SDB]{$site}}) {
	  my $statusCode = getStatusCode($$logEntry_ar[$LOG_SDB]{$site}{$SDB});
	  if ($statusCode != $STATUS_NOT_LISTED) {
	    $SDBProcsTotal++;
	    if ($statusCode == $STATUS_IN_COMMS) {
	      $SDBProcsInComms++;
	    } else {
	      $SDBProcStatus .= (($SDBProcStatus eq "") ? "    Databroker      " : ", ") . $SDB;
	    }
	  }
	}
	$SDBProcStatus .= "\n" if ($SDBProcStatus ne "");
      }


     
      # Print BPP out of comms 
      if (defined($$logEntry_ar[$LOG_BROADBANDPROBEPROC]{$site})) {
	foreach my $cardcage (sort {$a <=> $b} keys %{$$logEntry_ar[$LOG_BROADBANDPROBEPROC]{$site}}) {
	  my $BroadBandprobeProcStatus = "";
	  foreach my $BroadBandprobeProc (sort {$a <=> $b} keys %{$$logEntry_ar[$LOG_BROADBANDPROBEPROC]{$site}{$cardcage}}) {
	    my $statusCode = getStatusCode($$logEntry_ar[$LOG_BROADBANDPROBEPROC]{$site}{$cardcage}{$BroadBandprobeProc});
	    if ($statusCode != $STATUS_NOT_LISTED) {
	      $BroadBandprobeProcsTotal++;
	      if ($statusCode == $STATUS_IN_COMMS) {
	        $BroadBandprobeProcsInComms++;
	      } else {
		$BroadBandprobeProcStatus .= (($BroadBandprobeProcStatus eq "") ? "    LY CC " . $cardcage . " BPP " : ", ") . $BroadBandprobeProc;
	      }
	    }
	  }
	  $cardcageStatus .= $BroadBandprobeProcStatus . "\n" if ($BroadBandprobeProcStatus ne "");
	}
      }
      # Print EPP out of comms 
      if (defined($$logEntry_ar[$LOG_EPP]{$site})) {
	foreach my $cardcage (sort {$a <=> $b} keys %{$$logEntry_ar[$LOG_EPP]{$site}}) {
	  my $EPPProcStatus = "";
	  foreach my $EPP (sort {$a <=> $b} keys %{$$logEntry_ar[$LOG_EPP]{$site}{$cardcage}}) {
	    my $statusCode = getStatusCode($$logEntry_ar[$LOG_EPP]{$site}{$cardcage}{$EPP});
	    if ($statusCode != $STATUS_NOT_LISTED) {
	      $EPPProcsTotal++;
	      if ($statusCode == $STATUS_IN_COMMS) {
	        $EPPProcsInComms++;
	      } else {
		$EPPProcStatus .= (($EPPProcStatus eq "") ? "    LY CC " . $cardcage . " EPP " : ", ") . $EPP;
	      }
	    }
	  }
	  $cardcageStatus .= $EPPProcStatus . "\n" if ($EPPProcStatus ne "");
	}
      }

      # Print IFPCs out of comms
      if (defined($$logEntry_ar[$LOG_IFPC]{$site})) {
	foreach my $cardcage (sort {$a <=> $b} keys %{$$logEntry_ar[$LOG_IFPC]{$site}}) {
	  my $ifpcStatus = "";
	  foreach my $ifpc (sort {$a <=> $b} keys %{$$logEntry_ar[$LOG_IFPC]{$site}{$cardcage}}) {
	    my $statusCode = getStatusCode($$logEntry_ar[$LOG_IFPC]{$site}{$cardcage}{$ifpc});
	    if ($statusCode != $STATUS_NOT_LISTED) {
	      $ifpcsTotal++;
	      if ($statusCode == $STATUS_IN_COMMS) {
		$ifpcsInComms++;
	      } else {
		$ifpcStatus .= (($ifpcStatus eq "") ? "    Cardcage " . $cardcage . " IFPC " : ", ") . $ifpc;
	      }
	    }
	  }
	  $cardcageStatus .= $ifpcStatus . "\n" if ($ifpcStatus ne "");
	}
      }

      # Print site summary
      if ($siteStatus ne "" || $probeProcStatus ne "" || $cardcageStatus ne "" || $DSPProcStatus ne "") {
	$overallStatus .= "  Site $site\n" . $siteStatus . $probeProcStatus . $cardcageStatus . $DSPProcStatus . $SDBProcStatus;
      }
    }
  }

  # Print workstation/app server log
  if (defined($$logEntry_ar[$LOG_GUI])) {
    my $guiStatus = "";
    foreach my $workstation (sort {$a <=> $b} keys %{$$logEntry_ar[$LOG_GUI]}) {
      my $statusCode = getStatusCode($$logEntry_ar[$LOG_GUI]{$workstation});
      if ($statusCode != $STATUS_NOT_LISTED) {
	$guisTotal++;
	if ($statusCode == $STATUS_IN_COMMS) {
	  $guisInComms++;
	} else {
	  $guiStatus .= (($guiStatus eq "") ? "  Wrkstn/AppSvr " : ", ") . $workstation;
	}
      }
    }
    if ($guiStatus ne "") {
      $overallStatus .= $guiStatus . "\n";
    }
  }

  if ($overallStatus eq "") {
    print($FH_OUT "\nAll entities are in comms/configured\n");
  } else {
    print($FH_OUT "\nThese entities are NOT in comms or NOT configured:\n", $overallStatus);
  }

  # Print any unknown log lines found in the file
  if (defined($$logEntry_ar[$LOG_UNMATCHED])) {
    print($FH_OUT "\n");
    foreach my $line (@{$$logEntry_ar[$LOG_UNMATCHED]}) {
      print($FH_OUT $line, "\n");
    }
  }

  # Print the summary
  print($FH_OUT "\n");
  printSummary($FH_OUT, "Sites        ", $sitesTotal, $sitesInComms)
    if ($sitesTotal > 0);
  printSummary($FH_OUT, "Probe Procs  ", $probeProcsTotal, $probeProcsInComms)
    if ($probeProcsTotal > 0);
  printSummary($FH_OUT, "AMCs         ", $AMCProcsTotal, $AMCProcsInComms)
    if ($AMCProcsTotal > 0);
  printSummary($FH_OUT, "BPPs         ", $BroadBandprobeProcsTotal, $BroadBandprobeProcsInComms)
    if ($BroadBandprobeProcsTotal > 0);
  printSummary($FH_OUT, "EPPs         ", $EPPProcsTotal, $EPPProcsInComms)
    if ($EPPProcsTotal > 0);
  printSummary($FH_OUT, "IFPCs        ", $ifpcsTotal, $ifpcsInComms)
    if ($ifpcsTotal > 0);
  printSummary($FH_OUT, "Wrkstn/AppSvr", $guisTotal, $guisInComms)
    if ($guisTotal  > 0);
  printSummary($FH_OUT, "DSP          ", $DSPProcsTotal, $DSPProcsInComms)
    if ($DSPProcsTotal  > 0);
  printSummary($FH_OUT, "SDB          ", $SDBProcsTotal, $SDBProcsInComms)
    if ($SDBProcsTotal  > 0);
}

###############################################################################
#

sub main {
  my @log;
  my $printMap  = FALSE;
  my $printList = TRUE;

  foreach my $arg (@ARGV) {
    if ($arg eq "-map") {
      $printMap  = TRUE;
      $printList = FALSE;
    } elsif ($arg eq "-list") {
      $printMap  = FALSE;
      $printList = TRUE;
    }
  }

  readLog(*STDIN{IO}, @log);

  my $lastLogEntry = $#log;
  if ($lastLogEntry < 0) {
    print(STDOUT "No comms status listings found\n");
  } else {
    if ($printMap) {
      printStatusMap(*STDOUT{IO}, @{$log[$lastLogEntry]});
    }
    if ($printList) {
      printNotInCommsList(*STDOUT{IO}, @{$log[$lastLogEntry]});
    } 
  }
}


__DATA__
p7commsstatus -i|-s|-w [<central_server>] filter by site cc  -overview/summary/map -list -??
print alternative output format by site list only out of comms?
control column width - multiple map outputs (suppress sites w/no output on line?)
put in decoded site name short/long - what about app server names?

