#!/usr/bin/perl
#
# This perl script file expects two arguments: datafilename and location
#     e.g. listing family.txt Home
# The script
#  - prepares a time stamp and the header line
#  - sort the data file (as per the key prefix) and save it in the data file
#  - swap first and lastname of each contact person and build a lastname based sort file
#  - rearranges the pages of the firstname-based file and the lastname-based file into a
#      a listing file for the given datafile.
#
# Turn on the DUPLEX and set DUPLEX BINDING as SHORT EDGE on papermill/press
# Logion goliath (solaris OS), tcsh, print the jnamelist file on press
#  use Unix print command as "lpr -Ppress jnamelist"
# Reset the DUPLEX BINDING to LONG on papermill/press
# 
# Author: Prabakar 5/29/10

use POSIX;
use constant METATAG	=> '$'; # '\044'
use constant TOPMARGIN	=> 0; # no. of blank lines at the top of each page
use constant FOOTMARGIN	=> 0; # no. of blank lines at the bottom of each page
use constant LEFTMARGIN	=> 0;
use constant LEFTSPACES => " " x LEFTMARGIN;
use constant LINEWIDTH	=> 92;
use constant LINE1SKIP  => (LINEWIDTH - LEFTMARGIN -17)/2; # timestamp: 17 chars
use constant LINE2SKIP  => (LINEWIDTH - LEFTMARGIN -17-40)/2; # databankfile and location are 20char max
use constant PAGEHEIGHT	=> 60; # the no. of lines on a printed page for the chosen printer
use constant INDENT	=> 3; # left indent for sublines of a fold
#use constant FORMFEED	=> '\014';
#use constant BLANK	=> ' '; # '\040'

sub compareLines {
  $aidx = index($a, METATAG);
  $bidx = index($b, METATAG);
  if (($aidx >= 0) && ($bidx >= 0)) {
  # compare the key segments (including $ and the tag letter) of both lines 
    $akey = substr $a, 0, ($aidx + 2);
    $bkey = substr $b, 0, ($bidx + 2);
    if ($akey eq $bkey) { 0; }
    elsif ($akey lt $bkey) { -1; }
    else { +1; }
  }
  elsif ($a =~ /^{/) { +1; } # Moves "{End of the directory}" line to tail
  elsif ($b =~ /^{/) { -1; }
  elsif ($aidx < 0) { -1; } # Moves all untagged lines to the head
  else { +1; }
}

sub orderLines {
# sort the lines of the given file where the sort key on each line
#  is terminated by the meta tag. Also, strip blank lines and save the
#  sorted result in the same file
  my @inpLines = `cat $_[0]`;
  foreach (@inpLines) {
    s/\s+$//; # strip trailing whitespace
  }
  my @orderLines = sort compareLines @inpLines;
  open(orderF, ">$_[0]") || die "cannot open output file $_[0] - $!";
  foreach $line (@orderLines) {
    if ($line !~ /^$/) { print orderF "$line\n"; }
  }
  close(orderF);
}

sub foldLines {
# For each person in the input file, concatenate all data information together as one line
#  and then fold the line such that the first line is full output width and the rest
#   folded with the given indentation.
 my ($inpFile, $foldFile) = @_;
 open(inpF, "<".$inpFile) || die "cannot open input file $inpFile - $!";
 open(foldF, ">>".$foldFile) || die "cannot open output file $foldFile - $!";
 $sublineInsert = " " x INDENT;
 $fstLineDataMax = LINEWIDTH - LEFTMARGIN;
 $subLineDataMax = LINEWIDTH - LEFTMARGIN - INDENT;
 $prevName = "";
 $outLine = "";
 while (<inpF>) {
  chomp;
  $inpLine = $_;
  $currName = "";
  $currData = "";
  $posn = index($inpLine, METATAG);
  if ($posn >= 0) {
   $currName = substr $inpLine, 0, $posn;
   $currData = substr $inpLine, $posn;
  }
  if ( $prevName eq "") { $outLine = $inpLine; }
  elsif ($prevName eq $currName) { $outLine .= " $currData"; }
  else { # fold $outLine and output to the folded file
   $outLineLen = length $outLine;
   print foldF LEFTSPACES ;
   if ($outLineLen <= fstLineDataMax) { printf foldF "$outLine\n"; }
   else {
    $fstFragment = substr $outLine,0,$fstLineDataMax;
    printf foldF "$fstFragment\n";
    $charIdx = $fstLineDataMax;
    while ($outLineLen > $charIdx) {
     $nextFragment = substr $outLine,$charIdx,$subLineDataMax;
     printf foldF LEFTSPACES."$sublineInsert$nextFragment\n";
     $charIdx += $subLineDataMax;
    }
   }
   $outLine = $inpLine;
  }
  $prevName = $currName;
 }
 if ($outLine ne "") { printf foldF LEFTSPACES."$outLine\n"; } # flush the last line
 close(foldF);
 close(inpF);
}

sub swapFLNames { # Swap the first and last names of arg1 file, sort and store it arg2 file
 my ($inpFile, $swapFile) = @_;
 my @inpLines = `cat $inpFile`;
 foreach (@inpLines) {
  chop;
  $posn = index($_, METATAG);
  if ( $posn >= 0 ) {
   $fullName = substr $_, 0, $posn;
   $currData = substr $_, $posn;
   $fullName =~ s/^\s*(.*)\s+(\w+)\s*$/$2, $1 /;
   $_ = $fullName.$currData."\n";
  }
  else { $_ .= "\n"; }
 }
 my @sortedLines = sort @inpLines;
 open(swapF, ">".$swapFile) || die "cannot open output file $swapFile - $!";
 print swapF @sortedLines;
 close(swapF);
}

sub blendFiles {
# It arranges the 1st and 2nd files into a third file as below:
#  1stF-1stPage, 2ndF-LastPage, 1stF-2ndPage, 2ndF-secondLastPage, ...
 my ($fnameFile, $lnameFile, $jnameFile) = @_;
 my @fnLines = `cat $fnameFile`;
 my @lnLines = `cat $lnameFile`;
 my $pageDataLines = PAGEHEIGHT - TOPMARGIN - FOOTMARGIN;
 my $fnPages = ceil(($#fnLines + 1)/$pageDataLines);
 my $lnPages = ceil(($#lnLines + 1)/$pageDataLines);
 my $sheets = $fnpages;
 if ($lnPages > $sheets) { $sheets = $lnPages; }
 open(jnameF, ">".$jnameFile) || die "cannot open output file $jnameFile - $!";
 for ($sheet = 0; $sheet < $sheets; $sheet++) {
  # output one (forward sequenced) page of lines from the fnameFile
  for ($i = 0; $i < TOPMARGIN; $i++) { print jnameF "\n"; }
  $fnStartLine = $sheet * $pageDataLines;
  $fnEndLine = $fnStartLine + $pageDataLines;
  $idx = $fnStartLine;
  while (($idx < $fnEndLine) && ($idx <= $#fnLines)) {
    print jnameF $fnLines[$idx]; 
    $idx++;
  }
  if ($idx > $#fnLines)
    { print jnameF "\f"; }
  for ($i = 0; $i < FOOTMARGIN; $i++) { print jnameF "\n"; }
  # output one (reverse sequenced) page of lines from the lnameFile
  for ($i = 0; $i < TOPMARGIN; $i++) { print jnameF "\n"; }
  $lnStartLine = ($sheets - $sheet - 1) * $pageDataLines;
  $lnEndLine = $lnStartLine + $pageDataLines;
  $idx = $lnStartLine;
  while (($idx < $lnEndLine) && ($idx <= $#lnLines)) {
    print jnameF $lnLines[$idx]; 
    $idx++;
  }
  if ($idx > $#lnLines)
    { print jnameF "\f"; }
  for ($i = 0; $i < FOOTMARGIN; $i++) { print jnameF "\n"; }
 }
 close(jnameF);
}

sub appendFile { # append the arg1 file to arg2 file with the current left margin spaces
 my ($inpFile, $nameFile) = @_;
 my @inpLines = `cat $inpFile`;
 open(nameF, ">>".$nameFile) || die "cannot open output file $nameFile - $!";
 foreach (@inpLines) {
  print nameF LEFTSPACES.$_;
 }
 close(nameF);
}

# main segment begins here
if ($#ARGV != 1) { # in Perl, argcnt is zero for one argument
    die "Usage: $0 name-of-the-databank-file {Home/Office/Car} \n";
}
@wdaystring = ('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
@monstring = ('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct',
		'Nov','Dec');
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
$year += 1900;
$timestamp = $wdaystring[$wday]. ", " . $monstring[$mon] . " " . $mday . ", " . $year;
$databankfile = $ARGV[0];
system("chmod 660 $databankfile");
orderLines($databankfile);
$databank = $databankfile;
$databank =~ s/\..*//;
$databank = ucfirst(lc($databank));
$leftHeader = sprintf("%-20.20s", $databank);
$location = ucfirst(lc($ARGV[1]));
$rightHeader = sprintf("%20.20s", $location);
# Prepare header lines
$fnameFile = "fnamelist";
open(fnameF, ">".$fnameFile) || die "cannot open output file $fnameFile - $!";
printf fnameF LEFTSPACES." "x LINE1SKIP ."$timestamp\n";
printf fnameF LEFTSPACES.$leftHeader." "x LINE2SKIP ."Firstname Listing "." "x LINE2SKIP .$rightHeader."\n";
close(fnameF);
$lnameFile = "lnamelist";
open(lnameF, ">".$lnameFile) || die "cannot open output file $lnameFile - $!";
printf lnameF LEFTSPACES." "x LINE1SKIP ."$timestamp\n";
printf lnameF LEFTSPACES.$leftHeader." "x LINE2SKIP ."Lastname Listing  "." "x LINE2SKIP .$rightHeader."\n";
close(lnameF);
# Prepare the normal listing (sorted by first name)
foldLines($databankfile,fnamelist);
appendFile("directry.hlp",fnamelist);
# Swap the first & last name of each individual in the
#  in the personal information file and then sort the entries.
swapFLNames($databankfile, tmp1);
foldLines(tmp1,lnamelist);
appendFile("directry.hlp",lnamelist);
# Combine both firstname and lastname files in a suitable manner for viewing the print out
blendFiles("fnamelist", "lnamelist", "jnamelist");
system("chmod 600 [fjl]namelist");
system("rm -f tmp1");
exit(0);
