<?php
if (!defined('PmWiki'))
	exit ();

/**
 * This script allows votings with several items and ouputs a nice graph
 * 
 * @author Patrick R. Michaud <pmichaud@pobox.com> 
 * @author Sebastian Siedentopf <schlaefer@macnews.de>
 * @version 0.5a
 * @link http://www.pmwiki.org/wiki/Cookbook/RyeVoting http://www.pmwiki.org/wiki/Cookbook/RyeVoting
 * @copyright by the respective authors 2004-2005
 * @license http://www.gnu.org/copyleft/gpl.html GNU General Public License
 * @package ryevote
 */


/*

needs 2.1beta 15
For Developers
==============

Version History
---------------
* 0.5 - - Schlaefer
** [feature] multiple button fields in form
* 0.4.4 - 2006-02-01 - Schlaefer
** [change] removed unnecessary function addone()
* 0.4.2 - 2006-01-23 - Schlaefer
** [bugfix] changed drawing for better IE compatibility
* 0.4.1 - 2005-10-23 - Schlaefer
** [bugfix] use {$PageUrl} for complete URI in form
*/

define(RYEVOTE, '0.5');

SDVA($PmWikiAutoUpdate['RyeVote'] , array(
    'version' => RYEVOTE, 
    'updateurl' =>  "http://pmwiki.org/wiki/Cookbook/RyeVoting"
));

SDV($HandleActions['ryevote'], 'HandleRyeVote');
SDV($HandleAuth['ryevote'], 'read');

SDV($RyeVoteHideAfterVote, 1);
SDV($RyeVoteRestrictions, 1);
SDV($RyeVoteCookie, $CookiePrefix.'ryevote');
SDV($RyeVoteExpires, $Now +60 * 60 * 24 * 30);
SDV($RyeVoteDBPName, "Site.RyeVoteDB");
SDV($RyeVoteDir, '/');

Markup('showryevote', '<split', '/(\(:input form.*?action=ryevote.*?input end:\))/se', "showRyeVote(PSS('$0'))");

/**
 * Belongs to Markup "showryevote" and hides the vote input form if someone already voted
 * 
 * @param string $text
 */
function showRyeVote($text) {
	global $RyeVoteCookie, $RyeVoteHideAfterVote, $RyeVoteDBPName, $RyeVoteRestrictions;
	preg_match("/\(:input hidden votename\s*(.*?)\s*?:\)/", $text, $votename);
	
	$dbname = (preg_match("/\(:input hidden db\s*(.*?)\s*?:\)/", $text, $r)) ? $r[1] : $RyeVoteDBPName;
	$db = new PmWikiPageDB($dbname);
	$data = $db->ReadData();
	$cookiename = $RyeVoteCookie.$votename[1];
	
	if ((isset ($_COOKIE[$cookiename]) ||  strpos($data['ryevote'][$votename[1]]['ipsvoted'],$_SERVER['REMOTE_ADDR']) != false) && $RyeVoteHideAfterVote && $RyeVoteRestrictions)
		return "";
	else
		return $text;
}

/**
 * Handles the voting process
 * 
 * @param string $pagename
 */
function HandleRyeVote($pagename, $auth = 'edit') {
	global $HandleActions, $ChangeSummary, $RyeVoteCookie, $RyeVoteExpires, $RyeVoteDir, $RyeVoteDBPName, $RyeVoteRestrictions;

	if (!isset ($_REQUEST['votename']))
		Redirect($pagename);

	Lock(1);
	$page = RetrieveAuthPage($pagename, $auth);
	Lock(0);
	if (!$page)
		Abort("?cannot edit $pagename");

	# find all vote input forms on a wiki page
    preg_match_all("/\\(:input form.*?action=ryevote(.*?)\\(:input end:\\)/s",$page['text'], $votes);

    $votename = $_REQUEST['votename'];
    
	foreach ($votes[0] as $key => $text) {
		# searchs the vote form in question, if there are more then one on a wiki page
		if (!preg_match("/\(:input hidden votename\s*".$votename."/", $text))
			continue;
		
		$cookiename = $RyeVoteCookie.$votename;
		if (!isset ($_COOKIE[$cookiename]))
			setcookie($cookiename, "true", $RyeVoteExpires, $RyeVoteDir);
		elseif ($RyeVoteRestrictions)
			Redirect($pagename);

		# searchs for the label and values in the vote form
		preg_match_all("/\(:input radio ([^\\s]*?)\\s*?([^\\s]*?)\s*?:\)(.*?)(\n|\(:|\\\\)/", $text, $options);

        $dbname = ($_POST['db']) ? $_POST['db'] : $RyeVoteDBPName;
		$db = new PmWikiPageDB($dbname);
    	$data = $db->ReadData();
    	
    	if (!$data['ryevote'][$votename]) 
		{
		    for ($i = 0; $i<count($options[1]); $i++){
		        $data['ryevote'][$votename][$options[1][$i]]['setname'] = $_POST[$options[1][$i]."-name"];   
			    $data['ryevote'][$votename][$options[1][$i]][$options[2][$i]]['name'] = $options[3][$i];
			    $data['ryevote'][$votename][$options[1][$i]][$options[2][$i]]['value'] = 0;
			}
		}

        if ((strpos($data['ryevote'][$votename]['ipsvoted'],$_SERVER['REMOTE_ADDR']) != false))
	  	    Redirect($pagename);
    	elseif ($RyeVoteRestrictions)
            $data['ryevote'][$votename]['ipsvoted'] .= " {$_SERVER['REMOTE_ADDR']}, ";


        foreach ($_POST as $set => $id)
            if ($data['ryevote'][$votename][$set][$id]) 
                $data['ryevote'][$votename][$set][$id]['value'] +=1;
		
		$db->WriteData($data);	
	}
	if ($_POST['redirect']) $pagename = $_POST['redirect'];
	Redirect($pagename);
}


Markup('ryevotediagramm', '<split', "/\\(:ryevote\\s(.*?):\\)/e", "RyeVoteDrawDiagramm('$1')" );
/**
 * Handles the drawing of the votes.
 * 
 * @param string $args
 */
function RyeVoteDrawDiagramm($args) {
    global $RyeVoteDBPName;
	$out = "\n";
	
	$pargs = ParseArgs($args) ;
	$dbname = ($pargs['db']) ? $pargs['db'] : $RyeVoteDBPName;
	$db = new PmWikiPageDB($dbname);
	$data = $db->ReadData();
	if (!$data) return;
	foreach($data['ryevote'][$pargs['votename']] as $set => $id) {
	    if ($set == "ipsvoted") continue;
        $setnames = $names = $values = array();
        foreach($id as $k => $value){
            if ($k != "setname") {
                $values[] = $value['value'];
                $names[] = $value['name'];
            } else
                $setnames[$set] = $value;
        }

        # install your own fancy drawing code here
        # values ar in values[], names in names[] and headings in []setnames
        foreach($setnames as $set => $setname) {
    	    $out .= "<br/><br/>\n$setname";
        	if (($sum = array_sum($values)) != 0)
        	    $sum = 100 / $sum;
        	$out .= "%define=ryevotebox display=block bgcolor=silver color=silver%\n";
        	$out .= "(:table:)\n";
        	foreach ($names as $k => $v) {
        		$percentage = floor($values[$k] * $sum);
        		$upbound = $percentage * 4;
        		$out .= "(:cellnr:)".$names[$k]."\n(:cell:)%ryevotebox width=".$upbound."px%.\n";
        		$out .= "(:cell style=\"color:gray;\":) (".$values[$k]."/".$percentage."%)\n"; 
        	}
        	$out .= "(:tableend:) \n";
    	}
       
	}
	
	return $out;
}

class PmWikiPageDB {
    var $dbpname;
    var $sep = ' => ';
    
    function PmWikiPageDB($pagename) {
            $this->dbpname = $pagename;
    }
    
    function ReadData(){
        Lock(1);
        $page = ReadPage($this->dbpname, READPAGE_CURRENT);
        Lock(0);
        $data = $page['text'];
        $lines = explode("\n", $data);
        $stack = array();
        foreach($lines as $line){
            if (!preg_match("/^([#*]+)(.*)$/", $line, $match)) continue;
            if ($match[1]{0} == "#") {
                while (count($stack) >= strlen($match[1]))
                    array_pop($stack);
                array_push($stack, $match[2]);
                continue;
            } else {
                $p = '$out';
                foreach($stack as $st) $p .= "['$st']";
                $p .= str_replace($this->sep, "='", $match[2])."';";
                eval ($p);   
                array_pop($stack);
            }
        }
        return $out;
    }
    
    function WriteData($newdata, $mode = "w") {
        global $EnablePost, $Now;
        Lock(2);
        $page = ReadPage($this->dbpname);
        $new = $page;
        $new['text'] = $this->generateData($newdata);
        $new['time'] = $Now;
        $EnablePost = true;
        PostPage($this->dbpname, $page, $new);
        Lock(0);
    }
    
    function generateData($newdata, $depth = 0, $pre = "") {
        $depth ++;
         if ($depth < 5) $out .= str_repeat("!", $depth+1)." \n";
        foreach($newdata as $key => $value) 
            if (is_array($value)) {
                $out .= str_repeat("#",$depth)."$key\n";
                $out .= $this->generateData($value, $depth);
            }
            else {
                $out .= str_repeat("#",$depth)."$key\n";
                $out .= str_repeat("*",$depth+1)."$this->sep$value\n";     
            }
        return $out;
    }

}

?>