<?php

// version 1.0  First release

class quiz {
//  Quiz plugin for Dokuwiki
//  Copyright (C) 2010  Luigi Micco
//  based on osQuest5 PHP/XML based Quiz software (and associated Text to XML module)
//  Copyright (C) 2009  Jon-Michael C. Brook
//  based on osQuest4 PHP/XML based Quiz software (and associated Text to XML module)
//  Copyright (C) 2007  Jay Banks
//
//  These program are free software: you can redistribute them and/or modify
//  them under the terms of the GNU Affero General Public License as
//  published by the Free Software Foundation, either version 3 of the
//  License, or (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU Affero General Public License for more details.
//
//  A copy of the GNU Affero General Public License is provided below
//  and it applies to all programs in this archive.
//  See also: <http://www.gnu.org/licenses/> or
//  http://www.fsf.org/licensing/licenses/agpl-3.0.html.
//
//

    // change below values to adjust preferences
    //

    var $quizID;
    var $mode;
    var $rndquest;
    var $rndchoice;
    var $highscore;
    var $showintro;
    var $current_question = 1;
    var $error = '';

    var $in_question = 0;
    var $in_section = '';

    var $parseQuiz_cache = null;
    var $quizobj;

    function quiz($quizID, &$param) {
      $this->quizID = $quizID;
      $this->mode = $param['learning'];
      $this->rndquest = $param['rndquest'];
      $this->rndchoice = $param['rndchoice'];
      $this->highscore = $param['highscores'];
      $this->showintro = $param['showintro'];
      
      $this->quizobj = plugin_load('syntax','quiz');

      if (!($this->mode < 0 || $this->mode > 1 )) {
        $this->error = 'Error: "' . $this->mode .'" is not a valid quiz mode. Valid modes are "test (0)" and "learning (1)"';
      }
    }
    
    function do_quiz_here() {
      if (isset($_POST['next_question'])) {
        $next = $_POST['next_question']; // + 1;
        if ((!isset($_POST['answers'][$next - 1])) && ($next > 1)) { $next = $next - 1; }
      } else {
        unset($_POST);
        $next = 0;
      }
      return $this->print_question($next);
    }
    
    function print_question($question_num) {
  
      $html = "";
      $question_num = (int)$question_num;
      $data = $this->parseQuiz();
      if ($data !== false) {
        $a = $data['questions'][$question_num];
        $count_a = count($data['questions']);

        if ($question_num <= $count_a) {
          if ($question_num <= 0)  {
            $html .= '<h1>'.$data['title'].'</h1>';
            
            $html .= $data['intro'];
            if (($question_num != 0) && ($this->highscore )) $html .= $this->print_highscore();  
            
            $html .= '<div class="quiz-block" id="quiz-form__'.$this->quizID.'">';
          } else {
            $html .= '<h1>'.$data['title'].' - '.$question_num.'/'.$count_a.'</h1>';
            if ($this->showintro) $html .= $data['intro'];
            $html .= '<div class="quiz-block" id="quiz-form__'.$this->quizID.'">';
            $html .= '<div class="quiz-question">'.$a['question'].'</div>';
          }
          
          $html .= '<form action="getform.php" method="post" onsubmit="plgQuiz_send(\''.$this->quizID.'\'); return false;">';
          $html .= '<input type="hidden" name="quiz_id" value="' . $this->quizID. '">' . "\n";
          $html .= '<input type="hidden" name="quiz_learning" value="' . $this->mode. '">' . "\n";
          $html .= '<input type="hidden" name="quiz_showintro" value="' . $this->showintro. '">' . "\n";
          $html .= '<input type="hidden" name="quiz_rndquest" value="' . $this->rndquest. '">' . "\n";
          $html .= '<input type="hidden" name="quiz_rndchoice" value="' . $this->rndchoice. '">' . "\n";
          $html .= '<input type="hidden" name="quiz_highscore" value="' . $this->highscore. '">' . "\n";
          
          if ($question_num <= 0)  {
            $html .= '<div class="quiz-button">';
            $html .= '<button class="button" type="submit" onClick="plgQuiz_send(\''.$this->quizID.'\',1); return false;" > '.$this->quizobj->getLang('quiz_start').' </button>';
            
            if (($question_num == 0) && ($this->highscore )) {
              $html .= '<button class="button" type="submit" onClick="plgQuiz_send(\''.$this->quizID.'\',-1); return false;" > '.$this->quizobj->getLang('quiz_highscore').' </button>';
            }  
            
            $html .= '</div>';
            $html .= '</form>';
            $html .= '</div>';
          
          } else {
          
            $html .= '<div class="quiz-choice">';
            
            // se si torna alla domanda precedente, cancella i dati doppi
            $temp = $_POST['answers'][$question_num];
            if (isset($_POST['prev'])) {
              unset($_POST['answers'][$question_num]);
            }
            //
            
            // se presenti, aggiunge in POST i dati delle risposte precedenti
            if (isset($_POST) && isset($_POST['answers'])) {
              foreach ($_POST['answers'] as $key => $value) {
                if (!is_array($value)) {
                  $html .= '<input type="hidden" name="answers[' . $key . ']" value="' . $value .'">' . "\n";
                } else {
                  foreach ($value as $literal_key => $valueison) {
                    $html .= '<input type="hidden" name="answers[' . $key . '][' . $literal_key .']" value="on">' . "\n";
                  }
                }
              }
            }
            // 
            
            if ($a['type'] == 'single') {
              for($n=1; $n<=count($a['choices']); $n++) {
                $state = '';
                if ($temp == $n) $state = ' checked';
                $html .= '<input '.$state.' type="radio" name="answers[' . $question_num . ']" id="'.$n.'" value="'.$n.'">&nbsp;<label for="' . $n .
                    '">' . $a['choices'][$n]['text'] . '</label><br>' . "\n";
              } 
            } else {
              if ($a['type'] == 'text') {
                $html .= '<input type="text" name="answers[' . $question_num .
                    ']" value="'.$temp.'" size="50"><br>' . "\n";
              } else {
                if ($a['type'] == 'multi') {
                  for($n=1; $n<=count($a['choices']); $n++) {
                    $state = '';
                    if (isset($temp[$n]) && ($temp[$n] =='on')) $state = ' checked';
                    $html .='<input '.$state.' type="checkbox" id="answers[' . $question_num . '][' . $n . ']" name="answers[' . $question_num . '][' . $n .']">
                    &nbsp;<label for="answers[' . $question_num . '][' . $n . ']">' . $a['choices'][$n]['text'] .
                        '</label><br>' . "\n";
                  }
                }
              }
            }  
            $html .= '</div>';
            $html .= '<div class="quiz-button">';
            if ($question_num > 1) {
              $html .= '<button class="button" name="next_question" value="'.($question_num-1).'" type="submit" onClick="plgQuiz_send(\''.$this->quizID.'\','.($question_num-1).'); return false;" > '.$this->quizobj->getLang('quiz_prevquest').' </button>';
            }   
            $html .= '<button class="button" name="next_question" value="'.($question_num+1).'" type="submit" onClick="plgQuiz_send(\''.$this->quizID.'\','.($question_num+1).'); return false;"> ' .  $this->quizobj->getLang(($count_a == $question_num ?'quiz_finish':'quiz_nextquest')) . ' </button>';
            $html .= '</form>';
            $html .= '</div>';
            $html .= '</div>';
          }
        } else {
        
          // mostra le risposte giuste
          //display test results
          $total_answers = count($_POST['answers']);
          $total_correct_answers = 0;
          $total_score = 0;
          foreach ($_POST['answers'] as $_question_num => $_users_answer) {
            if ($this->checkanswer($_question_num)) {
              $total_correct_answers++;
              $total_score = $total_score + $data['questions'][$_question_num]['score'];
            }
          }

          $html .= '<h1>'.$data['title'].' - '.$this->quizobj->getLang('quiz_result').'</h1>';
          if ($this->showintro) $html .= $data['intro'];
          $html .= '<div class="quiz-block">';
          $html .= '<div class="quiz-result">';
          $percent = round(($total_correct_answers / $total_answers) * 100, 2);
          $html .= sprintf($this->quizobj->getLang('quiz_resulttext'), $total_correct_answers, $total_answers, $percent);
          $html .= '<br>';
          $html .= $this->quizobj->getLang('quiz_score').$total_score . '<br>';
          $html .= '</div>';
          
          // descrizione del risultato per scaglioni
          if ($data['scores']) {
            foreach ($data['scores'] as $scores) {
              if (($total_score >= $scores['range'][0]) && ($total_score <= $scores['range'][1])) {
                $html .= '<div class="quiz-report">';
                $html .= $scores['text'];
                $html .= '</div>';
              }
            }
          }
          
          $html .= '<div class="quiz-button">';
          $html .= '<form action="" method="post">';
          $html .= '<BUTTON class="button" name="again" type="submit" > '.$this->quizobj->getLang('quiz_tryagain').' </BUTTON>';
          $html .= '</form>';
          $html .= '</div>';


          if ($this->mode == 1 && $question_num > 1) {
            $html .= "<hr>";
            for ($i = 1; $i <= $count_a; $i++) {
              $html .= $this->learning_mode_print_answer($i );
            }
          }
          
          $scorelist = $this->updateScore($total_score, $percent);
          $html .= '</div>';
        }
      } else {
        $html .= $this->quiz_error();
      }
      return $html;
    }
    
    function learning_mode_print_answer($question_num) {
      $ok = false;
      
      if ($this->checkanswer($question_num, &$answers))  {
        $ok = true;
        $div = "correct";
      } else {
        $div = "wrong";
      }      
      
      $a = $this->parseQuiz();
      $a = $a['questions'][$question_num];
      
      $html = "";

      $html .= '<div class="quiz-block">';
      $html .= '<div class="quiz-question">';
      $html .= '<div class="quiz-'.$div.'">';
      $html .=  $question_num.") ".$a['question']; //."&nbsp;".$img;
      $html .= '</div>';
      $html .= '</div>';
      $html .= '<div class="quiz-choice">';
      $html .= '<ul>';
      
      if ($a['type'] == 'text') {
        if (!$ok) 
          $html .= '<div class="quiz-wrong">'. $answers[1].'</div>';
        
        if (!$ok)
          $html .= '<div class="quiz-missing">'. $a['answers'][0] .'</div>';
        else
          $html .= '<div class="quiz-correct">'. $a['answers'][0] .'</div>'; 
      } else {
        for($n=1; $n<=count($a['choices']); $n++) {
        
          if (($answers[$n] == 1) && $a['choices'][$n]['correct']) {
            $div = "correct";
          } elseif (($answers[$n] == 1) && !$a['choices'][$n]['correct']) {
            $div = "wrong";
          } elseif (($answers[$n] == 0) && $a['choices'][$n]['correct']) {
            $div = "missing";
          } else {
            $div = "";
          }
          
          $html .= '<div class="quiz-'.$div.'">';
          $html .= '<li class="level1">'.$a['choices'][$n]['text'].'</li>';
          $html .= '</div>' . "\n";
        }
      }
      $html .= '</ul>';
      
      if ($a['explanation'] != '') {
        $html .= '<hr><b>'.$this->quizobj->getLang('quiz_explanation').'</b><br>' . $a['explanation'].'';
      }  
      $html .= '</div>';
      $html .= '</div>';
      return $html ;  
    }
    
    function checkanswer($question, $answer_array = null) {
      $result = false;
      if ($this->parseQuiz() !== false && $question > 0) {
        $data = $this->parseQuiz();
        $a = $data['questions'][$question];
       
        $your_answer = '';
        $correct_answer = '';
        if ($a['type'] == 'single') {
          $your_answer = $_POST['answers'][$question];
          for($n=1; $n<=count($a['choices']); $n++) {
            $answer_array[$n] = ($n == $your_answer?1:0);
          }
          $result = $a['choices'][$your_answer]['correct'];
          
        } else {
          if ($a['type'] == 'text') {
            $your_answer = $_POST['answers'][$question];
            $answer_array[1] = $your_answer;
            $result = (strtolower($your_answer) == strtolower($a['answers'][0]));

          } else {
            if ($a['type'] == 'multi') {
              $your_answers = $_POST['answers'][$question];
              ksort($your_answers);
              
              $result = true;
              for($n=1; $n<=count($a['choices']); $n++) {
                $answer_array[$n] = (isset($your_answers[$n])? 1:0);
                if ( (($answer_array[$n] == 1) && !$a['choices'][$n]['correct']) || 
                     (($answer_array[$n] == 0) && $a['choices'][$n]['correct']) ) {
                  $result = false;
                }     
              }
            }
          }
        }
      }
      return $result;
    }
   
    function quiz_error() {
      return $this->error;
    }
    
    
    function parseQuiz() {
      if ($this->parseQuiz_cache === null) {
        $page = $this->quizID;
        $quizz = array();
        $pos = strrpos(utf8_decode($page), ':');
        $pageName = p_get_first_heading($page);
        if($pageName == NULL) {
          if($pos != FALSE) {
            $pageName = utf8_substr($page, $pos+1, utf8_strlen($page));
          } else {
            $pageName = $page;
          }
          $pageName = str_replace('_', ' ', $pageName);
        }    
        $quizz['title'] = $pageName;
        $select= rawWiki($page);
        $lines = explode("\n", $select);
        $nr = count($lines);
        
        $hRender = new Doku_Renderer_xhtml();  

        $nquest = 0;
        $quizz['questions'] = array();
        
        for($n=0; $n<$nr; $n++) {

          if (substr($lines[$n], 0, 6) == "======") continue;
          
          if (substr($lines[$n], 0, 5) == "=====") {
            $temp = str_replace("=====",'',$lines[$n]);
            $tmp_array = array();            
            $tmp_array['range']= explode("-", $temp);
            for($k=$n+1; $k<$nr; $k++) {
              if ((trim($lines[$k]) == '') || (substr($lines[$k], 0, 5) != "====="))  {
                $tmp_array['text'] .= $lines[$k]."\n";
              } else {
                $n = $k - 1;
                $k = $nr + 1;
              } 
            };
            $tmp_array['text'] = $hRender->render($tmp_array['text']);
            $quizz['scores'][]= $tmp_array;
            
          };
          
          if ((trim($lines[$n]) == '') || (substr($lines[$n], 0, 4) != "  * "))  {
            if ($nquest == 0) $quizz['intro'] .= $lines[$n]."\n";
            continue;
          }
          
          
          
          $nquest++;;
          $tmp = $hRender->render(str_replace("  * ",'',$lines[$n]));
          $tmp = substr($tmp, 4);
          $tmp = substr($tmp, 0, -5);
          $quizz['questions'][$nquest]['question'] = $tmp;

          $nchoices = 0;
          $quizz['questions'][$nquest]['choices'] = array();
          $quizz['questions'][$nquest]['answers'] = array();
          $quizz['questions'][$nquest]['score']= 1;
          $quizz['questions'][$nquest]['explanation'] = '';
          
          $temp_choices = array();
          for($k=$n+1; $k<$nr; $k++) {
            if (trim($lines[$k]) == '') continue;
            if (substr($lines[$k], 0, 6) == "    - ") { 
              $nchoices++;
              $tmp = $hRender->render(str_replace("    - ",'',$lines[$k]));
              $tmp = substr($tmp, 4);
              $tmp = substr($tmp, 0, -5);
              
              $quizz['questions'][$nquest]['choices'][$nchoices]['text'] = $tmp;
              $quizz['questions'][$nquest]['choices'][$nchoices]['correct'] = false;
              
            } elseif (substr($lines[$k], 0, 7) == "    * [") { 
              $temp = str_replace("    * [",'',$lines[$k]);
              $temp = ereg_replace("].*", "", $temp);

              $quizz['questions'][$nquest]['answers'] = explode("|", $temp);
              sort($quizz['questions'][$nquest]['answers']);
          
              for($i=0; $i<count($quizz['questions'][$nquest]['answers']); $i++) {
                if (isset($quizz['questions'][$nquest]['choices'][$quizz['questions'][$nquest]['answers'][$i]]['text'])) {
                  $quizz['questions'][$nquest]['choices'][$quizz['questions'][$nquest]['answers'][$i]]['correct'] = true;
                }
              }
              
            } elseif (substr($lines[$k], 0, 7) == "    * (") { 
              $temp = str_replace("    * (",'',$lines[$k]);
              $temp = ereg_replace(").*", "", $temp);

              $quizz['questions'][$nquest]['score']= $temp;
              
            } elseif (substr($lines[$k], 0, 6) == "    * ") { 
              $tmp = $hRender->render(str_replace("    * ",'',$lines[$k]));
              $tmp = substr($tmp, 4);
              $tmp = substr($tmp, 0, -5);

              $quizz['questions'][$nquest]['explanation'] = $tmp;
            } else {
              $n = $k - 1;
              $k = $nr + 1;
            } 
          }
                 
          if ($this->rndchoice) $this->kshuffle($quizz['questions'][$nquest]['choices']);
          
          if (count($quizz['questions'][$nquest]['choices']) == 0) {
            $quizz['questions'][$nquest]['type'] = 'text';
          } elseif (count($quizz['questions'][$nquest]['answers']) > 1) {
            $quizz['questions'][$nquest]['type'] = 'multi';
          } else {
            $quizz['questions'][$nquest]['type'] = 'single';
          }
          
        }

        if ($this->rndquest) $this->kshuffle($quizz['questions']);
        $quizz['intro'] = $hRender->render($quizz['intro']);


        $this->parseQuiz_cache = $quizz;
      }
      return $this->parseQuiz_cache;
      
    }

    // sequenza casuale, fissa per sessione
    function kshuffle(&$items) { 
      $temp = $items;
      srand(hexdec(session_id()));
      shuffle($temp);
      for($k=1; $k<=count($temp); $k++) {
        $items[$k] = $temp[$k-1];
      }     
    } 

    // visualizza i migliori 10 punteggi
    function print_highscore() { 
			// get score file contents
			$pfile = metaFN(md5($this->quizID), '.quiz');
			$scorelist = unserialize(@file_get_contents($pfile));

      $temp = $scorelist['rows'];
      usort($temp, array($this,'cmp'));
      $temp = array_slice($temp, 0, 10);

      $html = "";
      $html .= '<h2>10 '.$this->quizobj->getLang('quiz_highscore').' ('.$scorelist['total'].')</h2><br>';
      
      $html .= '<table class="inline">';
      $html .= '<tr class="row0">';
      $html .= '<th class="col0 centeralign">  User  </th>
                <th class="col1 centeralign">  IP  </th>
                <th class="col2 centeralign">  Score </th>
                <th class="col3 centeralign">  %  </th>
                <th class="col3 centeralign">  Date  </th>';
	    $html .= '</tr>';
      foreach ($temp as $row) {
        $html .= "<tr>";
        $html .= '<td class="col0">'.$row['user'].'</td>';
        $html .= '<td class="col1">'.$row['ip'].'</td>';
        $html .= '<td class="col2">'.$row['score'].'</td>';
        $html .= '<td class="col3">'.$row['percent'].'</td>';
        $html .= '<td class="col3">'.dformat($row['timestamp']).'</td>';
        $html .= "</tr>";
      }

      $html .= "</table>";

      return $html;
    }

    // Comparison function
    function cmp($a, $b) {
        if ($a['score'] == $b['score']) {
            return 0;
        }
        return ($a['score'] > $b['score']) ? -1 : 1;
    }

    // aggiorna il file dei risultati
    function updateScore($userscore, $percent) { 
    
			// get score file contents
			$pfile = metaFN(md5($this->quizID), '.quiz');
			$score = unserialize(@file_get_contents($pfile));
			
			if(!isset($score['total'])) $score['total'] = 0;
			if(!isset($score['rows'])) {
        $score['rows'] = array();
      }
      
			if(!isset($score['ips'])) $score['ips'] = array();
			if(!isset($score['users'])) $score['users'] = array();    

			$ip = clientIP(true);

      $score['total']++;
      $tmp = '(anonymous)';
      if($_SERVER['REMOTE_USER']) $tmp = $_SERVER['REMOTE_USER'];
      $score['users'][] =$tmp;
      $score['ips'][] = $ip;
      
      $score['rows'][$score['total']]['percent'] = $percent;
      $score['rows'][$score['total']]['score'] = $userscore;
      $score['rows'][$score['total']]['user'] = $tmp;
      $score['rows'][$score['total']]['ip'] = $ip;
      $score['rows'][$score['total']]['timestamp'] = time();
      
      if($fh = fopen($pfile, 'w')) {
        fwrite($fh, serialize($score));
        fclose($fh);
      }
      return $score;
    }

    
}

?>

