package Vote::DB;

# $Id$

use strict;
use warnings;
use Vote;
use Mail::Mailer;
use base 'Vote::DB::common';
use Vote::DB::Poll;
use Vote::DB::Ballot; # see ballot()
use Vote::DB::Voting; # see delete_voting()
use Vote::DB::Choice;

=head1 NAME

Vote::Model::Vote - Catalyst Model

=head1 DESCRIPTION

Catalyst Model.

=cut

sub new {
    my ($class, $dbstring) = @_;
    
    bless {
        dbstring => $dbstring,
        db => Vote::DB::common::_newdb($dbstring),
    }, $class;
}

sub list_comming_vote {
    my ($self) = @_;

    my $sth = $self->db->prepare_cached(
        q{
        select id from poll where
        (start > now() and "end" > now()) or
        "end" is null or start is null
        }
    );

    $sth->execute;
    my @id;
    while(my $res = $sth->fetchrow_hashref) {
        push(@id, $res->{id});
    }

    @id
}

sub list_running_vote {
    my ($self) = @_;

    my $sth = $self->db->prepare_cached(
        q{
        select id from poll where start < now() and "end" > now()
        }
    );

    $sth->execute;
    my @id;
    while(my $res = $sth->fetchrow_hashref) {
        push(@id, $res->{id});
    }

    @id
}

sub list_closed_vote {
    my ($self) = @_;

    my $sth = $self->db->prepare_cached(
        q{
        select id from poll where
        start < now() and "end" < now()
        }
    );

    $sth->execute;
    my @id;
    while(my $res = $sth->fetchrow_hashref) {
        push(@id, $res->{id});
    }

    @id
}

sub poll {
    my ($self, $pollid) = @_;
    Vote::DB::Poll->new($self->{dbstring}, $pollid);
}

sub ballot {
    my ($self, $ballotid) = @_;
    # TODO must die, ballot are attached to a poll
    Vote::DB::Ballot->new($self->{dbstring}, $ballotid);
}

sub vote_param {
    my ($self, $voteid, %attr) = @_;
    warn "# vote_param";
    $self->poll($voteid)->param(%attr);
}

sub vote_status {
    my ($self, $id) = @_;
    warn "# vote_status";
    $self->poll($id)->status;
}

sub vote_info {
    my ($self, $id) = @_;
    $self->poll($id)->info;
}

sub vote_set_settings {
    my ($self, $poll, $var, $val) = @_;
    $self->poll($poll)->set_settings($var, $val);
}

sub vote_signing {
    my ($self, $id) = @_;
    $self->poll($id)->signing;
}

sub vote_voting {
    my ($self, $voteid) = @_;
    $self->poll($voteid)->voting_keys;
}

sub voting_info {
    my ($self, $id) = @_;
    $self->poll($id)->voting_info;
}

sub vote_choices {
    my ($self, $id) = @_;
    $self->poll($id)->choices;
}

sub vote_add_choice {
    my ($self, $voteid, $label) = @_;
    $self->poll($voteid)->add_choice($label);
}

sub choice_info {
    my ($self, $chid) = @_;
    Vote::DB::Choice->new($self->{dbstring}, $chid)->info;
}

sub delete_choice {
    my ($self, $chid) = @_;

    my $sth = $self->db->prepare_cached(
        q{delete from choice where key = ?}
    );

    $sth->execute($chid);
}

sub voting_info_id {
    my ($self, $mail, $voteid) = @_;
    $self->poll($voteid)->voting_from_mail($mail)->info;
}

sub register_ballot {
    my ($self, $vid, $voteid, $choice, $fchoice, $referal) = @_;
    $self->poll($voteid)->register_ballot($vid, $choice, $fchoice, $referal);
}

sub mail_ballot_confirm {
    my ($self, $vid, $voteid, $info) = @_;
    $self->poll($voteid)->mail_ballot_confirm($vid, $info);
}

sub vote_voting_count {
    my ($self, $id) = @_;
    $self->poll($id)->voting_count;
}

sub signing_count { vote_signing_count(@_) }

sub vote_signing_count {
    my ($self, $voteid) = @_;
    $self->poll($voteid)->signing_count;
}

sub ballot_count { vote_ballot_count(@_) }

sub vote_ballot_count {
    my ($self, $voteid) = @_;
    $self->poll($voteid)->ballot_count;
}

sub ballot_count_nonull { vote_ballot_count_nonull(@_) }

sub vote_ballot_count_nonull {
    my ($self, $voteid) = @_;
    $self->poll($voteid)->ballot_count_nonull;
}

sub auth_voting {
    my ($self, $poll, $mail, $password) = @_;
    $self->poll($poll)->auth_voting($mail, $password);
}

sub auth_poll {
    my ($self, $voteid, $passwd) = @_;
    $self->poll($voteid)->auth_poll($passwd);
}

sub voting_has_sign {
    my ($self, $poll, $user) = @_;
    warn $user;
    $self->poll($poll)->voting_has_sign($user);
}

# Requete de decompte des voix:

sub vote_results_count {
    my ($self, $voteid) = @_;
    $self->poll($voteid)->results_count;
}

sub vote_results_nonull {
    my ($self, $voteid) = @_;
    $self->poll($voteid)->results_nonull;
}

sub list_vote_ballot {
    my ($self, $voteid) = @_;
    $self->poll($voteid)->list_ballot;
}

sub list_vote_ballot_needvalid {
    my ($self, $voteid) = @_;
    $self->poll($voteid)->list_ballot_needvalid;
}

sub ballot_info {
    my ($self, $ballotid) = @_;
    $self->ballot($ballotid)->info;
}

sub mark_ballot_invalid {
    my ($self, $ballotid, $invalid) = @_;
    $self->ballot($ballotid)->mark_invalid($invalid);
}

sub ballot_items {
    my ($self, $ballotid) = @_;
    $self->ballot($ballotid)->items;
}

sub vote_ballot_untrusted_values {
    my ($self, $voteid) = @_;
    $self->poll($voteid)->ballot_untrusted_values;
}

sub vote_ballot_values {
    my ($self, $voteid) = @_;
    $self->poll($voteid)->ballot_values;
}

sub vote_map_value {
    my ($self, $voteid, $from, $to) = @_;
    $self->poll($voteid)->map_value($from, $to);
}

sub addupd_voting {
    my ($self, $voteid, $mail, $id) = @_;
    $self->poll($voteid)->addupd_voting($mail, $id);
}

sub delete_voting {
    my ($self, $key) = @_;
    # must die, voting are attached to a poll
    Vote::DB::Voting->new($self->{dbstring}, $key)->has_sign and return;
    my $sth = $self->db->prepare_cached(
        q{delete from voting where key = ?}
    );

    $sth->execute($key);
}

sub voting_from_file {
    my ($self, $voteid, $fh, $delete) = @_;
    $self->poll($voteid)->voting_from_file($fh, $delete);
}

sub mail_passwd_ifnul {
    my ($self, $voteid, $mailinfo) = @_;
    $self->poll($voteid)->mail_passwd_ifnul($mailinfo);
}

sub clean_old_poll_request {
    my ($self) = @_;

    $self->db->do(q{delete from poll_request where "create" < now() - '30 days'::interval});
}

sub poll_request_info {
    my ($self, $rid) = @_;

    my $sth = $self->db->prepare_cached(
        q{select * from poll_request where id = ?}
    );

    $sth->execute($rid);
    my $res = $sth->fetchrow_hashref;
    $sth->finish;
    $res
}

sub poll_from_request {
    my ($self, $rid, $passwd) = @_;
    my $rinfo = $self->poll_request_info($rid) or return;

    my $encpasswd = $self->gen_enc_passwd($passwd);

    my $getpollid = $self->db->prepare_cached(
        q{select nextval('poll_id_seq')}
    );
    $getpollid->execute();
    my $newpollid = $getpollid->fetchrow_hashref->{nextval};
    
    my $newpoll = $self->db->prepare_cached(
        q{insert into poll (id, label, owner, password) values (?,?,?,?)}
    );

    $newpoll->execute($newpollid, $rinfo->{label}, $rinfo->{mail}, $encpasswd);
    # set some default
    $self->vote_param($newpollid,
        free_choice => 0,
        choice_count => 1,
    );     

    my $delreq = $self->db->prepare_cached(
        q{delete from poll_request where id = ?}
    );

    $delreq->execute($rid);
    $self->db->commit;

    $newpollid
}

sub create_poll_request {
    my ($self, %info) = @_;

    $info{mail} or return;
    my $addreq = $self->db->prepare_cached(
        q{insert into poll_request (id, label, mail) values (?,?,?)}
    );

    my $reqid = Vote::DB::common::gen_uid();

    $addreq->execute($reqid, $info{label}, $info{mail});
    my $mailer = new Mail::Mailer 'smtp', Server => (Vote->config->{smtp} || 'localhost');
    $ENV{MAILADDRESS} = undef;
    $mailer->open({
        From => 'Voting system <nomail@nomail.com>', # TODO allow to configure this
        To => $info{mail},
        Subject => 'Votre nouveau vote',
        Vote::DB::common::mail_header(),
    });
    print $mailer <<EOF;

Vous avez demandez la création d'un nouveau vote:
$info{label}

Pour valider votre demande, veuiller allez visitez la page:
$info{url}/$reqid

A bientôt
EOF
    $mailer->close
        or warn "couldn't send whole message: $!\n";
    $self->db->commit;
    1;
}

=head1 AUTHOR

Thauvin Olivier

=head1 LICENSE

This library is free software, you can redistribute it and/or modify
it under the same terms as Perl itself or CeCILL.

=cut

1;
