package WebGUI::Asset::Wobject::Poll;


#-------------------------------------------------------------------
# WebGUI is Copyright 2001-2009 Plain Black Corporation.
#-------------------------------------------------------------------
# Please read the legal notices (docs/legal.txt) and the license
# (docs/license.txt) that came with this distribution before using
# this software.
#-------------------------------------------------------------------
# http://www.plainblack.com                     info@plainblack.com
#-------------------------------------------------------------------

use strict;
use List::Util;
use WebGUI::Form;
use WebGUI::International;
use WebGUI::SQL;
use WebGUI::User;
use WebGUI::Utility;
use WebGUI::Asset::Wobject;
use WebGUI::Image::Graph;
use WebGUI::Storage;
use JSON;

use WebGUI::Definition::Asset;
extends 'WebGUI::Asset::Wobject';
aspect assetName => ['assetName', 'Asset_Poll'];
aspect tableName => 'Poll';
aspect icon      => 'poll.gif';
property templateId => (
                tab          => 'display',
                fieldType    => "template",
                default      => 'PBtmpl0000000000000055',
                label        => [73, 'Asset_Poll'],
                hoverHelp    => ['73 description', 'Asset_Poll'],
                namespace    => "Poll",
         );
property active => (
                tab          => 'properties',
                fieldType    => "yesNo",
                default      => 1,
                label        => [3, 'Asset_Poll'],
                hoverHelp    => ['3 description', 'Asset_Poll'],
            );
property karmaPerVote => (
                fieldType    => 'integer',
                noFormPost   => \&_karmaPerVote_noFormPost,
                default      => 0,
                label        => [20, 'Asset_Poll'],
                hoverHelp    => ['20 description', 'Asset_Poll'],
         ); 
sub _karmaPerVote_noFormPost {
    my $self = shift;
    return ! $self->session->setting->get('useKarma');
}
property graphWidth => (
                fieldType    => "integer",
                default      => 150,
                label        => [5, 'Asset_Poll'],
                hoverHelp    => ['5 description', 'Asset_Poll'],
         ); 
property voteGroup => (
                tab          => 'security',
                fieldType    => "group",
                default      => 7,
                label        => [4, 'Asset_Poll'],
                hoverHelp    => ['4 description', 'Asset_Poll'],
         ); 
property question => (
                tab          => 'properties',
                fieldType    => "text",
                default      => undef,
                label        => [6, 'Asset_Poll'],
                hoverHelp    => ['6 description', 'Asset_Poll'],
         ); 
property randomizeAnswers => (
                tab          => 'properties',
                fieldType    => "yesNo",
                default      => 1,
                label        => [72, 'Asset_Poll'],
                hoverHelp    => ['72 description', 'Asset_Poll'],
         );
property a1 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a2 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a3 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a4 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a5 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a6 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a7 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a8 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a9 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a10 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a11 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a12 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a13 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a14 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a15 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a16 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a17 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a18 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a19 => (
                fieldType=>"hidden",
                default     =>undef
         ); 
property a20 => (
                fieldType=>"hidden",
                default     =>undef
         );
property graphConfiguration => (
                fieldType=>"hidden",
                default     =>undef,
         );
property generateGraph => (
                noFormPost   => \&_generateGraph_noFormPost,
                fieldType    => 'yesNo',
                default      => 0,
                label        => ['generate graph', 'Asset_Poll'],
                hoverHelp    => ['generate graph description', 'Asset_Poll'],
         );
sub _generateGraph_noFormPost {
    my $self = shift;
    return WebGUI::Image::Graph->getPluginList($self->session) ? 1 : 0;
}
#-------------------------------------------------------------------
sub _hasVoted {
	my $self = shift;
	my ($hasVoted) = $self->session->db->quickArray("select count(*) from Poll_answer 
		where assetId=".$self->session->db->quote($self->getId)." and ((userId=".$self->session->db->quote($self->session->user->userId)."
		and userId<>'1') or (userId=".$self->session->db->quote($self->session->user->userId)." and ipAddress='".$self->session->env->getIp."'))");
	return $hasVoted;
}

#-------------------------------------------------------------------

=head2 duplicate 

Extend the base method to handle copying Poll answer data.

=cut

sub duplicate {
	my $self = shift;
	my $newAsset = $self->SUPER::duplicate(@_);
	my $sth = $self->session->db->read("select * from Poll_answer where assetId=?", [$self->getId]);
	while (my $data = $sth->hashRef) {
		$newAsset->setVote($data->{answer}, $data->{userId}, $data->{ipAddress});
	}
	$sth->finish;
	return $newAsset;
}

#----------------------------------------------------------------------------

=head2 freezeGraphConfig 

Serializes graph configuration. Returns a scalar containing the serialized
structure.

=cut

sub freezeGraphConfig {
    my $self        = shift;
    my $obj         = shift;
    
    return JSON::to_json($obj);
}


#-------------------------------------------------------------------

=head2 getEditForm 

Extend the base class to handle the answers and graphing plugins.

=cut

##TODO: Pull out all form elements which can come from the definition sub
##and only have hand code in here.

sub getEditForm {
	my $self = shift;
	my $tabform = $self->SUPER::getEditForm; 
	my $i18n = WebGUI::International->new($self->session,"Asset_Poll");
    my ($i, $answers);
    for ($i=1; $i<=20; $i++) {
        if ($self->get('a'.$i) =~ /\C/) {
            $answers .= $self->getValue("a".$i)."\n";
        }
    }
	if ($self->session->setting->get("useKarma")) {
		$tabform->getTab("properties")->integer(
			-name=>"karmaPerVote",
			-label=>$i18n->get(20),
			-hoverHelp=>$i18n->get('20 description'),
			-value=>$self->getValue("karmaPerVote")
			);
	} else {
		$tabform->getTab("properties")->hidden(
			-name=>"karmaPerVote",
			-value=>$self->getValue("karmaPerVote")
			);
	}
	$tabform->getTab("display")->integer(
		-name=>"graphWidth",
		-label=>$i18n->get(5),
		-hoverHelp=>$i18n->get('5 description'),
		-value=>$self->getValue("graphWidth")
		);
        $tabform->getTab("properties")->textarea(
		-name=>"answers",
		-label=>$i18n->get(7),
		-hoverHelp=>$i18n->get('7 description'),
		-subtext=>('<span class="formSubtext"><br />'.$i18n->get(8).'</span>'),
		-value=>$answers
		);
	$tabform->getTab("properties")->yesNo(
		-name=>"resetVotes",
		-label=>$i18n->get(10),
		-hoverHelp=>$i18n->get('10 description')
		) if $self->session->form->process("func") ne 'add';


	if (WebGUI::Image::Graph->getPluginList($self->session)) {
		my $config = $self->getGraphConfig;

		$tabform->addTab('graph', $i18n->get('Graphing','Image_Graph'));
		$tabform->getTab('graph')->yesNo(
			-name		=> 'generateGraph',
			-label		=> $i18n->get('generate graph'),
			-hoverHelp	=> $i18n->get('generate graph description'),
			-value		=> $self->getValue('generateGraph'),
		);
		$tabform->getTab('graph')->raw(WebGUI::Image::Graph->getGraphingTab($self->session, $config));
	}

	return $tabform;
}

#----------------------------------------------------------------------------

=head2 getGraphConfig

Gets and thaws the graph configuration. Returns a reference to the original
data structure.

=cut

sub getGraphConfig {
    my $self    = shift;
    my $config  = $self->get("graphConfiguration");

    return undef unless $config;
    return $self->thawGraphConfig($config);
}

#-------------------------------------------------------------------

=head2 indexContent ( )

Indexing question and answers. See WebGUI::Asset::indexContent() for additonal details. 

=cut

sub indexContent {
	my $self = shift;
	my $indexer = $self->SUPER::indexContent;
	$indexer->addKeywords($self->get("question")." ".$self->get("answers"));
}


#-------------------------------------------------------------------

=head2 prepareView ( )

See WebGUI::Asset::prepareView() for details.

=cut

sub prepareView {
    my $self = shift;
    $self->SUPER::prepareView();
    my $template = WebGUI::Asset::Template->new($self->session, $self->get("templateId"));
    if (!$template) {
        WebGUI::Error::ObjectNotFound::Template->throw(
            error      => qq{Template not found},
            templateId => $self->get("templateId"),
            assetId    => $self->getId,
        );
    }
    $template->prepare($self->getMetaDataAsTemplateVariables);
    $self->{_viewTemplate} = $template;
}


#-------------------------------------------------------------------

=head2 processPropertiesFromFormPost 

Extend the base method to handle the answers and the Graphing plugin.

=cut

sub processPropertiesFromFormPost {
	my $self = shift;
	$self->SUPER::processPropertiesFromFormPost;
	my $property = {};
    my $answers = $self->session->form->process("answers");
    $answers =~ s{\r}{}xmsg;
    my @answer = split("\n",$answers);
    for (my $i=1; $i<=20; $i++) {
        $property->{'a'.$i} = $answer[($i-1)] || "";
    }

	if (WebGUI::Image::Graph->getPluginList($self->session)) {
		my $graph = WebGUI::Image::Graph->processConfigurationForm($self->session);
		$self->setGraphConfig( $graph->getConfiguration );
	}

	$self->update($property);
	$self->session->db->write("delete from Poll_answer where assetId=".$self->session->db->quote($self->getId)) if ($self->session->form->process("resetVotes"));
}


#-------------------------------------------------------------------

=head2 purge 

Extend the base method to handle Poll answers.

=cut

sub purge {
	my $self = shift;
	$self->session->db->write("delete from Poll_answer where assetId=".$self->session->db->quote($self->getId));
	$self->SUPER::purge();
}	

#----------------------------------------------------------------------------

=head2 setGraphConfig

Freezes and stores the configuration for the graphing of this poll. 

=cut

sub setGraphConfig {
    my $self    = shift;
    my $obj     = shift;

    $self->update({
        graphConfiguration  => $self->freezeGraphConfig($obj),
    });
}

#-------------------------------------------------------------------

=head2 setVote ($answer, $userId, $ip)

Accumulates a vote into the database so that it can be counted.

=head3 $answer

The answer selected by the user.

=head3 $userid

The userId of the person who voted.

=head3 $ip

The IP address of the user who voted.

=cut

sub setVote {
    my $self = shift;
    my $answer = shift;
    my $userId = shift;
    my $ip = shift;
    $self->session->db->write("insert into Poll_answer (assetId, answer, userId, ipAddress) values (?,?,?,?)",
        [$self->getId, $answer, $userId, $ip] );
}

#----------------------------------------------------------------------------

=head2 thawGraphConfig 

Deserializes the graph configuration and returns the data structure.

=cut

sub thawGraphConfig {
    my $self        = shift;
    my $string      = shift;
    
    return unless $string;
    return JSON::from_json($string);
}

#-------------------------------------------------------------------

=head2 view 

Generate the poll results with graph if configured to do so.  Display the form
for the user to vote.

=cut

sub view {
	my $self = shift;
	my (%var, $answer, @answers, $showPoll, $f, @dataset, @labels);
        $var{question} = $self->get("question");
	if ($self->get("active") eq "0") {
		$showPoll = 0;
	} elsif ($self->session->user->isInGroup($self->get("voteGroup"))) {
		if ($self->_hasVoted()) {
			$showPoll = 0;
		} else {
			$showPoll = 1;
		}
	} else {
		$showPoll = 0;
	}
	$var{canVote} = $showPoll;
        my ($totalResponses) = $self->session->db->quickArray("select count(*) from Poll_answer where assetId=".$self->session->db->quote($self->getId));
	my $i18n = WebGUI::International->new($self->session,"Asset_Poll");
	$var{"responses.label"} = $i18n->get(12);
	$var{"responses.total"} = $totalResponses;
	$var{"form.start"} = WebGUI::Form::formHeader($self->session,{action=>$self->getUrl});
        $var{"form.start"} .= WebGUI::Form::hidden($self->session,{name=>'func',value=>'vote'});
	$var{"form.submit"} = WebGUI::Form::submit($self->session,{value=>$i18n->get(11)});
	$var{"form.end"} = WebGUI::Form::formFooter($self->session,);
	$totalResponses = 1 if ($totalResponses < 1);
        for (my $i=1; $i<=20; $i++) {
        	if ($self->get('a'.$i) =~ /\C/) {
                        my ($tally) = $self->session->db->quickArray("select count(*) from Poll_answer where answer='a"
				.$i."' and assetId=".$self->session->db->quote($self->getId)." group by answer");
                	push(@answers,{
				"answer.form"=>WebGUI::Form::radio($self->session,{name=>"answer",value=>"a".$i}),
				"answer.text"=>$self->get('a'.$i),
				"answer.graphWidth"=>round($self->get("graphWidth")*$tally/$totalResponses),
				"answer.number"=>$i,
				"answer.percent"=>round(100*$tally/$totalResponses),
				"answer.total"=>($tally+0)
                        	});
			push(@dataset, ($tally+0));
			push(@labels, $self->get('a'.$i));
                }
	}
	@answers = List::Util::shuffle(@answers) if ($self->get("randomizeAnswers"));
	$var{answer_loop} = \@answers;

	if ($self->getValue('generateGraph')) {
		my $config = $self->getGraphConfig;
        if ($config) {
            my $graph = WebGUI::Image::Graph->loadByConfiguration($self->session, $config);
            $graph->addDataset(\@dataset);
            $graph->setLabels(\@labels);

            $graph->draw;

            my $storage = WebGUI::Storage->createTemp($self->session);
            my $filename = 'poll'.$self->session->id->generate.".png";
            $graph->saveToStorageLocation($storage, $filename);

            $var{graphUrl} = $storage->getUrl($filename);
            $var{hasImageGraph} = 1;
        } else {
            $self->session->errorHandler->error('The graph configuration hash of the Poll ('.$self->getUrl.') is corrupt.');
        }
	}
	
	return $self->processTemplate(\%var,undef,$self->{_viewTemplate});
}

#-------------------------------------------------------------------

=head2 www_vote 

Web method for the user to add their vote.  If so configured, gives karma
to the user.

=cut

sub www_vote {
	my $self = shift;
	my $u;
        if ($self->session->form->process("answer") ne "" && $self->session->user->isInGroup($self->get("voteGroup")) && !($self->_hasVoted())) {
        	$self->setVote($self->session->form->process("answer"),$self->session->user->userId,$self->session->env->getIp);
		if ($self->session->setting->get("useKarma")) {
			$self->session->user->karma($self->get("karmaPerVote"),"Poll (".$self->getId.")","Voted on this poll.");
		}
		$self->getContainer->purgeCache;
	}

	return $self->session->asset($self->getContainer)->www_view;
}



1;

