package iPoll;
use strict;
#################################################################################
# Ikonboard v3 by Jarvis Entertainment Group, Inc.
#
# No parts of this script can be used outside Ikonboard without prior consent.
#
# More information available from <ib-license@jarvisgroup.net>
# (c)2001 Jarvis Entertainment Group, Inc.
# 
# http://www.ikonboard.com
#
# Please Read the license for more information
#+-----------------------------------------------------------------+
#
# iPoll: Polling Fucntions.
#
#################################################################################

# For the future
#
# Make the posting / polling more modular. This whole module is held together with
# duct tape. It works fine, it's just ugly and carries bad coding principles.
#
# Something like:
# Postings/
#     -- Global.pm  #Hold global posting elements such as the HTML compiler, etc
#     -- NewPost.pm  # New post routines
#     -- ReplyPost.pm  #ummm.
#     -- NewPoll.pm    #well...
#     -- ReplyPoll.pm  #You've guessed it

BEGIN {
    require 'Lib/FUNC.pm';
}

my $output = FUNC::Output->new();
my $mem    = FUNC::Member->new();
my $std    = FUNC::STD->new();
$iPoll::lang = $std->LoadLanguage('PostWords');    

sub new {
    my $pkg = shift;
    my $obj = { '.html' => undef, 'MEMBER' => $iB::MEMBER };
    bless $obj, $pkg;
    return $obj;
}



sub StartPoll {
    my ($obj, $db) = @_;
    require "Post.pm";
    my $post = Post->new();
    require $iB::SKIN->{'DIR'} . '/PostView.pm' or die $!;
    $post->NewPollForm($db);
}


sub AddPoll {
    my ($obj, $db) = @_;

    unless ($iB::IN{nullvote}) {
        $std->Error( DB      => $db,
                     LEVEL   =>'1',
                     MESSAGE =>'No Vote!'
                   ) unless (defined $std->IsNumber($iB::IN{'poll_vote'}));
    }

    my $found = $db->query(  TABLE => 'forum_poll_voters', 
                             MATCH => 'ONE',
                             WHERE => "MEMBER_ID eq '$iB::MEMBER->{'MEMBER_ID'}' and POLL_ID == $obj->{'.topic_id'} and FORUM_ID == $obj->{'.forum_id'}"
                          );

    if ($found->{'MEMBER_ID'}) {
        $std->Error( DB => $db, LEVEL=>'1',MESSAGE=>'poll_you_voted');
    }
 
    unless ( $obj->{'p_data'} = $db->query( TABLE => 'forum_polls',
                                            MATCH => 'ONE',
                                            WHERE => "POLL_ID == $obj->{'.topic_id'} and FORUM_ID == $obj->{'.forum_id'}"
                                            ) ) {
        $std->Error( DB => $db, LEVEL=>'1',MESSAGE=>'poll_none_found');
    }

    # If we get to here, then we're good to add a vote

    $db->insert( TABLE  => 'forum_poll_voters',
                 VALUES => { MEMBER_ID => $iB::MEMBER->{'MEMBER_ID'},
                             VOTER_IP  => $ENV{'REMOTE_ADDR'},
                             POLL_ID   => $obj->{'.topic_id'},
                             FORUM_ID  => $obj->{'.forum_id'},
                             DATE      => time,
                           }
               );

    # Is this a null vote?

    unless ($iB::IN{nullvote}) {

        for (split /\|/, $obj->{'p_data'}->{'POLL_ANSWERS'}) {
            my ($split, $votes) = split "~=~";
            my ($id, $answer)   = split /\~\:\:\~/,$split;
            ++$votes if $id == $iB::IN{'poll_vote'};
            $obj->{'.newline'} .= $id.'~::~'.$answer.'~=~'.$votes.'|';
        }
    
        ++$obj->{'p_data'}->{'TOTAL_VOTES'};
        $obj->{'p_data'}->{'POLL_ANSWERS'} = $obj->{'.newline'};
    
        $db->update( TABLE  => 'forum_polls',
                     KEY    => $obj->{'p_data'}->{'ID'},
                     VALUES => $obj->{'p_data'}
                   );
    
        if ($iB::INFO->{'ALLOW_POLL_BUMP'}) {
    
            $obj->{'TOPIC'}->{'LAST_VOTE'} = time;
            $obj->{'TOPIC'}->{'TOPIC_LAST_DATE'} = time;
            $db->update( TABLE    => 'forum_topics',
                         ID       => $obj->{'.forum_id'},
                         KEY      => $obj->{'.topic_id'},
                         VALUES   => $obj->{'TOPIC'}
                        );
        }

    }

    my $lang = $iB::IN{nullvote} ? $iPoll::lang->{poll_viewing_results} : $iPoll::lang->{'poll_vote_added'};
    
    $output->redirect_screen( TEXT => $lang, URL => "act=ST;f=$obj->{'.forum_id'};t=$obj->{'.topic_id'}");
}


sub ProcessPoll {
    my ($obj, $db) = @_;

    # This is horrible and I hate it.
    # First thing to do for v3.1? Rewrite the entire polling/posting system...

    require "Post.pm";
    my $post = Post->new();
    require $iB::SKIN->{'DIR'} . '/PostView.pm' or die $!;

    $iB::IN{'allow_disc'} = $iB::IN{'allow_disc'} == 0  ? 'open' : 'closed';

    # Check for errors

    my %POST;


    $POST{'POST_DATE'}    = time;
    $POST{'POST_ICON'}    = $std->IsNumber($iB::IN{'iconid'}) || 0;
    $POST{'POST'}         = $iB::IN{'Post'};
    $POST{'TOPIC_ID'}     = $obj->{'.topic_id'};
    $POST{'FORUM_ID'}     = $obj->{'.forum_id'};

    # Cut off a piece of duct tape...
    $iB::IN{CODE} = '01';


    unless (($iB::CGI->param('TopicTitle')) and (length $iB::CGI->param('TopicTitle') > 2)) {
        $POST{'_ERROR'} = $Post::lang->{'no_topic_title'};
        $post->NewPollForm($db, \%POST)
    }

    unless (length($iB::CGI->param('TopicTitle')) < 51) {
        $POST{'_ERROR'} = $Post::lang->{'topic_title_long'};
        $post->NewPollForm($db, \%POST)
    }

    unless ($iB::IN{'PollAnswers'}) {
        $POST{'_ERROR'} = $Post::lang->{'no_poll_data'};
        $post->NewPollForm($db, \%POST)
    }

    $iB::IN{'PollAnswers'} =~ s!<br><br>!!g;
    my $count = 0;
    $count++ while $iB::IN{'PollAnswers'} =~ /<br>/g;

    if ($count > 10) {
        $POST{'_ERROR'} = $Post::lang->{'poll_to_many'};
        $post->NewPollForm($db, \%POST)
    }
    if ($count < 1) {
        $POST{'_ERROR'} = $Post::lang->{'poll_not_enough'};
        $post->NewPollForm($db, \%POST)
    }

    ##

    $obj->{'.topic_id'}  = $post->NewPoll($db, $obj->{preview});

    $iB::IN{'PollAnswers'} = '<!--0-->' . $iB::IN{'PollAnswers'};
    my $cnt = 0;

    $iB::IN{'PollAnswers'} =~ s{<br>} { ++$cnt; qq[<br><!--$cnt-->];}exg;
    my @poll_answers = sort keys %{ { map { $_, 1 } split /<br>/,$iB::IN{'PollAnswers'} } };

    my $i = 0; my $answers;
    for (@poll_answers) {
        next if /^<!--\d-->$/;
        $answers .= $i . '~::~' . $_ . '~=~0|'; ++$i;
    }
    my $time = time;
    #+-----------------------------------------------------------------------------------
    
    $db->insert( TABLE    => 'forum_polls',
                 VALUES   => {  'POLL_ID'        => $obj->{'.topic_id'},
                                'FORUM_ID'       => $obj->{'.forum_id'},
                                'POLL_TITLE'     => $iB::IN{'TopicTitle'},
                                'POLL_DESC'      => $iB::IN{'TopicDesc'},
                                'POLL_STARTED'   => $time,
                                'POLL_ANSWERS'   => $answers,
                                'POLL_STARTER'   => $obj->{'MEMBER'}->{'MEMBER_ID'},
                                'POLL_STARTER_N' => $obj->{'MEMBER'}->{'MEMBER_NAME'},
                                'TOTAL_VOTES'    => '0'
                              }
                );

    #+-----------------------------------------------------------------------------------
    if ($obj->{preview}) {
        $output->redirect_screen( TEXT => $Post::lang->{'moderate_topic'}, URL => "act=SF;f=$obj->{'.forum_id'}" );
    } else {
        $output->redirect_screen( TEXT  => $iPoll::lang->{'poll_vote_created'}, URL => "act=ST;f=$obj->{'.forum_id'};t=$obj->{'.topic_id'}");
    }
}



sub display_poll {
    my $obj = shift;

    my $IN = { DB         => "",
               TOPIC_ID   => "",
               FORUM_ID   => "",
               @_,
             };

    my $db = $IN->{'DB'};
    my $check;
    my $found;
    my $html;

    $obj->{'p_data'} = $db->query( TABLE => 'forum_polls',
                                   MATCH => 'ONE',
                                   WHERE => "FORUM_ID == $IN->{'FORUM_ID'} and POLL_ID == $IN->{'TOPIC_ID'}"
                                 );

    return unless defined $obj->{'p_data'}->{'ID'};
   
    require $iB::SKIN->{'DIR'} . '/PollView.pm' or die $!;

    $html = PollView::ShowPoll_header($obj->{'p_data'});

      $found = $db->query(  TABLE => 'forum_poll_voters',
                             MATCH => 'ONE',
                             WHERE => "MEMBER_ID eq '$iB::MEMBER->{'MEMBER_ID'}' and POLL_ID == $IN->{'TOPIC_ID'} and FORUM_ID == $IN->{'FORUM_ID'}"
                          );

    if ($found->{'MEMBER_ID'}) {
        $check = 1;
        $obj->{'.vote_state'} = $iPoll::lang->{'poll_you_voted'};
    }

    if ($obj->{'p_data'}->{'POLL_STARTER'} eq $iB::MEMBER->{'MEMBER_ID'} and $iB::INFO->{'ALLOW_CREATOR_VOTE'} != 1) {
        $check = 1;
        $obj->{'.vote_state'} = $iPoll::lang->{'poll_you_created'};
    }
    unless ($iB::MEMBER->{'MEMBER_ID'}) {
        $check = 1;
        $obj->{'.vote_state'} = $iPoll::lang->{'poll_no_guests'};
    }

    $html .= $check == 1 ? $obj->_show_results() : $obj->_show_form();
    
    $html .= PollView::ShowPoll_footer($obj->{'.vote_state'});

    return $html;
}
        

sub _show_results ($) {
   my $obj = shift;
   my $html;
   for (split /\|/, $obj->{'p_data'}->{'POLL_ANSWERS'}) {
        my ($split, $votes) = split "~=~";
        my ($id, $answer)   = split /\~\:\:\~/,$split;
        my $percentage = $votes == 0 ? 0 : $votes / $obj->{'p_data'}->{'TOTAL_VOTES'} * 100;
        $percentage = sprintf '%.2f', $percentage;
        my $width = $percentage > 0 ? (split/\./,$percentage)[0] * 2 : 0;
        $html .= PollView::Render_row_results($votes,$id,$answer,$percentage,$width);
    }
    return $html;
}

sub _show_form ($) {
    my $obj = shift;
    my $html;
    for (split /\|/, $obj->{'p_data'}->{'POLL_ANSWERS'}) {
        my ($split, $votes) = split "~=~";
        my ($id, $answer)   = split /\~\:\:\~/,$split;
        $html .= PollView::Render_row_form($votes,$id,$answer);
    }
    $obj->{'.vote_state'} = qq[<input type="submit" name="submit" value="$iPoll::lang->{'poll_add_vote'}" class='forminput'>&nbsp;<input type="submit" name="nullvote" value="$iPoll::lang->{'poll_null_vote'}" class='forminput'>];
    return $html;
}    




sub Process {
    my ($obj, $db) = @_;
    $std->Error( DB => $db, LEVEL=>'1',MESSAGE=>'incorrect_use') unless (defined $iB::IN{'CODE'}
                                                                 and defined $iB::IN{'f'});
    $std->Error( DB => $db, LEVEL=>'1',MESSAGE=>"poll_no_guests")unless $iB::MEMBER->{'MEMBER_ID'};
    $obj->{'.topic_id'} = $std->IsNumber($iB::IN{'t'}) || 0;
    $obj->{'.forum_id'} = $std->IsNumber($iB::IN{'f'}) || 0;
    $obj->LoadForum($db);
    $obj->LoadTopic($db) if defined $iB::IN{'t'};
    $obj->SetSession($db);
    my $CodeNo = $std->CheckCodeNo($iB::IN{'CODE'});
    my %Mode = ( '00'     => \&ProcessPoll,
                 '01'     => \&StartPoll,
                 '02'     => \&AddPoll,
                 '03'     => \&nullvote,
               );
    $Mode{$CodeNo} ? $Mode{$CodeNo}->($obj, $db) : PollError($obj, $db);
} 

#+------------------------------------------------------------------------------------------------------

sub LoadForum {
    my ($obj, $db) = @_;
    $obj->{'.forum_id'} ||= $iB::IN{'f'};
    $obj->{'FORUM'} = $db->select( TABLE   => 'forum_info',
                                   KEY     => $obj->{'.forum_id'},
                                 ) || die $db->{'error'};
    $std->Error( DB      => $db,
                 LEVEL   => 1,
                 MESSAGE => 'forum_off'
               ) unless $obj->{'FORUM'}->{'FORUM_STATUS'};

}

#+------------------------------------------------------------------------------------------------------

sub LoadTopic {
    my ($obj, $db) = @_;

    $obj->{'TOPIC'} = $db->select( TABLE  => 'forum_topics',
                                   ID     => $obj->{'.forum_id'},
                                   KEY    => $obj->{'.topic_id'}
                                 ) || die $db->{'error'};

    $std->Error( DB      => $db,
                 LEVEL   => 1,
                 MESSAGE => 'locked_topic'
               ) unless $obj->{'TOPIC'}->{'TOPIC_STATE'} eq 'open';
}

#+------------------------------------------------------------------------------------------------------

sub SetSession {
    my ($obj, $db) = @_;

    # Set up the preview posting stuff.
    
    $obj->{preview} = $obj->{'FORUM'}->{'MODERATE'} ? 1 : 0;
    # If we can avoid the moderators queue..
    $obj->{preview} = 0 if $iB::MEMBER_GROUP->{'AVOID_Q'};

    unless($iB::MEMBER->{'ALLOW_POST'}) {
        $std->Error( DB => $db, LEVEL=>'1',MESSAGE=>'posting_off');
    }

    unless( !$iB::MEMBER->{'MEMBER_ID'} or $iB::MEMBER_GROUP->{'IS_SUPMOD'} ) {

        $obj->{'.active_mod'} = $db->query( TABLE      => 'forum_moderators',
                                            MATCH      => 'ONE',
                                            WHERE      => qq!FORUM_ID == "$obj->{'.forum_id'}" and MEMBER_ID eq "$iB::MEMBER->{'MEMBER_ID'}"!
                                          );
        $obj->{'.active_mod'} ||= { };
    }


    if ($iB::IN{'CODE'} eq '00' or $iB::IN{'CODE'} eq '01') {
        unless ($iB::MEMBER_GROUP->{POST_POLLS}) {
            $std->Error( DB => $db, LEVEL=>'1',MESSAGE=>'no_start_polls');
        }
        if ($obj->{'FORUM'}->{'FORUM_START_THREADS'} ne '*') {
            unless (grep { $_ == $iB::MEMBER->{'MEMBER_GROUP'} } (split (/,/, $obj->{'FORUM'}->{'FORUM_START_THREADS'}) )) {
                $std->Error( DB => $db, LEVEL=>'1',MESSAGE=>'no_start_polls');
            }
        }
    }

    if ($iB::IN{'CODE'} eq '02') {
        unless ($iB::MEMBER_GROUP->{VOTE_POLLS}) {
            $std->Error( DB => $db, LEVEL=>'1',MESSAGE=>'no_reply_polls');
        }
        if ($obj->{'FORUM'}->{'FORUM_REPLY_THREADS'} ne '*') {
            unless (grep { $_ == $iB::MEMBER->{'MEMBER_GROUP'} } (split (/,/, $obj->{'FORUM'}->{'FORUM_REPLY_THREADS'}) )) {
                $std->Error( DB => $db, LEVEL=>'1',MESSAGE=>'no_reply_polls');
            }
        }
    }

    if ($obj->{'FORUM'}->{'FORUM_PROTECT'}) {
        if (exists $iB::COOKIES->{ $iB::INFO->{'COOKIE_ID'}.'iBForum' . $obj->{'FORUM'}->{'FORUM_ID'} }) {
            return if $iB::COOKIES->{ $iB::INFO->{'COOKIE_ID'}.'iBForum' . $obj->{'FORUM'}->{'FORUM_ID'} } eq $obj->{'FORUM'}->{'FORUM_PROTECT'};
        }
        $output->redirect_screen( TEXT => "$Topic::lang->{'please_log_in'}", URL => "?act=SF;f=$iB::IN{'f'}");
        return 1;
    }

}

sub PollError  { $std->Error(LEVEL=>'1',MESSAGE=>'No Action has been specified') }



1;
