#!/local/bin/perl
# 
#  $Source: /afs/athena.mit.edu/user/t/o/tompalka/perl/RCS/make-timecard.pl,v $
#  $Revision: 2.28 $
#  $Date: 92/05/09 17:43:26 $
#  $State: Exp $
#  $Author: tompalka $
#  $Locker: tompalka $
# 

($mypath,$WHOAMI) = ( $0 =~ /^([^ ]*)\/([^\/]*)$/ );

$homedir      = $ENV{"HOME"};
$rcfile       = $homedir . "/.timecardrc";

# this is kludgy -- why parse the options twice?  but it is simple.
# 1. we have to find what rcfile to use before we parse it
# 2. we want the command line args to override the rcfile defaults
    
&parse_opts;
&open_rcfile;
&parse_opts;

if(! $nooutput) { 
    &output_prologue($OUTFILENAME); 
}

&count_entries;

if( $manual && ! $quick )
{
    print "please enter: \n";
    $lastday   = &prompt_user("the \"last day of the week\" date: ");
    $timesheet = &prompt_user("the timesheet number: ");
} else {
    print "following dates are generated automatically:\n";
    print "please use the \"-manual\" flag if you don't like them.\n";
    ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
    $mon++;			# correct for jan=0
    $lastday = &get_lastday;
    print "the \"last day of the week\" date: $lastday\n";
    $timesheet = &get_timesheet;
    print "the timesheet number: $timesheet\n";
}


open(timecard,$TIMECARDFILE) || die "cannot open $TIMECARDFILE: $!\n";

if(! $nooutput) {
    open(OUTFILE,">>$OUTFILENAME") || die "cannot open output file: $!\n";
}

&create_arrays;
&mainloop;

if(! $nooutput) {
    &print_week;
    close(OUTFILE);
    print "\n\nthe output is in $OUTFILENAME";
}

close(timecard);

print "\nyou have worked a total of ",$GRANDTOTAL," hours this week.\n";

if( $pay != 0 ) {
    $pay *= $GRANDTOTAL;
    $paytax = $pay * .82;

    printf "that amounts to \$%6.2lf, or about \$%6.2lf after taxes.\n\n",
    $pay, $paytax;
}

exit;


#
# this is so i know how used this program really is
#

sub log_usage
{
    local($logfile) = "/afs/athena/user/t/tompalka/public/make-t-usage";
    open(LOGFP,">>$logfile") || die "cannot open log file: $!\n";
    print LOGFP $ENV{"USER"}, " ", $lastday,"\n";
    close(LOGFP);
}


sub create_arrays
{
    # initialize the days-of-the-week array
    @weekdays = ( 'mon','tue','wed','thu','fri','sat','sun' );

    # construct an associative array from the one above

    $index = 0; 
    foreach (@weekdays) { $daynumber{$_} = $index++; }
    $index = 0;
}


# mainloop parses the file and feeds the valid data lines to parse_line.
# a valid data line is in the first section of the file (if $USEFIRST is true),
# or in the last section, where the current hours are kept.

sub mainloop
{
    while(<timecard>) {
	if( $USEFIRST ) {
	    if( /----/ ) {
		$USEFIRST = 0;
		$counter--;
		next;
	    }
	    next if /^$/;
	    chop;
	    &parse_line($_);
	}

	if( $counter > 0 ) { $counter-- if /----/; next; }

	next if /^$/;
	chop; 
	&parse_line($_);
    }
}


#
# parse_line routine parses the line of the current hour entry.
#

sub parse_line
{
    local($_)=@_;

    s/\s+/ /g;
    
    if( ! /^ / ) {
	($day,$numday,$month,$start,$end,$total,$desc) = split(' ',$_,7);
    } else 	{
	($start,$end,$total,$desc) = split(' ',$_,4);
    }

    $day =~ tr/A-Z/a-z/;
    
    # check if hour is extra--i.e. it is if does not begin with word "olc"
    # or "mcr" in the description field
    # if description begins with "nontaken", then it's a non-taken hour
    
    if($desc =~ /^olc|mcr/) {
	$extra = " ";
	$week[$daynumber{$day}] += $total;
	$GRANDTOTAL += $total;
    } elsif ( $desc =~ /^nontaken/ ) {
	$extra = "nontaken";
	$desc =~ s/^nontaken\ //;
	push(@nontaken,
	     "($day) ($start) ($end) ($total) ($desc) xh-enter-non-taken\n");
    } else {
	$week[$daynumber{$day}] += $total;
	$GRANDTOTAL += $total;
	$extra = "extra";
	push(@extra,
	     "($day) ($start) ($end) ($total) ($desc) xh-enter-time\n");
    }
    if($verbose) { write; }
}


sub print_week 
{
    foreach $i ( 0..6 ) {
	if( $week[$i] != 0 ) {
	    printf OUTFILE "(%5.2lf) t-enter-time \t%% %s\n", $week[$i], $weekdays[$i];
	} else {
	    printf OUTFILE "() t-enter-time \t%% %s\n", $weekdays[$i];
	}
    }

    # round $GRANDTOTAL to two decimals.
    $GRANDTOTAL = sprintf("%5.2f",$GRANDTOTAL);

    print OUTFILE "($GRANDTOTAL) t-enter-grandtotal\n";
    print OUTFILE "($lastday) ($timesheet) t-put-weekend\n";
    print OUTFILE "($signature) t-name\n\n";
    print OUTFILE "($idnumber) t-id\n";
    print OUTFILE "\nxh-enter-time-setup\n";
    print OUTFILE @extra;
    print OUTFILE "\nxh-enter-non-taken-setup\n";
    print OUTFILE @nontaken;
    print OUTFILE "\n($lastday) end-of-week\n";
    print OUTFILE "($signature) name\n\n";
    print OUTFILE "showpage\n";
}


sub open_rcfile
{
    if ( -e $rcfile ) {
	open(RCFILE,$rcfile) || die "cannot open $rcfile: $!\n";
	while(<RCFILE>) {
	    chop;

	    if(! /[^ ]*:/ ) {
		close(RCFILE);
		system("rm -f",$rcfile);
		print "your $rcfile is in wrong format!  please fix it..\n\n";
		&create_rcfile;
	    }
	    s/\s+/ /g;
	    ($field,$contents) = ( $_ =~ /([^ ]*): (.*)$/ );
	    $userinfo{$field} = $contents;
	}

	close(RCFILE);

	$signature    = $userinfo{signature};
	$idnumber     = $userinfo{idnumber};
	$OUTFILENAME  = $userinfo{outfile};
	$TIMECARDFILE = $userinfo{datafile};
	$pay          = $userinfo{pay};

	if( $userinfo{usefirst} =~ /true/i ) {
	    $USEFIRST = 1;
	}

	if( $userinfo{verbose} =~ /true/i ) {
	    $verbose = 1;
	}
    }
    else {
	print "you don't have a $rcfile file!.  creating one..\n\n";
	&create_rcfile;
    }
}

sub create_rcfile
{
    print "please enter:\n";

    $signature    = &prompt_user("your name and username: ");
    $idnumber     = &prompt_user("your mit id number: ");

    $TIMECARDFILE = &prompt_user("path for the data file: ");
    $TIMECARDFILE =~ s/~/$homedir/g;

    $OUTFILENAME  = &prompt_user("path for the output PostScript file: ");
    $OUTFILENAME  =~ s/~/$homedir/g;

    $pay          = &prompt_user("your hourly pay [optional]: ");

    open(RCFILE,">$rcfile") || die "cannot open .timecardrc file: $!\n";
	
    print RCFILE "signature: " ,$signature,"\n";
    print RCFILE "idnumber: "  ,$idnumber,"\n";
    print RCFILE "outfile: "   ,$OUTFILENAME,"\n";
    print RCFILE "datafile: "  ,$TIMECARDFILE,"\n";
    print RCFILE "pay: "       ,$pay,"\n";
    
    close(RCFILE);
    print "file created.\n\n";
}

sub prompt_user
{
    local($question) = @_;
    $answer = "";
    while( $answer =~ /^$/ ) {
	print $question;
	$answer = <STDIN>;
    }

    chop($answer);
    return($answer);
}

sub count_entries
{
    $counter = 0;

    open(timecard,$TIMECARDFILE) || die "cannot open $TIMECARDFILE: $!\n";
    while(<timecard>) 
    { $counter++ if /----/; }
    close(timecard);
}


sub parse_opts
{
    for( $i=0 ; $i<@ARGV ; $i++)
    {
	if( $ARGV[$i] =~ "-in" ) {
	    $TIMECARDFILE = $ARGV[++$i];
	    next;
	} elsif( $ARGV[$i] =~ "-out" ) {
	    $OUTFILENAME = $ARGV[++$i];
	    next;
	} elsif( $ARGV[$i] =~ /-v/ ) {
	    $verbose = 1;
	    next;
	} elsif( $ARGV[$i] =~ /-n/ ) {
	    $nooutput = 1;
	    print "this is what we WOULD do.\n\n";
	    next;
	} elsif( $ARGV[$i] =~ /-q/ ) {
	    $quick = 1;
	    $verbose = 1;
	    $nooutput = 1;
	    next;
	} elsif( $ARGV[$i] =~ /-h/ ) {
	    &usage_and_die;
	} elsif( $ARGV[$i] =~ /-p/ ) {
	    $pay = $ARGV[++$i];
	    next;
	} elsif( $ARGV[$i] =~ /-m/ ) {
	    $manual = 1;
	    next;
	} elsif( $ARGV[$i] =~ /-last/ ) {
	    $LASTOPT = 1;
	    print "\nnote that the -last option does not work well\n";
	    print "across months.  if the last day of last week was in the\n";
	    print "previous month, you'll probably need to use the -manual\n";
	    print "flag instead.\n\n";
	    next;
	} elsif( $ARGV[$i] =~ /-rc/ ) {
	    $rcfile = $ARGV[++$i];
	    next;
	} elsif( $ARGV[$i] =~ /-use/ ) {
	    $USEFIRST = 1;
	    next;
	} else {
	    print "\nunknown option: \"$ARGV[$i]\".\n";
	    &usage_and_die;
	}
    }
}

sub usage_and_die
{
    die <<EOU;

usage:

    $WHOAMI [-in timecard-file] [-out output-file] [-help] 
            [-verbose] [-no] [-pay number] [-quick] 
	    [-manual] [-rc rc-filename] [-last] [-usefirst]

       -in -- name of file containing timecard data
      -out -- name of file to contain output PostScript code
      -pay -- your hourly pay.  if you specify this number, you'll
	      know more or less how much you earned.
       -rc -- name of the rcfile [default: ~/.timecardrc]

  -verbose -- display the hours worked this week
       -no -- process data file but do not produce PostScript output
    -quick -- quickly process data, display hours worked, but don't
	      produce any output files
   -manual -- enter the last-day-of-week and timesheet no. manually.
     -last -- turn in the timecard for the previous week.
 -usefirst -- use the first segment of the data file as hour that are
	      scheduled hours by default.

     -help -- display this info

EOU
}


sub output_prologue
{
    local($filename) = @_;

    open(out,">$filename") || die "cannot open file $filename for output: $!\n";

    print out <<EOP;
%!
%
% thomas m. palka
%
% PostScript template to produce the extra hours form
% and the timecard for i/s consultants.  
%
% produced by make-timecard version:
% $Header: /afs/athena.mit.edu/user/t/o/tompalka/perl/RCS/make-timecard.pl,v 2.28 92/05/09 17:43:26 tompalka Exp Locker: tompalka $

/myinit	{ 0 setgray } def
/inch 	{ 72 mul } def
/sfont	{ findfont exch scalefont setfont } def
/xmoveto { currentpoint	exch pop moveto	} def
/sinch	{ 1 16 div 72 mul mul } def
/name	{
	gsave
	13 /Helvetica-Bold sfont
	1.6 inch 9.8 inch moveto
	show
	grestore
	} bind def
/header	{
	15 /Helvetica-Bold sfont
	2.75 inch 10.25 inch moveto (Consulting Extra Hours Form)  show
	10 /Helvetica-Bold sfont
	72 9.8 inch moveto (Name:) show
	10 /Helvetica-Bold sfont
	5 inch xmoveto (Week ending: ) show
	36 9.5 inch moveto (Extra hours worked. Please make sure you include these on your timecard.) show
	36 9.1 inch moveto (Day) show
	87 xmoveto (Start time) show
	148 xmoveto (End time) show
	209 xmoveto (Total) show
	271 xmoveto (Description) show
	523 xmoveto (Approved) show
	} bind def
/non-taken-header {
	10 /Helvetica-Bold sfont
	36 5.5 inch moveto (Please list any of your scheduled hours which you did not take.) show
	36 5.3 inch moveto (Day) show
	87 xmoveto (Start time) show
	148 xmoveto (End time) show
	209 xmoveto (Total) show
	271 xmoveto (Taken By:) show
	} bind def
/non-taken-line-entry {
	.3 inch mul 5.0 inch sub neg
	10 /Helvetica sfont
	.5 inch exch moveto (_______) show
	87 xmoveto  (_________) show
	148 xmoveto (_________) show
	209 xmoveto (_________) show
	271 xmoveto (___________________________________________) show
	} def

/end-of-week {
	gsave
	6 inch 9.8 inch moveto
	13 /Helvetica-Bold sfont
	show
	grestore
	} def
/line-entry {
	.3 inch mul 8.75 inch sub neg
	10 /Helvetica sfont
	.5 inch exch moveto (_______) show
	87 xmoveto  (_________) show
	148 xmoveto (_________) show
	209 xmoveto (_________) show
	271 xmoveto (___________________________________________) show
	523 xmoveto (_________) show
	} def
/x-hours-form
	{
	myinit
	header
	0 1 10 { line-entry } for
	non-taken-header
	0 1 4 { non-taken-line-entry } for
	} def
/box	{
	gsave
	exch dup 0 rlineto
	exch 0 exch rlineto
	neg 0 rlineto
	closepath
	stroke
	grestore
	} def
/timecard-setup
	{
	90 rotate
	.25 inch -8.25 inch translate
	0 0 moveto
	.1 setlinewidth
	} def
/t-frame {
	3.25 inch 8 inch box
	} def
/hour-box {
	gsave
	14 sinch 5 sinch box
	8 sinch 0 rmoveto
	0 5 sinch rlineto
	2 sinch 0 rmoveto
	0 -5 sinch rlineto
	2 sinch 0 rmoveto
	0 5 sinch rlineto
	2 sinch -5 sinch rmoveto
	stroke
	grestore
	} def
/3-hour-boxes {
	gsave
	hour-box 1 inch 0 rmoveto
	hour-box 1 inch 0 rmoveto
	hour-box
	grestore
	} def
/t-draw-boxes {
	gsave
	.2 inch 6.3 inch moveto
	[ (MON) (TUE) (WED) (THU) (FRI) (SAT) (SUN) ]
	{ 
		gsave
		gsave
		90 rotate
		1 3 rmoveto
		show 
		grestore		
		3-hour-boxes
		grestore
		0 -6 sinch rmoveto 
		} forall
	grestore
	} def
/t-put-inout {
	.2 inch 2.9 inch moveto
	gsave
	1 1 7 {
		gsave 0 -31 sinch rlineto stroke grestore
		34 0 rmoveto
	      } for
	grestore
	gsave	
	0 1 9 {
		gsave 204 0 rlineto stroke grestore
		0 -15.5 rmoveto
	      } for
	grestore
	12 /Helvetica sfont
	0 -13 rmoveto
	1 1 3 {
		gsave
		14 0 rmoveto (IN) show
		grestore gsave
		40 0 rmoveto (OUT) show
		grestore
		68 0 rmoveto
	      } for
	} def
/t-name {
	gsave
	.2 inch 7.75 inch moveto
	12 /Helvetica-Bold sfont
	show 
	grestore
	} bind def
/t-id 	{
	gsave
	.5 inch 7.35 inch moveto
	9 /Helvetica sfont
	show
	grestore
	} bind def
/t-put-label {
	.2 inch 7.7 inch moveto
	gsave 3 inch 0 rlineto stroke grestore
	9 /Helvetica sfont
	gsave 0 -10 rmoveto
	(Employee Name) show grestore
	gsave 0 -25 rmoveto 
	gsave (ID#) show grestore
	1.4 inch 0 rmoveto (Dept: 242400   Coll.pt: 302) show
	grestore
	} def
/t-put-weekend {
	gsave
	9 /Helvetica-Bold sfont
	.2 inch 7 inch moveto
	(Time sheet No. ) show show
	1.6 inch xmoveto
	(Week Ending: ) show
	show
	grestore
	} def
/t-put-supervisor {
	.2 inch 3.3 inch moveto
	gsave 3 inch 0 rlineto stroke grestore
	0 -10 rmoveto
	9 /Helvetica sfont
	(SUPERVISOR'S SIGNATURE) show
	} def
/t-enter-time-setup
	{
	.3 inch 6.4 inch moveto
	} def
/t-enter-time
	{
	gsave
	show
	grestore
	0 -6 sinch rmoveto
	} def
/t-enter-grandtotal
	{
	gsave
	.2 inch 3.8 inch moveto
	12 /Helvetica sfont
 	(Total hours worked: ) show 
	12 /Helvetica-Bold sfont
	show
	grestore
	} def
/xh-enter-time-setup
	{
	grestore
	.7 inch 8.8 inch moveto
	12 /Helvetica sfont
	} def
/xh-enter-time
        {
	gsave
        271 xmoveto show
        209 xmoveto show
        148 xmoveto show
        87 xmoveto show
	36 xmoveto show
	grestore
	0 -.3 inch rmoveto
        } def
/xh-enter-non-taken-setup
	{
	gsave
	.7 inch 5.05 inch moveto
	12 /Helvetica sfont
	} def
/xh-enter-non-taken
        {
	gsave
        271 xmoveto show
        209 xmoveto show
        148 xmoveto show
        87 xmoveto show
	36 xmoveto show
	grestore
	0 -.3 inch rmoveto
        } def
/timecard-form
	{
	timecard-setup
	t-frame
	t-draw-boxes
	t-put-label	
	t-put-supervisor
	t-put-inout
	} def
/Recycle {
        gsave 10 setlinewidth
        currentpoint translate
        1 1 3 { pop newpath
                0 -300 moveto 100 -120 lineto 100 -180 lineto
                500 -180 600 0 80 arcto pop pop pop pop
                360 -420 100 -420 80 arcto pop pop pop pop
                100 -420 lineto 100 -480 lineto closepath stroke
                -300 -180 moveto -50 -180 lineto -50 -420 lineto
                -360 -420 -430 -300 80 arcto pop pop pop pop
                stroke 120 rotate
        } for
        grestore
} def

%% 
%% end of defs
%% 

gsave
7.3 inch 10. inch  moveto 
.05 .05 scale 
Recycle
grestore
7 inch 9.6 inch moveto
8 /Times-Roman sfont
(please recycle) show

x-hours-form
gsave

timecard-form

%%
%% enter first the normal hours, in format
%% (number) t-enter-time
%% for each day of the week!
%%
%% then, time for the end of week label.  put
%% (end-of-week) (time sheet no) t-put-weekend
%%
%% then, put a "grestore", so that we get back to the 
%% extra-hours form environment again.
%% (day-name)(start)(end)(total)(desc)xh-enter-time
%%
%% then put:
%% (yourname) name
%%

t-enter-time-setup

EOP

close(out);
}



format top=

      hours   date           from   to     description
      ------  ------------   ----   --     -----------

.

format STDOUT=
@<<<< @##.##  @<<< @<< @<<<  @<<<<  @<<<<  @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$extra,$total,$day,$numday,$month,$start,$end,$desc
.


sub get_lastday 
{
    local($i,$day,$lastdayofweek);
    local($ourday,$ourmonth,$ouryear);
    # are we in the right century?
    $ouryear = $year;
    if( $ouryear < 1900 ) { $ouryear += 1900; }
    $ourmonth = $mon;
    if( $ourmonth > 12 ) {
	$ourmonth = 1;
	$ouryear++;
    }
    if( mday < 10 ) {
	$ourday = " ".$mday;
    } else {
	$ourday = $mday;
    }
    push(@cal,`cal $ourmonth $ouryear`);
    $ourmonth++;
    if( $ourmonth > 12 ) {
	$ourmonth = 1;
	$ouryear++;
    }
    push(@cal,`cal $ourmonth $ouryear`);
    for( $i=0 ; $i<$#cal ;$i++ ) {
	$_ = $cal[$i];
	next if /^$/;
	next if /[a-zA-Z]/;
	# is today the last day?  then return it!
	if( /^$ourday/ ) {
	    if( $LASTOPT ) {
		# find the last day of the previous week
		($day) = ( $cal[--$i] =~ /^(..).*/);
	    } else {
		$day = $ourday;
	    }
	    $lastdayofweek = sprintf("%02d/%02d/%02d",$year,$mon,$day);
	    return($lastdayofweek);
	} elsif ( /$ourday/ ) {
	    if( $LASTOPT ) {
		# find the last day of the previous week
		($day) = ( $cal[$i] =~ /^(..).*/);
		$lastdayofweek = sprintf("%02d/%02d/%02d",$year,$mon,$ourday);
		return($lastdayofweek);
	    }
	    ($day) = ( $cal[++$i] =~ /^(..).*/);
	    while ($day ==  0 ) {
		($day) = ( $cal[++$i] =~ /^(..).*/);
	    }
	    if( $day < $ourday ) { $mon++; }
	    if( $mon > 12 ) { $mon = 1; }
	    $lastdayofweek = sprintf("%02d/%02d/%02d",$year,$mon,$day);
	    return($lastdayofweek);
	    last;    
	}
    }
}


sub get_timesheet
{
    local($timesheetno) = $year.(int($yday/7)+1);
    $timesheetno =~ s/\ //g;
    if( $LASTOPT ) { 
	$timesheetno--;
    }
    return($timesheetno);
}


#
#( 1.00) t-enter-time 	% mon
#( 2.75) t-enter-time 	% tue
#( 3.00) t-enter-time 	% wed
#( 3.50) t-enter-time 	% thu
#( 3.50) t-enter-time 	% fri
#( 1.50) t-enter-time 	% sat
#() t-enter-time 	% sun
#(15.25) t-enter-grandtotal
#(92/04/19) (9216) t-put-weekend
#(tom palka (tompalka)) t-name
#
#(888-00-2574) t-id
#xh-enter-time-setup
#
#(wed) (1800) (1900) (1.0) (discuss and olc stock) xh-enter-time
#(thu) (1800) (1900) (1.0) (klook, ostock-related stuff) xh-enter-time
#(sat) (1545) (1615) (0.5) (extra qm on soravi and troff) xh-enter-time
#(sat) (1615) (1715) (1.0) (discuss q&a, stock answers) xh-enter-time
#
#xh-enter-non-taken-setup
#(wed) (1200) (1300) (1.0) (tony took it) xh-enter-non-taken
#
#(92/04/19) end-of-week
#(tom palka (tompalka)) name
#
#showpage
#
