#!perl -w

# ** calcpay.pl
# ** program for calculating the situation of the CSC444h payments

# Copyright (C) Cosmin Truta, 2000-2002. No warranty.
# This program may be freely used for any purpose, even outside of CSC444h,
# provided that the purpose does not cause any harm.
# The author may not be charged for not applying good software engineering
# principles.

# bonus style points: global variables
%balances = ();
%expenses = ();
%revenues = ();
%contracts       = ();
$nr_contracts    = 0;
$nr_additional   = 0;
$initial_balance = 300;
$previous_date   = "";		# no previous date, as you can see

if (@ARGV == 0)
{
  die "Usage:\n".
    "  calcccontr.pl <payments-file>\t(with 'execute' permission on Unix)\n".
    "  perl calccontr.pl <payments-file>\t(on any OS)\n".
    "See the manual file \"calccontr.txt\" for details.\n";
}

# process each line in the input file
while ($line = <>)
{
  chomp $line;			# trim line endings
  $line =~ s/#.*$//;		# remove '#' comments
  $line =~ s/^\s*//;		# trim leading spaces
  $line =~ s/\s*$//;		# trim trailing spaces
  next if ($line eq "");	# skip blank lines

  $additional = ($line =~ s/^\*\s*//) ? 1 : 0;	# additional payment?

  # parse the line (no kidding)
  $line =~ /^(\w+[-.\/\s]*\w+)\s+(\S+)\s+to\s+(\S+)\s+\$([\d.]+)$/
    || die "Syntax error in line:\n$line\n";
  $date   = lc $1;
  $team1  = $2;
  $team2  = $3;
  $amount = $4;

  $date =~ s:[-./\s]+:-:;	# normalize the date
  if ($date ne $previous_date)
  {
#   This year we do not check for negative balances
#   check_bank_accounts();	# do this only when ending/starting a day
    $previous_date = $date;
  }

  check_new_team($team1);
  check_new_team($team2);
  check_new_payment($team1, $team2);

  if ($amount =~ /\.\d\d\d/)
  {
    $old_amount = $amount;
    $amount =~ s/(\.\d\d).*$/$1/;
    print "Warning: amount \$$old_amount truncated to \$$amount\n";
  }
  $expenses{$team1} += $amount; $balances{$team1} -= $amount;
  $revenues{$team2} += $amount; $balances{$team2} += $amount;
}

#This year we do not check for negative balances
#check_bank_accounts();		# do this again, because real banks do it

print $nr_contracts, " contract payment(s) and ", $nr_additional,
  " additional payment(s) processed.\n\n";

foreach $team (keys %balances)
{
  printf "%-24sexpenses: %7.2f  revenues: %7.2f  profit: %7.2f\n",
    $team,
    $expenses{$team},
    $revenues{$team},
    $revenues{$team} - $expenses{$team};
}

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

# this function name should be self-explanatory
sub check_new_team
{
  my $new_team = shift;
  if (!defined $balances{$new_team})
  {
    # add a new balance
    $balances{$new_team} = $initial_balance;
    $revenues{$new_team} = $expenses{$new_team} = 0;
  }
}

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

# this function name should also be self-explanatory
sub check_bank_accounts
{
  # check for negative balances
  foreach $team (keys %balances)
  {
    if ($balances{$team} < 0)
    {
      print "Warning: negative balance on ", $previous_date, ": ",
        $team, " had -\$", (sprintf "%-7.2f", -$balances{$team}), "\n";
    }
  }
}

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

# ok, this is not self-explanatory
# check to see whether a contract payment has not been entered twice
sub check_new_payment
{
  if ($additional)
  {
    $nr_additional++;
    return;			# don't record the payment if it is additional
  }

  my $team1 = shift;
  my $team2 = shift;
  $payment = $team1." to ".$team2;
  if (defined $contracts{$payment})
  {
    print "Warning: this contract payment was recorded twice and is ignored:",
      "\n", $payment, "\n";
  }
  $contracts{$payment} = 1;
  $nr_contracts++;
}
