<?php
/**
* Poll Plugin: allows to create sligthly extended polls
*
* @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
* @author     Etienne MELEARD <etienne.meleard@cru.fr>
*/

if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/');
if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/');
require_once(DOKU_PLUGIN.'syntax.php');

/**
* All DokuWiki plugins to extend the parser/rendering mechanism
* need to inherit from this class
*/
class syntax_plugin_multipoll extends DokuWiki_Syntax_Plugin {

	/**
	* return some info
	*/
	function getInfo() {
		return confToHash(dirname(__FILE__).'/INFO');
	}

	function getType() { return 'substition';}
	function getPType() { return 'block';}
	function getSort() { return 167; }

	/**
	* Connect pattern to lexer
	*/
	function connectTo($mode) {
		$this->Lexer->addSpecialPattern('<multipoll.*?>.+?</multipoll>', $mode, 'plugin_multipoll');
	}

	/**
	* Handle the match
	*/
	function handle($match, $state, $pos, &$handler) {
		$match = substr($match, 11, -12);  // strip markup
		if(preg_match('`^\s*((hideresults|hideifvoted|showresultsto\=(\@?[a-z0-9_-]+,)*(\@?[a-z0-9_-]+))\s+)+\|`i', $match)) {
			$o = array_map('trim', explode(' ', substr($match, 0, strpos($match, '|'))));
			$opts = array();
			foreach($o as $v) {
				if(substr($v, 0, 14) == 'showresultsto=') {
					$k = 'showresultsto';
					$v = array_map('trim', explode(',', substr($v, 14)));
				}else{
					$k = $v;
					$v = true;
				}
				$opts[$k] = $v;
			}
			$match = substr($match, strpos($match, '|') + 1);
		}
		$title = substr($match, 0, strpos($match, '>'));
		$r = substr($match, strpos($match, '>') + 1);
		$questions = array();
		$q = array('q' => array(), 'a' => array(), 'm' => false);
		$lwq = true;
		foreach(explode("\n", $r) as $l) {
			if($lwq) {
				if(preg_match('`^\s\s([\+\*])\s(.+)$`', $l, $m)) {
					$lwq = false;
					$q['a'][] = $m[2];
					if($m[1] == '+') $q['m'] = true;
				}else $q['q'][] = $l;
			}else{
				if(preg_match('`^\s\s([\+\*])\s(.+)$`', $l, $m)) {
					$q['a'][] = $m[2];
					if($m[1] == '+') $q['m'] = true;
				}else{
					$lwq = true;
					$q['q'] = implode(' ', array_map('trim', $q['q']));
					$q['a'] = array_filter(array_map('trim', $q['a']), create_function('$e', 'return ($e["q"] != "");'));
					$questions[] = $q;
					$q = array('q' => array(), 'a' => array());
					$q['q'][] = $l;
				}
			}
		}
		
		if(count($questions) > 1) { // if more than 1 question => only keep questions with text
			$questions = array_filter($questions, create_function('$e', 'return ($e["q"] != "");'));
		}
		
		return array(trim($title), $questions, $opts);
	}

	/**
	* Create output
	*/
	function render($mode, &$renderer, $data) {
		if ($mode == 'xhtml') {
			global $ID;
			global $INFO;
			
			$opts = $data[2];
			$questions = $data[1];
			$title = $renderer->_xmlEntities($data[0]);
			
			$authedit = (auth_quickaclcheck($ID) >= AUTH_EDIT);
			$showresults = ((!isset($opts['hideifvoted']) && !isset($opts['hideresults'])) || $authedit);
			$showresultsextra = false;
			if(isset($opts['showresultsto']) && $_SERVER['REMOTE_USER']) {
				if(in_array($_SERVER['REMOTE_USER'], $opts['showresultsto'])) $showresultsextra = true;
				foreach($INFO['userinfo']['grps'] as $g) {
					if(in_array('@'.$g, $opts['showresultsto'])) $showresultsextra = true;
				}
			}
			$showalreadyvoted = (isset($opts['hideresults']) && !$authedit);
			
			// prevent caching to ensure the poll results are fresh
			$renderer->info['cache'] = false;
			
			// get poll file contents
			$pfile = metaFN(md5($title), '.multipoll');
			$poll = unserialize(@file_get_contents($pfile));
			
			if(!isset($poll['results'])) $poll['results'] = array();
			if(!isset($poll['votes'])) $poll['votes'] = 0;
			if(!isset($poll['ips'])) $poll['ips'] = array();
			if(!isset($poll['users'])) $poll['users'] = array();
			
			$ip = clientIP(true);
			$voted = false;
			
			// just voted
			if(isset($_POST['multipoll_vote'])) {
				$save = false;
				foreach($_POST as $k => $v) {
					if(preg_match('`^multipoll_question_([0-9]+)$`', $k, $m)) {
						$q = (int)$m[1];
						if(!isset($questions[$q])) continue;
						if(!isset($poll['results'][$q])) $poll['results'][$q] = array();
						if($questions[$q]['m']) {
							if(!is_array($v)) $v = array($v);
							foreach($v as $ans) {
								if(!isset($poll['results'][$q][$ans])) $poll['results'][$q][$ans] = 0;
								$poll['results'][$q][$ans]++;
							}
						}else{
							if(is_array($v)) $v = array_shift($v);
							if(!isset($poll['results'][$q][$v])) $poll['results'][$q][$v] = 0;
							$poll['results'][$q][$v]++;
						}
						$save = true;
					}
				}
				if($save) {
					$poll['votes']++;
					$poll['ips'][] = $ip;
					if($_SERVER['REMOTE_USER']) $poll['users'][] = $_SERVER['REMOTE_USER'];
					if($fh = fopen($pfile, 'w')) {
						fwrite($fh, serialize($poll));
						fclose($fh);
					}
					$voted = true;
				}
			}elseif(in_array($ip, $poll['ips']) || ($_SERVER['REMOTE_USER'] && in_array($_SERVER['REMOTE_USER'], $poll['users']))) {
				$voted = true;
			}
			
			if(!$voted || $showresults || $showresultsextra || $showalreadyvoted) {
				$renderer->doc .= '<fieldset class="multipoll">'."\n".'<legend>'.$title.'</legend>';
				if(!$voted) $renderer->doc .= $this->_pollForm($questions, $renderer);
				
				if($voted && $showalreadyvoted) {
					$renderer->doc .= $this->getLang('already_voted');
				}
				
				if(($voted && $showresults) || $showresultsextra) {
					$renderer->doc .= $this->_pollResults($questions, $poll, $renderer);
				}
				$renderer->doc .= '</fieldset>';
			}
			
			return true;
		}
		return false;
	}

	function _pollResults($questions, $poll, &$renderer) {
		if($poll['votes'] == 0) return '';
		
		$q = 0;
		foreach($questions as $question) {
			$ret .= '	<div class="multipoll_question" id="poll_question_'.$q.'">'.$renderer->_xmlEntities($question['q']).'</div>'."\n";
			$ret .= '	<table class="blind">'."\n";
			foreach($question['a'] as $a) {
				$ret .= '		<tr>'."\n";
				$a = $renderer->_xmlEntities($a);
				$s = isset($poll['results'][$q]) ? (isset($poll['results'][$q][$a]) ? $poll['results'][$q][$a] : 0) : 0;
				$pct = sprintf('%3.1f', 100 * $s / $poll['votes']);
				$ret .= '			<td>'.$a.'</td>'."\n";
				$ret .= '			<td><div class="multipoll_bar">'.($s ? '<div class="multipoll_full" style="width:'.($pct * 2).'px">&nbsp;</div>' : '').'</div></td>'."\n";
				$ret .= '			<td class="rightalign">'.$pct.'% ('.$s.')</td>'."\n";
				$ret .= '		</tr>'."\n";
			}
			$ret .= '	</table>'."\n";
			$ret .= '	<br />'."\n";
			$q++;
		}
		return $ret;
	}

	function _pollForm($questions, &$renderer) {
		global $lang;
		global $ID;
		
		$ret = '<form id="multipoll__form" method="post" action="'.script().'" accept-charset="'.$lang['encoding'].'">'."\n";
		$ret .= '	<div class="no">'."\n";
		$ret .= '		<input type="hidden" name="do" value="show" />'."\n";
		$ret .= '		<input type="hidden" name="id" value="'.$ID.'" />'."\n";
		$ret .= '	</div>'."\n";
		
		$qret = array();
		$q = 0;
		foreach($questions as $question) {
			$ret .= '	<div class="multipoll_question" id="multipoll_question_'.$q.'">'.$renderer->_xmlEntities($question['q']).'</div>'."\n";
			foreach($question['a'] as $a) {
				$a = $renderer->_xmlEntities($a);
				if($question['m']) {
					$ret .= '	<input type="checkbox" name="multipoll_question_'.$q.'[]" value="'.$a.'" /> <span>'.$a.'</span><br />'."\n";
				}else $ret .= '	<input type="radio" name="multipoll_question_'.$q.'" value="'.$a.'" /> <span>'.$a.'</span><br />'."\n";
			}
			$ret .= '	<hr />'."\n";
			$q++;
		}
		$ret .= '	<input class="button" type="submit" name="multipoll_vote" value="'.$this->getLang('btn_vote').'" />'."\n";
		$ret .= '</form>'."\n";

		return $ret;
	}
}
