#!/usr/local/bin/perl5 -w
#
# $Source: /home/cur/djb1/develop/logtools/RCS/sum-format,v $
#
# $Id: sum-format,v 1.25 1995/03/07 13:39:57 djb1 Exp $
#
# Formats summarised data prettily.
#
# USAGE: sum-format [config options] [--html] [--htmltitle=title] [--percent]
#        [--top=number] [summary file]
#
# (C) Copyright 1994,1995 Dave Beckett <D.J.Beckett@ukc.ac.uk>
# University of Kent at Canterbury
#
# This program is free software; you may distribute under the terms of
# either the GNU General Public License or the Artistic License, as
# specified in the README file.
#

require 'option_utils.pl';
require 'summary_utils.pl';


sub MENTION {
  &MENTION;
  $verbose=1;
  $summary_field_types=1;
}


$percentfmtlength=6;


sub parse_local_options {
  local(*args)=@_;
  local($usage)=0;
  local($top)='';
  local($htmltitle)='Summary of data';

  local(@newargs)=();
  while(defined($_=shift(@args))) {
    if (/^--top=(.+)$/) {
      $top=$1;
    } elsif (/^--htmltitle=(.+)$/) {
      $htmltitle=$1;
    } else {
      push(@newargs, $_);
      last if /^--$/ || !/^--/;
    }
  }
  @args=(@newargs, @args);
  return ($usage,$top,$htmltitle);
}


sub percent_fmt {
  local($val,$total)=@_;
  return '-' if !defined($total) || !defined($val) || !$total;
  sprintf("%2.2f", int($val/$total*10000+0.5)/100);
}


sub sumformat {
  local($html,$htmltitle,$percent,$top,$file)=@_;

  if (!open (IN, $file)) {
    warn "$prog_name: Cannot open '$file' - $!\n";
    return;
  }

  local($datacount)=0;
  local($firstdate)='';     # From 'period ... ...'
  local($lastdate)='';      # "
  local($totalaccesses)=''; # From 'totals ... ...'
  local($totalbytes)='';    # "
  local(@infields)=();      # From 'fields ...'
  local($insort_field)='';  # From 'sort-field ...'
  local($noinfields)=0;
  local(@fieldwidths)=();
  local($data_entries)='';
  local(%data)=();
  local($seenfieldwidths)=0;

  while (<IN>) {
    chop;
    next if /^#/;
    if (/^period (\S+) (\S+)/) {
      $firstdate=$1 if !$firstdate || $1 lt $firstdate;
      $lastdate=$2 if !$lastdate || $2 gt $lastdate;
      next;
    }
    if (/^fields (.+)$/) {
      @infields=split(/ /,$1);
      $noinfields=scalar(@infields);
      warn "Found input fields=@infields\n" if $debug>1;
      next;
    }

    if (/^field-widths (.+)$/) {
      @fieldwidths=split(/ /,$1);
      if (!@infields) {
	die "$prog_name: Did not see 'fields' field before 'field-widths\n";
      }
      $seenfieldwidths++;
      next;
    }

    if (/^sort-field (.+)$/) {
      $insort_field=$1;
      next;
    }

    if (/^totals (\d+) (\d+)$/) {
      $totalaccesses=$1; $totalbytes=$2;
      next;
    }
    
    if (/^entries (\d+)$/) {
      $data_entries=$1;
      next;
    }
    
    if (/^data (.+)$/) {
      local($info)=$1;

      warn "data[$datacount]:'$info'\n" if $debug>5;

      if (!$noinfields) {
	warn "$prog_name: Cannot process -- no 'fields' line seen before data\n";
	return;
      }

      if (!$seenfieldwidths) {
	local($i)=0;
	foreach $field (split(/\s+/,$info,$noinfields)) {
	  local($llen,$flen)=(length($field),$fieldwidths[$i]);
	  $fieldwidths[$i]=$llen if !$flen || $llen > $flen;
	} continue {
	  $i++;
	}
      }
      $data{$datacount}=$info;
      $datacount++;
      last if $top && $datacount == $top;
      next;
    }

    warn "$prog_name:$file:$.:Ignoring line: '$_'\n";

  }
  close(IN);

  if ($top && !$insort_field) {
    warn "$prog_name: Printing first $top (probably) unsorted data entries\n";
  }

  if (!$datacount) {
    warn "$prog_name: No data seen in '$file'\n";
    return;
  }

  # Adjust fields for header widths
  foreach $i (0..$#infields) {
    local($flen,$llen)=(length($infields[$i]),$fieldwidths[$i]);
    $fieldwidths[$i]=$flen if $flen > $llen;
  }

  # Format data
  local(@formatlist)=();
  local(@headerformatlist)=();
  local($totalwidth)=0;
  local(@outfields)=();
  local($eval)='@info=@info[';
  foreach $i (0..$#infields) {
    local($fieldwidth)=$fieldwidths[$i];
    local($fieldname)=$infields[$i];
    push(@outfields,$fieldname);

    $eval.="," if $eval;
    $eval.="$i";

    $totalwidth+=$fieldwidth+1;

    local($fmt)=($summary_field_types{$fieldname} ne 'string') ? "%${fieldwidth}s":"%-${fieldwidth}s";
    $fmt="%s" if $fieldname eq 'email';
    push(@formatlist,$fmt);

    local($hdrfmt)=$fmt;
    $hdrfmt=~ s/d$/s/;
    push(@headerformatlist,$hdrfmt);

    if ($percent && ($i != $#infields)) {
      $fieldname="%$fieldname";
      push(@outfields,$fieldname);
      $fieldwidth=length($fieldname);
      $fieldwidth=($percentfmtlength > $fieldwidth) ? $percentfmtlength : $fieldwidth;

      $totalwidth+=$fieldwidth+1;
      $fmt="%${fieldwidth}s";
      push(@formatlist, $fmt);
      $hdrfmt=$fmt;
      $hdrfmt=~ s/d$/s/;
      push(@headerformatlist,$hdrfmt);
    }
  }

  # Make format strings to use with sprintf
  local($headerformatstring)=join(' ',@headerformatlist)."\n";
  local($formatstring)=join(' ',@formatlist)."\n";

  # Add rank column if doing a 'top'
  if ($top) {
    $headerformatstring="rank $headerformatstring";
    $formatstring="%4d $formatstring";
    $totalwidth+=5; # "rank "
  }

  # Build divider
  $divider=('-' x $totalwidth);

  if ($debug>2) {
    warn <<"EOT";
headerfmt  ='$headerformatstring'
datafmt    ='$formatstring'
totalwidth =$totalwidth
EOT
  }

  $eval.="]";

  if ($html) {
    print "<HTML>\n<HEAD>\n<TITLE>$htmltitle</TITLE>\n";
    print "<link href=\"mailto:webmaster\@pilgrim.umass.edu\" rev=\"made\">\n";
    print "</HEAD>\n";
    print "<BODY>\n<H1>$htmltitle</H1>\n";
    print "<PRE>\n";
  }
  # Print header
  print "Data period: $firstdate to $lastdate\n";
  print "Data sorted by field: $insort_field\n" if $insort_field;
  if ($data_entries) {
    if ($top && $top<= $data_entries) {
      print "Data entries: $data_entries (Top $top shown)\n";
    } else {
      print "Data entries: $data_entries\n";
    }
  }
  if ($totalbytes) {
    print "Data totals: $totalbytes bytes / $totalaccesses accesses\n";
    printf "Data total average transfer: %d bytes\n", int(0.5+$totalbytes/$totalaccesses);
  }
  print "\n";
  printf($headerformatstring,@outfields);
  print "$divider\n";

  # Print data lines in given order
  local($rank)=1;
  foreach $i (0..($datacount-1)) {
    local(@info)=split(/\s+/,$data{$i},$noinfields);

    warn "evalling '$eval'\n" if $debug>4;
    eval $eval;

    if ($percent) {
      local($a,$b)=@info[0..1];
      @info=($a,&percent_fmt($a,$totalaccesses),
	     $b,&percent_fmt($b,$totalbytes),
	     $info[2]);
    }

    if ($top) {
      last if $rank>$top;
      unshift(@info,$rank);
      $rank++;
    }
    printf($formatstring,@info);
  }
  if ($html) {
    print "</PRE>\n</BODY>\n</HTML>\n";
  }
}

# MAIN PROGRAM
#
#
#
#

&set_prog_name;

# Parse options
&handle_config_options(*ARGV);
($usage,$top,$htmltitle)=&parse_local_options(*ARGV);
$usage=&handle_local_flag_options(*ARGV, "html", "percent");
$usage=&remove_remaining_options(*ARGV) if !$usage;
$usage=1 if !$usage && @ARGV>1;

die <<"EOT" if $usage;
USAGE: $prog_name [config options] [--html] [--htmltitle=title] [--percent]
       [--top=number] [summary file]
EOT

# Remaining argument is summary file
local($summaryfile)=$ARGV[0] || '-';

&print_config_info if $verbose>2;

&sumformat($html,$htmltitle,$percent,$top,$summaryfile);

exit 0;
