#!/usr/bin/perl -w
# $Id: countify,v 1.3 2005/05/16 18:10:46 agriffis Exp $
#
# Copyright 2005-2015 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
#
# countify: collect, tabulate and announce ballot results
#

BEGIN {
    my $dirname;
    if(-f '/etc/elections/Votify.pm') {
        $dirname = '/etc/elections';
    } else {
        use Cwd qw(abs_path);
        use File::Basename qw(dirname);
        $dirname = dirname(abs_path(__FILE__));
    }
    push @INC, $dirname;
}

use Cwd qw(abs_path);
use File::Basename;
use File::Spec::Functions;
use Getopt::Long;
use List::Util;
use POSIX;

use Votify 'official';
use strict;

######################################################################
# Global vars
######################################################################

(my $zero = $0) =~ s,.*/,,;
(my $version = $Votify::version) =~ s/.*?(\d.*\d).*/$zero version $1\n/;
my %opt;

# Collect the open elections
my (%open_elections, $usage_elections);
%open_elections = Votify::get_open_elections_hash();
if (scalar keys %open_elections) {
    $usage_elections = join("\n        ", keys %open_elections);
} else {
    $usage_elections = "(no elections currently open)";
}

# rest of usage
my $usage = <<EOT;

usage: $zero <command> <election>

where <command> is one of:

    --collect   Collect the submitted ballots from home directories
    --rank      Show ranking based on master ballot
    --help      Show this help message
    --version   Show version information

and <election> is one of the elections currently in-progress.  The following
elections are currently open:

    $usage_elections

EOT

######################################################################
# Main
######################################################################

package main;

# Make sure umask is secure before we do anything
umask 077;

# Parse the options on the cmdline.  Put the short versions first in
# each optionstring so that the hash keys are created using the short
# versions.  For example, use 'q|qar', not 'qar|q'.
my ($result) = GetOptions(
    \%opt,
    'collect',          # collect the submitted ballots from home directories
    'rank',             # show the ranking based on a master ballot
    'help',             # help message
    'version',          # version information
);
if ($opt{'help'} or not %opt) { print STDERR $usage; exit 0 }
if ($opt{'version'}) { print STDERR $version; exit 0 }
die "$zero: only one command allowed; use --help for help\n" if 1 < keys %opt;
die "$zero: election required; use --help for help\n" unless @ARGV == 1;

my ($election) = $ARGV[0];
my ($vl) = VoterList->new($election);

if ($opt{'collect'}) {
    my ($ol) = OfficialList->new($election);
    my ($master) = MasterBallot->new($election, $vl);
    $master->collect($vl->voters);
    for my $o ($ol->officials) {
        my ($uid, $home) = (getpwnam $o)[2,7];
        $home = "/home/$o" unless defined $home;
        mkdir catfile("$home", "results-$election");
        $master->write_master("$home/results-$election/master-$election");
        $master->write_casting_voters("$home/results-$election/casting-voters-$election");
        $vl->write_confs("$home/results-$election/confs-$election");
        chown $uid, -1, "$home/results-$election",
            "$home/results-$election/master-$election",
            "$home/results-$election/confs-$election",
            "$home/results-$election/casting-voters-$election";
    }
    exit 0;
}

if ($opt{'rank'}) {
    my ($master) = MasterBallot->new($election, $vl);
    my (@candidates, @winner, @ranked, @ranks);
    $master->read_master("$ENV{HOME}/results-$election/master-$election");
    $master->generate_candidates();
    @candidates = sort keys %{$master->{'candidates'}};

    while (1) {
        $master->tabulate();

        # this is a hack :-(
        #print "\n";
        for my $r (@ranked) {
            #print "$r is already ranked\n";
            for my $c (@candidates) {
                $master->{'table'}{"$r+$c"} = -1;
            }
            $master->{'table'}{"$r+$r"} = '+++';
        }

        # now display the table
        print "\n";
        $master->display_table();

        @winner = $master->cssd();
        if (@winner == @candidates) {
            print "\n*** No additional winners to add to the list ***\n";
            last;
        }

        push @ranks, [ @winner ];
        push @ranked, @winner;
        if (@ranked == @candidates) {
            print "\n*** Finished ranking candidates ***\n";
            last;
        }

        print "\n*** Running another pass to find the next winners... ***\n";
    }

    print "\nFinal ranked list:\n";
    print map "@$_\n", @ranks;
}

__END__
# vim:sw=4 et
