#!@PERL@

use strict;
use warnings;

use lib '@CGIBINDIR@';
use civs_common;
use CGI qw(:standard -utf8);
$CGI::POST_MAX = @MAX_UPLOAD_SIZE@;
# $CGI::UNLINK_TMP_FILES = 0;

# use Digest::MD5 qw(md5_hex);
use DB_File;
use mail;
use Socket;
use IO::Handle;

my $thisurl = $civs_bin_path."/upload_ballots@PERLEXT@";

my $control_key = param('key');
my $authorization_key = param('akey');

HTML_Header('Load Ballots');

use election 1.02;

CIVS_Header("Load ballots");

CheckElectionID;
CheckControlKey($control_key);
CheckAuthorizationKeyForAddingVoter($authorization_key);

if ($external_ballots ne 'yes') {
    print p("Error: this election does not allow external ballots to be uploaded");
    exit 0;
}

my $ballot_fh = upload('ballot_data');

my $lineno = 0;
my @errors = ();
my $max_errors = 10;
my $num_ballots = 0;
my @ballots;
my $type;

if (VerifyUpload($ballot_fh, \@errors, "test ballot file")) {
  while (!$ballot_fh->handle->eof) {
    if ($#errors >= $max_errors) { next }
    $_ = $ballot_fh->handle->getline;
    $lineno++;
    # print pre("Line $lineno: $_"), $cr;
    s/\A(\s)*//;
    s/(\s)*\Z//;
    if (m/^#/) { next } # skip comments
    if ($_ eq '') { next } # skip blank lines
    my $multiplier = 1;
    if (m/^.*(x|X)/) {
	($multiplier, my $dummy, $_) = m/^\s*([^ xX]*)\s*(x|X)(.*$)/;


        s/^(\s)+//g;
	s/(\s)*$//g;
	if (!($multiplier =~ m/^(0|[1-9][0-9]*)$/)) {
	    push @errors, li("Line $lineno: ballot multiplier $multiplier not a number.");
	    next;
	}
    }
    my @indices = split /\s*,\s*|\s+/;
    if ($#indices != $num_choices - 1) {
	push @errors, li("Line $lineno: expected $num_choices ranks, found " .  ($#indices+1). ".");
	next;
    }
    for (my $cnt = 0; $cnt < $multiplier; $cnt++) {
	for (my $i = 0; $i < $num_choices; $i++) {
	    my $rank = $indices[$i];
	    if ($proportional eq 'yes' && $use_combined_ratings) {
		$ballots[$num_ballots][$i] = 0 + $rank;
		# print pre("rank $rank seen"), $cr;
		next;
	    }
	    if ($rank eq '-') { $rank = 'No opinion'; }
	    if ($rank =~ m/^[0-9]*$/ &&
		$rank >= 1 &&
		$rank <= $num_choices ||
		$rank eq 'No opinion') {
		$ballots[$num_ballots][$i] = $rank;
		next;
	    }
	    if ($cnt == 0) {
		push @errors, li("Line $lineno: badly formed rank &ldquo;$rank&rdquo;.");
	    }
	}
	$num_ballots++;
	if ($num_ballots > 1000) {
	    push @errors, li("Line $lineno: too many ballots for test poll.");
	}
    }
  }
}

if ($num_ballots == 0) {
    push @errors, li("No valid ballots found.");
}

if ($#errors >= 0) {
    print h2("Errors found in ballot file"), $cr;
    print ul(@errors);
    print p("Ballots not uploaded."), $cr;
    exit 0;
}
print p("Ballot file is well formed and contains $num_ballots ballots."), $cr;

my $nv_data = $vdata{'num_votes'};
my $num_votes = $nv_data ? (0 + $nv_data) : 0;

#
# Insert the ballots into the DB
#
for (my $i = 0; $i < $num_ballots; $i++) {
    my $vote = '';
    my @rank;
#
# Record the vote
#
    my $ballot_key = 'ext' . ($i + $num_votes);
    for (my $j=0; $j < $num_choices; $j++) {
	my $rank = $ballots[$i][$j];
	if ($vote eq '') {
	    $vote = $rank;
	} else {
	    $vote .= "," . $rank;
	}
	$rank[$j] = $rank;
    }
    $vdata{$ballot_key} = $vote;
#
# Record the "voter"
#
    if ($recorded_voters) {
	$recorded_voters = $vdata{'recorded_voters'} =
	    $recorded_voters . "\n".  $ballot_key;
    } else {
	$recorded_voters = $vdata{'recorded_voters'} = $ballot_key;
    }
    if ($reveal_voters eq 'yes') {
	$vdata{"voter key of $ballot_key"} = $ballot_key;
    }
#
# Update the matrix
#
    for (my $j = 0; $j < $num_choices; $j++) {
	for (my $k = 0; $k < $num_choices; $k++) {
	    my $jk = $vdata{"$j.$k"};
	       $jk = 0 if (!defined($jk));
	if ($rank[$j] ne 'No opinion' &&
			$rank[$k] ne 'No opinion' &&
			$rank[$j] < $rank[$k])
		{
			$vdata{"$j.$k"} = $jk + 1;
	    }	
	}
    }
}


$vdata{'last_vote_time'} = $last_vote_time = time();
$vdata{'num_votes'} += $num_ballots;

print p('Ballots uploaded successfully.'), $cr;

if (!IsStarted) {
    StartElection;
}

&PointToResults;
print end_html();

exit 0;
