#! /usr/bin/perl -w 
# Copyright (C) 2000-2002 Henrik Christian Grove <grove@sslug.dk>
#                      og Frank Damgaard <frank@diku.dk>
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

require POSIX;
use strict;

# Konstante værdier som det kan være interessant at ændre

my $versionsnummer = "0.96";
my $aarstal = 2002;
my $antal_pladser = 6;
my $antal_suppleanter = 2;
my $prioritetsniveauer = 5;  # ofte antal bestyrelsespladser (excl suppleanter)

my $mypath=".";
my $stemmefil="$mypath/stemmer.txt";
my $kandidaterfil="$mypath/kandidater.txt";

# Variabelerklæringer

my $antal_kandidater = 0;
my @kandidat;
#my @stemmer;
my $afgivne_stemmer = 0;
my $fordelingstal = 0;
my @nyt;
my @felt;
my $trouble;

# Indlæs liste med kandidaternes navne fra filen $kandidaterfil
#
# Filformat: Ét navn pr. linie, mellemrum i starten og slutningen af
# linien fjernes
#
sub indl_kandidater {
    open(KAND, $kandidaterfil) or die "Kan ikke åbne $kandidaterfil: $!";
    while (<KAND>){
	chomp;
#	if ( $_  &&  !( $_ =~ /^[\s]+$/ ) ) {
	if (/^\s*(\S.*?)\s*$/) {
	    $antal_kandidater++;
	    $kandidat[$antal_kandidater]{"navn"} = $1; 
	}
    }
    close(KAND);
}

#sub indl_stemmer_1 {
#    my @arr;
#    my $cnt=0;
#    my $lncnt=0;
#    my $snr;
#    my $sprior;
#    my $serror;
#    for ($snr=0; $snr<$antal_kandidater; $snr++) {
#	 for ($sprior=1; $sprior<=$prioritetsniveauer; $sprior++) {
#	     $stemmer[$sprior+$snr*$prioritetsniveauer]=0;
#	 }
#    }
#
#    open(STEM, $stemmefil) or die "Can't open $stemmefil: $!";
#    while (<STEM>){
#	 $lncnt++;
#	 $serror=0;
#	 chomp;
#	 $snr=$_;
#	 $snr =~ s/^.*;\s*// ;
#	 @arr= split(/\s/,$snr) ;
#	 if ($#arr>0) {
#	     for ($cnt=0; $cnt<=$#arr ; $cnt++  ) {
#		 $snr = $arr[$cnt];
#		 $sprior = $snr;
#		 $snr =~ s/:.*//;
#		 $sprior =~ s/^.*://;
#		 if ( $snr > 0 && $snr<=$antal_kandidater
#		      && $sprior>=0  && $sprior<=$prioritetsniveauer ) {
#		     $stemmer[$sprior+($snr-1)*$prioritetsniveauer] += 1;
#		 } else {
#		     $serror++;
#		 }
#	     }
#	     if ($serror>0) {
#		 print "*** $serror fejl i stemmeseddel linie $lncnt :\n";
#		 print "*** [",$_,"]\n";
#	     }
#	 }
#    }
#    close(STEM);
#    for ($snr=0; $snr<$antal_kandidater; $snr++) {
#	 printf "%3d: %-22s",$snr+1,$kandidat[$snr+1]{'navn'};
#	 for ($sprior=1; $sprior<=$prioritetsniveauer; $sprior++) {
#	     printf "%4d",$stemmer[$sprior+$snr*$prioritetsniveauer];
#	 }
#	 print "\n";
#    }
#}

# Indlæs de afgivne stemmer fra filen $stemmefil
#
# Det her må Frank tjekke...
# Filformat: En linie pr. stemmeseddel. 
#   Linieformat (regex): sid[^;]*;\s*(kand:prio\s+)*\s*
#
# Hvor sid er et unikt id-nummer (bruges til at tjekke for dubletter),
# og kand:prio er nummeret på en kandidat og den stemmeprioritet der
# er afgivet på kandidaten.
sub indl_stemmer {
    my @arr;
    my $bak;
    my $sid;
    my %stemmeseddel;
    my %stemmelinie;
    my $linienr = 0;
    my $skand;
    my $sprio;
    my $serror=0;
    my $cnt;

    for ($skand=1; $skand<=$antal_kandidater; $skand++) {
	for ($sprio=1; $sprio<=$prioritetsniveauer; $sprio++) {
	    $kandidat[$skand]{"modtagne_stemmer$sprio"} = 0;
	}
    }
    open(STEM, $stemmefil) or die "Kan ikke åbne $stemmefil: $!";
    while (<STEM>){
	$linienr++;
	chomp;
	$bak=$_;
	s/;.*\s*// ;
	@arr = split /\s/;
	$sid = $arr[0];
	$sid = "$sid";
	$_=$bak;
	s/^.*;\s*// ;
	if ( defined $stemmeseddel{$sid}) {
	    printf "duplet gammel=[%s]\n",$stemmeseddel{$sid};
	    printf "%9s ny=[%s]\n",$sid,$_;
	}
	$stemmeseddel{$sid} = $_;
	$stemmelinie{$sid} = $linienr;
    }
    close(STEM);
    foreach $sid (keys %stemmeseddel) {
	@arr = split(/\s/,$stemmeseddel{$sid}) ;
	if ($#arr>0) {
	    $afgivne_stemmer++;
	    for ($cnt=0; $cnt<=$#arr ; $cnt++  ) {
		$skand = $arr[$cnt];
		$sprio = $skand;
		$skand =~ s/:.*//;
		$sprio =~ s/^.*://;
		if ( $skand > 0 && $skand<=$antal_kandidater
		     && $sprio>=0  && $sprio<=$prioritetsniveauer ) {
#		    $stemmer[$sprio+($skand-1)*$prioritetsniveauer] += 1;
		    $kandidat[$skand]{"modtagne_stemmer$sprio"}++;
		} else {
		    $serror++;
		}
	    }
	    if ($serror>0) {
		print "*** $serror fejl i stemmeseddel linie $stemmelinie{$sid} :\n";
		print "*** [",$_,"]\n";
	    }
	}
    }
}

my @colors;
@colors[1..8] =  (0xf0ff99,0xe0ffc0,0xfff099,0xd0ffa0,
		  0xf0e099,0xe0f099,0xe0d099,0xd0c099);
# Lav HTML-fil med en side af resultatet
#
# Frank har tilføjet nogle baggrundsfarver til tabellen, desværre ikke
# med CSS
sub ud_html {
    my $nummer = shift(@_);
    my $i;
    my $j;
    my $bgcolor;
    my $bgcolortxt;
    my $valgtst;
    my $vprior;

    if ($nummer)
    { open(UDFIL,">res-$nummer.html"); }
    else
    { open(UDFIL,">endeligt-resultat.html"); }
    
    print UDFIL
	"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Strict//EN\">\n",
	"<html>\n",
	"<head>\n",
	"<title>Resultat af SSLUG's bestyrelsesvalg $aarstal";
    if ($nummer)
    { print UDFIL " -- $nummer"; }
    print UDFIL 
	"</title>\n",
	"<style type=\"text/css\">\n",
	"<!--\n",
	"body { background: white; color: black }\n",
	"h1 { font-family: fantasy }\n",
	"p td { font-family: serif }\n",
	"td { color: navy }\n",
	".nyt { color: green }\n",
	".info { font-size: small }\n",
	"-->\n",
	"</style>\n",
	"</head>\n",
	"<body> \n",
	"\n",
	"<h1>Resultat af SSLUG\'s bestyrelsesvalg $aarstal</h1>\n\n",
	"<p>Der er afgivet $afgivne_stemmer stemmer.<br>\n",
	"Fordelingstallet er $fordelingstal.</p>\n",
	"<table border=1>\n",
	"<tr><th>Navn</th><th>Valgt som</th><th>Stemmer</th>";
    for($i=1; $i<=$prioritetsniveauer; $i++) 
    { print UDFIL "<th>$i</th>"; }
    print UDFIL "</tr>\n";

    $bgcolor=0xffffff;
    for($i=1; $i<=$antal_kandidater; $i++){
	print UDFIL "<tr>";
	# valgst & prior should be stored in the counting-part, but...
	# Hvilket de pudsigt nok også er (og hele tiden har været)
	# de findes i henholdsvis $kandidat[$i]{'stemmer'}
	# og $kandidat[$i]{'valgt'}
	$valgtst= $felt[$i][3];
	if ( $valgtst =~ /\d+\.\d+/ ) {
	    $vprior = $valgtst;
	    $vprior =~ s/\.\d+//;
	    $valgtst =~ s/\d+\.//;
	    $bgcolor= $colors[$vprior];
	    #$bgcolor=0xfff088;
	} else {
	    $vprior=0;
	    $valgtst=0;
	}
	for($j=1; $j<= $prioritetsniveauer+3; $j++) { 
	    if ($j<3 || $vprior==0 || $j>$vprior+3 ) {
		$bgcolortxt="";
	    } else {
		$bgcolortxt=sprintf "bgcolor=\"#%06x\"",$bgcolor
	    }
	    if ($nyt[$i][$j]) { 
		print UDFIL "<td class=nyt $bgcolortxt>$felt[$i][$j] "; 
	    } else  { 		
		print UDFIL "<td $bgcolortxt>$felt[$i][$j] "; 
	    }
	    print UDFIL " </td>";
	}
	print UDFIL "</tr>\n";
	if ($i==$antal_pladser) {
	    print UDFIL "<tr>";
	    print UDFIL "<td colspan=\"",($prioritetsniveauer+3),"\">&nbsp;</td>"; 
	    print UDFIL "</tr>\n";
	}
	if ($i==$antal_pladser+$antal_suppleanter) {
	    print UDFIL "<tr>";
	    print UDFIL "<td colspan=\"",($prioritetsniveauer+3),"\">&nbsp;</td>"; 
	    print UDFIL "</tr>\n";
	}
    }

    print UDFIL "</table>\n\n";
    if ($nummer)
    { print UDFIL "<a href=\"res-".($nummer+1).".html\">Næste side</a>"; }
    if ($nummer>5)
    { print UDFIL "\n<a href=\"endeligt-resultat.html\">Endeligt resultat</a>"; }
    print UDFIL 
	"\n",
	"<hr>\n",
	"<p class=info>Genereret af valg.pl, version $versionsnummer<br>\n",
	"Copyright (C) 2000-2002 ",
	"Henrik Christian Grove ",
	"&lt;<a href=\"mailto:grove\@sslug.dk\">grove\@sslug.dk</a>&gt;\n",
	"og Frank Damgaard ",
	"&lt;<a href=\"mailto:frank\@sslug.dk\">frank\@sslug.dk</a>&gt;</p>\n",
	"</body>\n",
	"</html>\n";
    close(UDFIL);
} # ud_html

# Sammenlign to kandidater for at afgøre hvem der bliver valgt først.
sub smlign_kandidater {
    my $r;
    my $i;

#    print("$kandidat[$a]{'navn'} <=> $kandidat[$b]{'navn'}\n");
    if ($kandidat[$a]{'valgt'} < $kandidat[$b]{'valgt'}) 
    { return -1; }
    if ($kandidat[$b]{'valgt'} < $kandidat[$a]{'valgt'})
    { return 1; }
    if ($kandidat[$a]{'stemmer'} > $kandidat[$b]{'stemmer'}) 
    { return -1; } 
    if ($kandidat[$b]{'stemmer'} > $kandidat[$a]{'stemmer'})
    { return 1; }
    $r = 0;
    for ($i=1; ($i<=$prioritetsniveauer) && ($r==0); $i++) {
      if ($kandidat[$a]{"modtagne_stemmer$i"} > $kandidat[$b]{"modtagne_stemmer$i"})
      { $r = -1; }
      if ($kandidat[$b]{"modtagne_stemmer$i"} > $kandidat[$a]{"modtagne_stemmer$i"})
      { $r = 1; }
    }
    if ($kandidat[$a]{'magic'} < $kandidat[$b]{'magic'})
    { $r = -1; }
    if ($kandidat[$b]{'magic'} < $kandidat[$a]{'magic'})
    { $r = 1; }
    if ($r)
    { return $r; }
    print("Lodtrækning påkrævet mellem $kandidat[$a]{'navn'} og $kandidat[$b]{'navn'}\n");
    $trouble = 1;
    return 0;
} # smlign_kandidater

# Lokalisér evt. behov for lodtrækninger og bed om et resultat af hver
# af dem.
sub traeklod {
    my $i;
    my $j;
    my $k;
    my $p;
    my $tjah;

    $i = 0;
    do {
	$tjah = 0;
	do {
	    $i++;
	} until (($i==$antal_kandidater) ||
		 (($kandidat[$i]{'valgt'}==$kandidat[$i+1]{'valgt'}) &&
		  ($kandidat[$i]{'stemmer'}==$kandidat[$i+1]{'stemmer'})));
	unless ($i==$antal_kandidater) {
	    $tjah = 1;
	    $j = $i;
	    do {
		$j++;
		$p = 0;
		do {
		    $p++; 
		} while (($p<=$prioritetsniveauer) &&
			 ($kandidat[$i]{"modtagne_stemmer$p"}
			  ==$kandidat[$j]{"modtagne_stemmer$p"}));
		if ($p<=$prioritetsniveauer) {
		    $tjah = 0;
		} 
	    } while (($tjah) &&
		     ($kandidat[$i]{'valgt'}==$kandidat[$j+1]{'valgt'}) &&
		     ($kandidat[$i]{'stemmer'}==$kandidat[$j+1]{'stemmer'}));
	    if ($tjah) {
		print "Træk lod mellem\n";
		for ($k=$i; $k<=$j; $k++) {
		    print "  $kandidat[$k]{'navn'}\n";
		}
		print "Indtast nu et tal for hver kandidat, lavest for vinderen af lodtrækningen.\n";
		for ($k=$i; $k<=$j; $k++) {
		    print "Indtast for $kandidat[$k]{'navn'}-> ";
		    $kandidat[$k]{'magic'} = <STDIN>;
		}
	    }
	    $i = $j;
	}
    } until ($i==$antal_kandidater);
} # traeklod

# Testdata - 10 kandidater, 5 prioriteter, 31 afgivne stemmer
# Virkelige data skal indlæses  
#$antal_kandidater = 10;
#$kandidat[1]{'navn'} = "Luke Skywalker"; 
#$kandidat[2]{'navn'} = "Prinsesse Leia";
#$kandidat[3]{'navn'} = "Han Solo";
#$kandidat[4]{'navn'} = "Chewbacca";
#$kandidat[5]{'navn'} = "Dronning Amidala";
#$kandidat[6]{'navn'} = "Obi-Wan Kenobi";
#$kandidat[7]{'navn'} = "Yoda";
#$kandidat[8]{'navn'} = "Jar-Jar Binks";
#$kandidat[9]{'navn'} = "C-3PO";
#$kandidat[10]{'navn'} = "R2-D2";
#
#$afgivne_stemmer = 31;
#@stemmer[1..50] = (  1, 3, 3, 5, 5,    #1
#		     1, 6, 7, 4, 5,    #2
#		     0, 1, 2, 2, 4,    #3
#		     1, 0, 0, 0, 3,    #4
#		     3, 2, 2, 5, 2,    #5
#		    20, 5, 2, 1, 0,    #6
#		     1, 0, 3, 1, 2,    #7
#		     1,10, 9, 8, 3,    #8
#		     0, 2, 1, 2, 2,    #9
#		     3, 2, 2, 3, 2);   #10
##                  31 31 31 31 28
# Testdata - slut


##### Her begynder programet #####

my $i;
my $j;
my $niveau;
my @sorteret;
my $side;

&indl_kandidater;
print "$antal_kandidater kandidater indlæst!\n";
&indl_stemmer;
print "$afgivne_stemmer stemmer indlæst!\n";

for ($i=0; $i<$antal_kandidater; $i++) {
# De to næste linier uddeler teststemmerne til kandidaterne
#    for ($j=1; $j<=$prioritetsniveauer; $j++) 
#    { $kandidat[$i+1]{"modtagne_stemmer$j"} = $stemmer[$prioritetsniveauer*$i+$j]; }
    $kandidat[$i+1]{'valgt'} = $prioritetsniveauer+1;
    $kandidat[$i+1]{'stemmer'} = 0;
    $kandidat[$i+1]{'magic'} = 0;
}

$fordelingstal = POSIX::floor($afgivne_stemmer/($antal_pladser+1))+1;
print "Fordelingstallet beregnet til $fordelingstal\n";

# Her opgøres resultatet
for ($niveau=1; $niveau<=$prioritetsniveauer; $niveau++) {
    print STDERR "Opgør niveau $niveau...\n";
    for ($i=1; $i<=$antal_kandidater; $i++) {
	if ($kandidat[$i]{'valgt'} == $prioritetsniveauer+1) 
	{ $kandidat[$i]{'stemmer'} += $kandidat[$i]{"modtagne_stemmer$niveau"};	}
        if (($kandidat[$i]{'stemmer'} >= $fordelingstal) 
	    && ($kandidat[$i]{'valgt'} == $prioritetsniveauer+1)) 
	{ $kandidat[$i]{'valgt'} = $niveau; }
    }
}
print("---------------------------------\n");

for ($i=1; $i<=$antal_kandidater; $i++) 
{ printf("$kandidat[$i]{'navn'} $kandidat[$i]{'valgt'}.$kandidat[$i]{'stemmer'}\n"); }

print("---------------------------------\n");
print "Sorterer kandidaterne...\n";
$trouble = 0;

# Det her er lidt sjovt!
# Vi lader som om vi bare vil sortere tallene fra 1 til $antal_kandidater,
# men sammenligningsfunktionen sammenligner rent faktisk kandidaterne med de
# det tilsvarende numre, så @sorteret kommer ikke til at se sorteret ud.
@sorteret = sort smlign_kandidater ( 1..$antal_kandidater );
@kandidat[1..$antal_kandidater] = @kandidat[@sorteret];

if ($trouble) {
    &traeklod;
    # Tabellen er næsten sorteret, så måske kunne det være en fordel at
    # sortere @sorteret - kræver viden om Perls sort-funktion at afgøre
    print("---------------------------------\n");
    print "Sorterer kandidaterne...\n";
    @sorteret = sort smlign_kandidater ( 1..$antal_kandidater );
    @kandidat[1..$antal_kandidater] = @kandidat[@sorteret];
}
    
print("---------------------------------\n");
for ($i=1; $i<=$antal_kandidater; $i++) 
{ printf("$kandidat[$i]{'navn'} $kandidat[$i]{'valgt'}.$kandidat[$i]{'stemmer'}\n"); }

# Initialiser uddata-skemaet
for ($i=1; $i<=$antal_kandidater; $i++) {
    $felt[$i][1] = "&nbsp;";
    $felt[$i][2] = "&nbsp;";
    $felt[$i][3] = 0;
    for ($j=4; $j<=$prioritetsniveauer+3; $j++)
    { $felt[$i][$j] = "&nbsp;"; }
}

$side = 1;

&ud_html($side++);

for ($niveau=1; $niveau<=$prioritetsniveauer; $niveau++) {
    for ($i=1; $i<=$antal_kandidater; $i++) {
	for ($j=1; $j<=$prioritetsniveauer+3; $j++)
	{ $nyt[$i][$j] = 0; }
    }
    for ($i=1; $i<=$antal_kandidater; $i++) {
	$felt[$i][3+$niveau] = $kandidat[$i]{"modtagne_stemmer$niveau"};
	if ($kandidat[$i]{'valgt'} >= $niveau)
	{ $nyt[$i][3+$niveau] = 1; }
	if ($kandidat[$i]{'valgt'}>=$niveau) { 
	    $felt[$i][3] += $kandidat[$i]{"modtagne_stemmer$niveau"}; 
	}
    }

    &ud_html($side++);

    for ($i=1; $i<=$antal_kandidater; $i++) {
	if ($kandidat[$i]{'valgt'} == $niveau) {
	    $felt[$i][1] = $kandidat[$i]{'navn'};
	    if ($i<=$antal_pladser) {
		$felt[$i][2] = "Bestyrelsesmedlem"; 
	    } elsif ($i<=$antal_pladser+$antal_suppleanter) {
		$felt[$i][2] = "Suppleant"; 
	    } else {
		$felt[$i][2] = "Ikke valgt";
	    }
	    $felt[$i][3] = "$niveau.$kandidat[$i]{'stemmer'}";
	    $nyt[$i][1] = 1;
	    $nyt[$i][2] = 1;
	    $nyt[$i][3] = 1;
	    for ($j=$niveau+1; $j<=$prioritetsniveauer; $j++) { 
		$felt[$i][$j+3] = $kandidat[$i]{"modtagne_stemmer$j"}; 
		$nyt[$i][$j+3] = 1;
	    }
	}
    }
    &ud_html($side++);
}

for ($i=1; $i<=$antal_kandidater; $i++) {
    for ($j=1; $j<=$prioritetsniveauer+2; $j++)
    { $nyt[$i][$j] = 0; }
    $felt[$i][1] = $kandidat[$i]{'navn'};
    if ($felt[$i][2] eq "&nbsp;") {
	$felt[$i][2] = "Ikke valgt";
    }
}
&ud_html(0);

# Få næstsidste side til at pege på det endelige resultat
$side--;
system("mv res-$side.html res-$side.html~");
system("sed -e \'s/^.*res-".($side+1).".*\$//\' < res-$side.html~ > res-$side.html");
system("rm res-$side.html~");
