#!/usr/bin/perl
use CGI qw(:standard);
use strict;
##########################################################
#
# event constants
#
my $THIS_PROGRAM_ADDRESS = url();
my $RESULT_INDEX_FILE_HEADER = "resindexhead.html";
my $RESULT_INDEX_FILE_FOOTER = "resindexfoot.html";
my $RESULT_INDEX_FILE = "../resindex.html";
my $RACE_INDEX_FILE="./availableraces.txt";
my $REDBLOCK_GIF="redblock.gif";
my $END_CREDIT_LOGO ="";
my $END_CREDIT_LINK = "www.joelee.co.uk";
my $END_CREDIT_AUTHOR = "";
my $AVAILABLE_BACK_COLOR="#eeddff";
my $FORM_BACK_COLOR=="white";
my $FORM_BORDER_COLOR = "blue";
##########################################################
#
# variables
#
my $NumberOfLinesToPrint = 200;
my @MaleAgeCount = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
my @FemaleAgeCount = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
my @BaseFileContents;
my ($HisPace,$DistanceMiles,$DistanceKm,$HisName,$HisClub,$HisTime,$HisAge,$HisSex,$HisCode,$AgeGroup,$AgeBand);
my ($PosInRace,$PosInSelectedRange,$PosInAgeGroup,$PosInSex,$NumberInBand);
my ($PosInMaleUnder40s,$PosInFemaleUnder35s,$TotalMales,$TotalFemales);
my ($ResPerPage,$FromAge,$ToAge,$FirstResult,$LastResult);
my ($Sex,$PrevButton,$NextButton,$PageNumber);
my ($distance,$units);
my ($Event);
##########################################################
#
# print st or nd or th or rd according to the parameter
#
sub PrintTh
{
my ($ThisNumber)=@_;
my $LastDigit = $ThisNumber % 10 ;
my $Teens = $ThisNumber % 100 ;
if ($Teens == 11 || $Teens == 12 || $Teens == 13)
{
print "th";
}
elsif ($LastDigit == 1)
{
print "st";
}
elsif ($LastDigit == 2)
{
print "nd";
}
elsif ($LastDigit == 3)
{
print "rd";
}
else
{
print "th";
}
}
##########################################################
#
# print page header
#
sub printHeader
{
print "content-type: text/html\n\n";
print <<"ENDHEADER";
Race results selection
ENDHEADER
}
##########################################################
#
# Print the top section before the result table
#
sub PrintTopMessages
{
}
##########################################################
#
# set up the output table
#
sub OutputTableHeader
{
print <<"ENDOFTABLEHEADER";
";
}
}
##########################################################
#
# send the current line to the user
#
sub OutputThisLine
{
# force table cells to contain something....
if (not $HisName)
{
$HisName=" ";
}
if (not $HisClub)
{
$HisClub=" ";
}
if (not $HisTime)
{
$HisTime=" ";
}
if ($HisAge eq 0) # we don't want to print 0 - leave the cell blank instead
{
$HisAge=" ";
}
print "
$PosInSelectedRange" ;
# print race position
print "
$PosInRace" ;
PrintTh($PosInRace);
# print the position in their own 5 year age group
print "
$PosInAgeGroup" ;
PrintTh($PosInAgeGroup);
if ($HisSex eq "M" && $HisAge<40)
{
print " u/40M";
}
elsif ($HisSex ne "M" && $HisAge<35)
{
print " u/35L";
}
else
{
print " ${HisSex}$AgeBand";
}
# print position in that Sex
print "
\n";
}
##########################################################
#
# close the output table
#
sub OutputTableFooter
{
print "
\n";
}
##########################################################
#
# Print the end section after the result table
#
sub PrintEndMessages
{
}
##########################################################
#
# print bottom of page footer
#
sub PrintBottom
{
print <<"ENDFOOTER";
ENDFOOTER
}
##########################################################
#
# use the current line we've read from the result file
#
sub UseThisLineOrNot
{
$AgeGroup = int (($HisAge +0.1) / 5); # which element of the AgeGroup list, add 0.1 to force real division to err on the high side
$AgeBand = $HisAge - ($HisAge % 5); # convert eg 44 to 40 and 61 to 60 (round down to nearest 5 year band
if ($HisSex eq "M")
{
$PosInSex = ++$TotalMales ;
@MaleAgeCount[$AgeGroup] ++;
if ($HisAge<40)
{
$PosInAgeGroup = ++$PosInMaleUnder40s;
}
else
{
$PosInAgeGroup = @MaleAgeCount[$AgeGroup];
}
} else
{
$PosInSex = ++$TotalFemales ;
@FemaleAgeCount[$AgeGroup] ++;
if ($HisAge<35)
{
$PosInAgeGroup = ++$PosInFemaleUnder35s;
}
else
{
$PosInAgeGroup = @FemaleAgeCount[$AgeGroup];
}
}
# now count position in the selected sex and age range
if ($HisAge >= $FromAge && $HisAge <=$ToAge && ($HisSex eq $Sex || $Sex eq "B" ) )
{
$PosInSelectedRange ++ ;
if ($PosInSelectedRange>=$FirstResult && $NumberOfLinesToPrint-- > 0)
{
OutputThisLine();
}
}
}
##########################################################
#
# Read the file and process each line
#
sub PrintResultFile
{
$NumberOfLinesToPrint = $ResPerPage;
my ($FileName) = @_;
my (@ResultFile);
if (not open (RESULT_FILE, "<$FileName"))
{
print "Sorry, the file you requested cannot be found\n";
} else
{
@ResultFile = ; # load in all records
OutputTableHeader();
foreach my $thisline (@ResultFile)
{
($PosInRace,$HisName,$HisSex,$HisAge,$HisClub,$HisTime,$HisCode)=split(/,/ , $thisline); # split out the line
if ($PosInRace==0)
{
$distance=$HisName;
$units=$HisSex;
if ($distance eq "M"){$distance=26.2;}
if ($distance eq "H"){$distance=13.1;}
if ($units eq "M")
{
$DistanceMiles=$distance;
$DistanceKm=$distance * 1.609;
} else
{
$DistanceKm=$distance;
$DistanceMiles=$distance/1.609;
}
# print "Distance=$DistanceMiles miles, $DistanceKm km \n";
} else
{
# lines may not have sex or age embedded in them so set them to default values
if (not $HisSex)
{
$HisSex="M"; # default is always Male unless specifically told it's a Lady
}
if (not ($HisSex eq "M")) # deal with sex=F
{
$HisSex="L";
}
if (not $HisAge)
{
$HisAge=0;
}
UseThisLineOrNot();
}
}
OutputTableFooter();
}
}
##########################################################
#
# Open a file, and print everything in it either to the
# OutFileName, or to STDOUT if no OutFileName.
#
# If $EndPoint exists, stop printing when a line
# is reached.
sub PrintFile
{
my ($EndPoint,$InFileName,$OutFileName)=@_; # load in the parameters
$EndPoint = "\n"; # add in the newline and comments which will be read from the file
if (not open(BASEFILE, "<$InFileName"))
{
print "\nSorry, I cannot find the file $InFileName\n";
@BaseFileContents = ("");
}
else
{
@BaseFileContents = ; # read all the input file
close (BASEFILE);
if ($OutFileName)
{
if (not open(OUTPUTFILE, ">$OutFileName"))
{
print "\nSorry, there is a problem creating the file $OutFileName\n";
print "Contents are listed here...\n";
} else
{
select OUTPUTFILE;
}
}
# print either to the OutFileName or to STDERR
foreach my $ThisLine (@BaseFileContents)
{
$ThisLine =~ s/raceresults.cgi/raceresults.pl/;
print $ThisLine;
last if ($ThisLine eq $EndPoint); # finish when the end marker is reached
}
# close the output and return to STDOUT if we were writing to a file
if ($OutFileName)
{
close(OUTPUTFILE);
select STDOUT; # return to default print mode
}
}
}
##########################################################
#
# print out the available race result calendar by looking
# at the index file which is in the form:
#
# selectable,filelocation,Month,Race Description
#
# print it to the OutFileName if this exists, otherwise print
# it to the STDERR
#
sub PrintAvailableRaces
{
my ($OutFileName) = @_; # load in the parameter if it exists
if ($OutFileName) # we want to append to the file if we are writing to a file
{
if (not open(OUTPUTFILE, ">>$OutFileName"))
{
print "Sorry, there is a problem appending to the file $OutFileName\n";
} else
{
select OUTPUTFILE;
}
}
my $Nraces = 0;
if (not open(AVAILABLE_RACE_FILE, "$RACE_INDEX_FILE") )
{
print "Sorry, there are no available races to search through\n";
}
else
{
print <<"ENDAVAILTABLETOP";
Select the race to view
ENDAVAILTABLETOP
my @AvailableRaces = ; # read all the entries in the index
my $LastMonth="nomonth"; # force the first entry to print the month
my $LastYear="noyear";
foreach my $ThisRace (@AvailableRaces)
{
my ($Selectable, $ThisLocation, $ThisDay, $ThisMonth, $ThisYear, $ThisTitle) = split (/,/ , $ThisRace) ; # extract each field of the current index line
if (($ThisMonth ne $LastMonth)or($ThisYear ne $LastYear)) # start a new table heading
{
print <<"ENDRACEINFO";
$ThisMonth $ThisYear
ENDRACEINFO
$LastMonth = $ThisMonth;
$LastYear = $ThisYear;
}
# print "$ThisDay : ";
if ($Selectable ne "Y") # just print the normal link address to the file
{
print <<"ENDLINKPRINT";
$ThisTitle
ENDLINKPRINT
}
else # run the results cgi program and pass the link address into it as a parameter
{
# the dot before $ThisLocation ensures that we come out of the CGI-LOCAL directory back to the root
# since all locations in the index are relative to the root www.joelee.co.uk/ and the CGI runtime
# program is in www.joelee.co.uk/cgi-local/
print <<"ENDSELECTPRINT";
$ThisTitle
ENDSELECTPRINT
}
}
print "
\n
\n";
}
if ($OutFileName)
{
sele2ct STDOUT;
close(OUTPUTFILE);
}
}
##########################################################
#
# Recreate the results index file from the available races
# by adding the race calendar to the standard index file
#
sub CreateAndSendResultsIndex
{
print "content-type: text/html\n\n";
PrintFile("noend",$RESULT_INDEX_FILE_HEADER, $RESULT_INDEX_FILE); # load the basic index information
PrintAvailableRaces($RESULT_INDEX_FILE); # add in the race calendar
PrintFile("noend",$RESULT_INDEX_FILE_FOOTER, ">".$RESULT_INDEX_FILE); # append the footer (the function already has one > )
PrintFile("noend",$RESULT_INDEX_FILE); # send the new file contents to STDOUT
}
##########################################################
#
# print out the option and select it if the value is the
# the selected value
#
sub PrintSelectedSex
{
my ($ThisSexLetter,$ThisSex,$SelectedSex)=@_;
print "\n";
}
##########################################################
#
# print out the option and select it if the value is the
# the selected value
#
sub PrintSelectedNumber
{
my ($ThisAge,$SelectedAge)=@_;
print "\n";
}
##########################################################
#
# print out the form
#
sub PrintSelectionForm
{
my $ThisAgeBand;
print <<"ENDOPTIONSLIST1";
ENDOPTIONSLIST5
}
##########################################################
#
# print the header to show which results are being displayed
#
sub PrintResultHeader
{
my ($SexHeader, $AgeHeader);
if ($Sex eq "M")
{
$SexHeader="Results for Men";
}
elsif ($Sex eq "B")
{
$SexHeader="All Results";
}
else
{
$SexHeader="Results for Ladies";
}
if ($FromAge == 0 && $ToAge >= 99)
{
$AgeHeader = "- All Ages";
}
elsif ($FromAge >0 && $ToAge >=99)
{
$AgeHeader = "over $FromAge";
}
elsif ($FromAge == 0 && $ToAge < 99)
{
$AgeHeader = "under $ToAge";
}
else
{
$AgeHeader = "age $FromAge to $ToAge";
}
print <<"ENDRESULTHEADER";
$SexHeader $AgeHeader : position $FirstResult to $LastResult
ENDRESULTHEADER
}
##########################################################
#
#
#
sub PrintPageButtons
{
my $NoOfPages=int($PosInSelectedRange/$ResPerPage);
my $i;
if ($PosInSelectedRange%$ResPerPage)
{
$NoOfPages += 1;
}
if ($NoOfPages>1)
{
print <<"ENDOFOPENTABLE";
Select Page Number
ENDOFOPENTABLE
for ($i=1;$i<=$NoOfPages;$i++)
{
print <<"ENDOFPAGEBUTTONS";
ENDOFPAGEBUTTONS
}
print <<"ENDOFCLOSETABLE";
ENDOFCLOSETABLE
}
}
##########################################################
#-
# print the graph of the number of competitors in each
# age group
#
sub PrintAgeGroupGraph
{
my $TotNotVets;
my $TotalInRace;
my $BandIndex;
my $BandWidth;
my ($BandLowAge,$BandHighAge);
my $LastNonZeroBand;
$TotalInRace = $TotalMales + $TotalFemales;
if ($TotalInRace >0)
{
print "
Number finishing in each age group out of the $TotalInRace finishers in the race
\n";
print "
\n";
#************************************************
# draw the graph for the men
#************************************************
$TotNotVets =0;
for ($BandIndex=0; $BandIndex<=7; $BandIndex++)
{
$TotNotVets += $MaleAgeCount[$BandIndex];
}
$BandWidth = int ($TotNotVets / $TotalInRace * 500); # 100% is 500 pixels wide
print "
Men under 40
$TotNotVets
\n";
# find the last band with anyone in it
$LastNonZeroBand = 19;
while ($LastNonZeroBand>8 && $MaleAgeCount[$LastNonZeroBand] == 0)
{
$LastNonZeroBand--;
}
# now do 5year bands from 40 to 95
for ($BandIndex=8; $BandIndex<=$LastNonZeroBand; $BandIndex++)
{
$BandLowAge = ($BandIndex-8)*5 + 40;
$BandHighAge = $BandLowAge + 4;
$NumberInBand = $MaleAgeCount[$BandIndex];
$BandWidth = int ($NumberInBand / $TotalInRace * 500); # 100% is 500 pixels wide
print "
Men $BandLowAge to $BandHighAge";
if ($NumberInBand >0)
{
print "
$NumberInBand
\n";
}
}
#************************************************
# draw the graph for the ladies
#************************************************
$TotNotVets =0;
for ($BandIndex=0; $BandIndex<=6; $BandIndex++)
{
$TotNotVets += $FemaleAgeCount[$BandIndex];
}
$BandWidth = int ($TotNotVets / $TotalInRace * 500); # 100% is 500 pixels wide
print "
Ladies under 35
$TotNotVets
\n";
# find the last band with anyone in it
$LastNonZeroBand = 19;
while ($LastNonZeroBand>7 && $FemaleAgeCount[$LastNonZeroBand] == 0)
{
$LastNonZeroBand--;
}
# now do 5year bands from 35 to 95
for ($BandIndex=7; $BandIndex<=$LastNonZeroBand; $BandIndex++)
{
$BandLowAge = ($BandIndex-7)*5 + 35;
$BandHighAge = $BandLowAge + 4;
$NumberInBand = $FemaleAgeCount[$BandIndex];
$BandWidth = int ($NumberInBand / $TotalInRace * 500); # 100% is 500 pixels wide
print "
Ladies $BandLowAge to $BandHighAge";
if ($NumberInBand >0)
{
print "
$NumberInBand
\n";
}
}
print "
\n";
}
}
##########################################################
#
#
#
sub PrintSelectedEvent
{
$Event= CheckParam("event",35);
#print "event=$Event \n\r";
$FromAge=CheckParam("fromage",2);
if (not $FromAge)
{
$FromAge = 0; # default to all ages
}
$ToAge=CheckParam("toage",2);
if (not $ToAge)
{
$ToAge = 99; # default to all ages
}
$Sex=CheckParam("sex",1);
if (not $Sex)
{
$Sex="B"; #default to both sexes
}
$Sex = substr ($Sex,0,1); # keep the first letter only
$ResPerPage=CheckParam("ResPerPage",3);
if (not $ResPerPage)
{
$ResPerPage=200; # default display 200 results per page
}
$FirstResult=CheckParam("FirstResult",4);
if (not $FirstResult)
{
$FirstResult=1;
}
# $LastResult=param("LastResult");
# if (not $LastResult)
# {
# $LastResult= $FirstResult + ($ResPerPage-1);
# }
# one of these must be there
$PrevButton=CheckParam("prev",4);
$NextButton=CheckParam("next",4);
$PageNumber=CheckParam("pagebutton",3);
if ($PrevButton)
{
$FirstResult -= $ResPerPage;
if ($FirstResult <= 0)
{
$FirstResult = 1;
}
# print "GOT PREV BUTTON : FirstResult=$FirstResult\n";
}
elsif ($NextButton)
{
$FirstResult = $FirstResult + ($ResPerPage);
# print "GOT NEXT BUTTON : FirstResult=$FirstResult\n";
}
else
{
if (not $PageNumber)
{
$PageNumber=1;
}
$FirstResult=(($PageNumber-1) * ($ResPerPage) + 1);
# print "GOT BUTTON : PageNumber=$PageNumber, FirstResult=$FirstResult\n";
}
$LastResult= $FirstResult + ($ResPerPage-1);
# print "lastresult=$LastResult\n";
# print "**********************************\n";
PrintFile("ENDHEADER",$Event); # print the event header file to STDOUT, up to the line
print "\n";
PrintAgeGroupGraph();
PrintBottom();
}
##########################################################
#
# remove invalid chars and truncate as required
#
sub CheckParam
{
my ($field,$maxlen,$sqlquoted)=@_;
my $fieldvalue;
#print "checking $field: ";
if (not param($field)) { return undef;}
$fieldvalue=param($field);
#print "$fieldvalue ";
if (length($fieldvalue) > $maxlen) {$fieldvalue="";}
$fieldvalue =~ s//./g; #remove >
# if ($sqlquoted)
# {
# return $dbh->quote($fieldvalue);
# }
$fieldvalue =~ s/"/./g; #remove "
$fieldvalue =~ s/\|/./g; #remove |
# $fieldvalue =~ s/\'/ /g; #remove '
return $fieldvalue;
}
##########################################################
#
# main program
#
print header();
print "\n";
#print "content-type: text/html\n\n";
$DistanceMiles=0;
$DistanceKm=0;
$units="M";
if (CheckParam("event",35))
{
PrintSelectedEvent();
} else # first time in the program, so print the results index
{
CreateAndSendResultsIndex();
}