#! /usr/local/bin/perl -w
################################################################################
##      PROGRAM tdtsummary - expects dump-format TDTs
##      
##      AUTHOR: Jeremy Yang
##      05 June 1996
################################################################################

%data_count       = ( );  ## Total number of datatype occurances
%data_bytes       = ( );  ## Total bytes for datatype
%data_tdts        = ( );  ## Total number of TDTs with datatype
%data_pri_ids     = ( );  ## Total number of TDTs rooted with datatype
%data_in_this_tdt = ( );  ## Flag: does this TDT have this datatype?
%data_fields_per  = ( );  ## How many fields
$FILEIN = "-";
$FILEOUT = ">-";
$quiet = 0;
$MINORCOUNT = 20;
$MAJORCOUNT = 1000;
$| = 1;

sub PRINTHELP {
  print "\t******************************************************\n";
  print "\t* tdtsummary [-h] [-q] [-i infile] [-o outfile]      *\n";
  print "\t*         -h  ....... help                           *\n";
  print "\t*         -q  ....... quiet (no progress reports)    *\n";
  print "\t* Input must be dump-format TDTs (use tdtcat).       *\n";
  print "\t* e.g.: thorlist foo\@bar | tdtcat -d | tdtsummary    *\n";
  print "\t*       tdtcat -d < foo.tdt | tdtsummary             *\n";
  print "\t******************************************************\n";
  exit;
}

### Parse args ###
for ($i = 0; $i <= $#ARGV; $i++) {
  if (($ARGV[$i] eq "-h")) { &PRINTHELP; }
  elsif ($ARGV[$i] eq "-i") { $FILEIN = $ARGV[++$i]; }
  elsif ($ARGV[$i] eq "-o") { $FILEOUT = ">".$ARGV[++$i]; }
  elsif ($ARGV[$i] eq "-q") { $quiet = 1; }
}
open(FILEIN) || die "Can't open \"$FILEIN\" for input\n";
open(FILEOUT) || die "Can't open \"$FILEOUT\" for output\n";

$idcount = 0;

### TDT loop (must have 1 TDT per line) ###
TDT:
for ($tdtcount = $errcount = 0; $tdt = <FILEIN>; ++$tdtcount) {
  chop($tdt);

  ### Check for bad TDT ###
  if (!&CHECKTDT($tdt)) {
    $errcount++;
    $tdtcount--;
    next TDT;
  }

  $position = 0;

  ### Dataitem loop ###
  while (0 < ($i = index($tdt, "<", $position))) {
    $tag = substr($tdt, $position, $i - $position);
    if (!exists($data_count{$tag})) { &INIT_STRUCT($tag, $tdt, $position); }

    $data_in_this_tdt{$tag} = 1;               ### set presence flag
    if (0 == $position) { ++$data_pri_ids{$tag}; }
    ++$data_count{$tag};

    $j = DU_INDEX($tdt, ">", $i);
    $bytes = $j - $i -1;
    $data_bytes{$tag} += $bytes;
    $position = $j + 1;

    if ("\$" eq substr($tag, 0, 1)) { $idcount++; }
  }
  
  foreach $tag (keys(%data_in_this_tdt)) {
    $data_tdts{$tag} += $data_in_this_tdt{$tag};
    $data_in_this_tdt{$tag} = 0;
  }

  if ($tdtcount) {
    if (!$quiet && !($tdtcount%$MINORCOUNT)) { printf STDERR "."; }
    if (!$quiet && !($tdtcount%$MAJORCOUNT)) {
      printf STDERR "%d TDTs\n", $tdtcount;
    }
  }
}
if (!$quiet && ($tdtcount%$MAJORCOUNT)) {
  printf STDERR "%d TDTs\n", $tdtcount;
}

&PRINT_REPORT();

printf STDERR "So long, baby!\n";
exit 0;


################################################################################
##  SUBROUTINE INIT_STRUCT
################################################################################

sub INIT_STRUCT {

  local($tag, $tdt, $position) = @_;
  local($i, $j);

  $data_count{$tag}       = 0;
  $data_bytes{$tag}       = 0;
  $data_tdts{$tag}        = 0;
  $data_pri_ids{$tag}     = 0;
  $data_in_this_tdt{$tag} = 1;
  $data_fields_per{$tag}  = 1;

  $j = DU_INDEX($tdt, ">", $position);
  while (($j > ($i = DU_INDEX($tdt, ";", $position))) && ($i > 0)) {
    ++$data_fields_per{$tag};
    $position = $i + 1;
  }
}

################################################################################
##  SUBROUTINE DU_INDEX -- find next occurance of a character in a TDT
##  respecting Thor's quoting rules.  For example, the following are
##  legal TDTs:
##                 $SMI<CC>$NAM<ethane>REM<"vbar: |">|
##                 $SMI<CCCCC>$NAM<pentane>REM<"This ->""<- is a quote">|
##  And these are not legal:
##                 $SMI<C>$NAM<methane>BP< >0.8K>|
##                 $SMI<CC>$NAM<ethane>REM<It's a "gas", man!>|
################################################################################
 
sub DU_INDEX {
 
  local($tdt, $char, $position) = @_;
  local($i, $j, $k, $balanced);
 
  while (0 <= ($i = index($tdt, $char, $position))) {
    $j = index($tdt, "\"", $position);              ## 1st quote after $position
    if ($j < 0 || $i < $j) {
      last;
    } else {                                        ## find next quote
      $balanced = 0;
      $k = $j + 1;
      while (0 < ($k = index($tdt, "\"", $k))) {
        if ("\"" eq substr($tdt, $k + 1, 1)) {      ## quoted quote?
          $position = $k += 2;
        } else {
          $position = ++$k;
          $balanced = 1;
        }
      }
      if (!$balanced) {
        $i = -1;
        last;
      }
    }
  }
  $position = $i;
 
}

################################################################################
##  SUBROUTINE PRINT_REPORT
################################################################################

sub PRINT_REPORT {

  local($tag_count = 0, $total_dtypes = 0, $total_bytes = 0,
        $ovh_tags = 0, $ovh_delimiters = 0, $ovh_total = 0);

  system("date");
  printf("\nTDTSUMMARY for \"%s\"\n\n", $FILEIN);
  printf("\tTDT count        = %6d\n", $tdtcount);
  printf("\tID count         = %6d\n", $idcount);
  printf("\tXREF count       = %6d\n", $idcount - $tdtcount);
  printf("\tERRORS           = %6d\n", $errcount);
  printf("------------------------------------------------------------\n");
  printf("Tag       #fields    Number   TDTs w/   Pri-IDs        Bytes\n");
  printf("--------- ------- --------- --------- --------- ------------\n");
  foreach $tag (sort(keys(%data_count))) {
    
    ++$tag_count;
    $total_dtypes +=  $data_count{$tag};
    $total_bytes +=  $data_bytes{$tag};
 
    $ovh_tags += length($tag)*$data_count{$tag};
    $ovh_delimiters += $data_count{$tag}*(1 + $data_fields_per{$tag});
    printf("%-9s %7d %9d %9d %9d %12d\n", $tag, $data_fields_per{$tag},
           $data_count{$tag}, $data_tdts{$tag}, $data_pri_ids{$tag},
           $data_bytes{$tag});

  }
  printf("--------- ------- --------- --------- --------- ------------\n");
  printf("%9d         %9d           %9d %12d\n",
    $tag_count, $total_dtypes, $tdtcount, $total_bytes);
  printf("------------------------------------------------------------\n");
  printf("Overhead for tags:                              %12d\n",
         $ovh_tags);
  printf("Overhead for delimiters:                        %12d\n",
         $ovh_delimiters + $tdtcount);
  $ovh_total = $ovh_delimiters + $ovh_tags + 2*$tdtcount;
  printf("Total overhead w/ newlines:                     %12d\n",
         $ovh_total);
  $total_fsize = $ovh_total + $total_bytes;
  printf("Total file size:                     (%6.1fMB) %12d\n",
         $total_fsize/1000000.0, $total_fsize);
  printf("------------------------------------------------------------\n");
}

################################################################################
##  SUBROUTINE CHECKTDT
################################################################################

sub CHECKTDT {

  local($tdt) = @_;
  $_ = $tdt;

  if (!/^\$.*\|$/) {
    print STDERR "ERROR (TDTSUMMARY): TDT = \"$tdt\"\n";
    0;
  } else { 1; }
}

