<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * This file plays the game hangman.
 *
 * @package    mod_game
 * @copyright  2007 Vasilis Daloukas
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

/**
 * Plays the game hangman
 *
 * @param stdClass $cm
 * @param stdClass $game
 * @param stdClass $attempt
 * @param stdClass $hangman
 * @param string $newletter
 * @param string $action
 * @param stdClass $context
 * @param stdClass $course
 */
function game_hangman_continue($cm, $game, $attempt, $hangman, $newletter, $action, $context, $course) {
    global $DB, $USER;

    if ($attempt != false && $hangman != false) {
        if (($action == 'nextword') && ($hangman->finishedword != 0)) {
            // Finish with one word and continue to another.
            if (!$DB->set_field('game_hangman', 'finishedword', 0, ['id' => $hangman->id])) {
                error("game_hangman_continue: Can't update game_hangman");
            }
        } else {
            return game_hangman_play($cm, $game, $attempt, $hangman, false, false, $context, $course, $cm);
        }
    }

    $updatehangman = (($attempt != false) && ($hangman != false));

    // New game.
    // I try 10 times to find a new question.
    $found = false;
    $minnum = 0;
    $unchanged = 0;
    for ($i = 1; $i <= 10; $i++) {
        $rec = game_question_shortanswer($game, $game->param7, false);
        if ($rec === false) {
            continue;
        }

        $answer = game_upper($rec->answertext, $game->language);
        if ($game->language == '') {
            $game->language = game_detectlanguage($answer);
            $answer = game_upper($rec->answertext, $game->language);
        }

        $answer2 = $answer;
        if ($game->param7) {
            // Have to delete space.
            $answer2 = str_replace(' ', '', $answer2);
        }

        if ($game->param8) {
            // Have to delete -.
            $answer2 = str_replace('-', '', $answer2);
        }

        $allletters = game_getallletters($answer2, $game->language, $game->userlanguage);

        if ($allletters == '') {
            continue;
        }

        if ($game->param7) {
            $allletters .= '_';
        }

        if ($game->param8) {
            $allletters .= '-';
        }

        if ($game->param7 == false) {
            // I don't allow spaces.
            if (strpos($answer, " ")) {
                continue;
            }
        }

        $copy = false;
        $select2 = 'gameid=? AND userid=? AND questionid=? AND glossaryentryid=?';
        $rec2 = $DB->get_record_select(
            'game_repetitions',
            $select2,
            [$game->id, $USER->id, $rec->questionid, $rec->glossaryentryid],
            'id,repetitions AS r'
        );
        if ($rec2 != false) {
            if (($rec2->r < $minnum) || ($minnum == 0)) {
                $minnum = $rec2->r;
                $copy = true;
            }
        } else {
            $minnum = 0;
            $copy = true;
        }

        if ($copy) {
            $found = true;

            $min = new stdClass();
            $min->questionid = $rec->questionid;
            $min->glossaryentryid = $rec->glossaryentryid;
            $min->attachment = $rec->attachment;
            $min->questiontext = $rec->questiontext;
            $min->answerid = $rec->answerid;
            $min->answer = $answer;
            $min->language = $game->language;
            $min->allletters = $allletters;
            if ($minnum == 0) {
                break;  // We found an unused word.
            }
        } else {
            $unchanged++;
        }

        if ($unchanged > 2) {
            if ($found) {
                break;
            }
        }
    }

    if ($found == false) {
        throw new moodle_exception('no_words', 'game');
    }

    // Found one word for hangman.
    if ($attempt == false) {
        $attempt = game_addattempt($game);
    }

    if (!$DB->set_field('game_attempts', 'language', $min->language, ['id' => $attempt->id])) {
        throw new moodle_exception('hangman_error', 'game', 'game_hangman_continue: Can\'t set language');
    }

    $query = new stdClass();
    $query->attemptid = $attempt->id;
    $query->gamekind = $game->gamekind;
    $query->gameid = $game->id;
    $query->userid = $USER->id;
    $query->sourcemodule = $game->sourcemodule;
    $query->questionid = $min->questionid;
    $query->glossaryentryid = $min->glossaryentryid;
    $query->attachment = $min->attachment;
    $query->questiontext = $min->questiontext;
    $query->score = 0;
    $query->timelastattempt = time();
    $query->answertext = $min->answer;
    $query->answerid = $min->answerid;
    if (!($query->id = $DB->insert_record('game_queries', $query))) {
        throw new moodle_exception('hangman_error', 'game', 'game_hangman_continue: Can\'t insert to table game_queries');
    }

    $newrec = new stdClass();
    $newrec->id = $attempt->id;
    $newrec->queryid = $query->id;
    if ($updatehangman == false) {
        $newrec->maxtries = $game->param4;
        if ($newrec->maxtries == 0) {
            $newrec->maxtries = 1;
        }
        $newrec->finishedword = 0;
        $newrec->corrects = 0;
    }

    $newrec->allletters = $min->allletters;

    $letters = '';
    if ($game->param1) {
        $letters .= game_substr($min->answer, 0, 1);
    }

    if ($game->param2) {
        $letters .= game_substr($min->answer, -1, 1);
    }
    $newrec->letters = $letters;

    if ($updatehangman == false) {
        if (!game_insert_record('game_hangman', $newrec)) {
            throw new moodle_exception('hangman_error', 'game', 'game_hangman_continue: error inserting in game_hangman');
        }
    } else {
        if (!$DB->update_record('game_hangman', $newrec)) {
            throw new moodle_exception('hangman_error', 'game', 'game_hangman_continue: error updating in game_hangman');
        }
        $newrec = $DB->get_record('game_hangman', ['id' => $newrec->id]);
    }

    game_update_repetitions($game->id, $USER->id, $query->questionid, $query->glossaryentryid);

    game_hangman_play($cm, $game, $attempt, $newrec, false, false, $context, $course);
}

/**
 * On finish game.
 *
 * @param stdClass $cm
 * @param stdClass $game
 * @param stdClass $attempt
 * @param stdClass $hangman
 * @param stdClass $course
 */
function game_hangman_onfinishgame($cm, $game, $attempt, $hangman, $course) {
    global $DB;

    $score = $hangman->corrects / $hangman->maxtries;

    game_updateattempts($game, $attempt, $score, true, $cm, $course);

    if (!$DB->set_field('game_hangman', 'finishedword', 0, ['id' => $hangman->id])) {
        throw new moodle_exception('hangman_error', 'game', 'game_hangman_onfinishgame: Can\'t update game_hangman');
    }
}

/**
 * Plays the hangman game.
 *
 * @param stdClass $cm
 * @param stdClass $game
 * @param stdClass $attempt
 * @param stdClass $hangman
 * @param boolean $onlyshow
 * @param boolean $showsolution
 * @param stdClass $context
 * @param stdClass $course
 */
function game_hangman_play($cm, $game, $attempt, $hangman, $onlyshow, $showsolution, $context, $course) {
    global $DB;

    $query = $DB->get_record('game_queries', ['id' => $hangman->queryid]);

    if ($attempt->language != '') {
        $wordrtl = game_right_to_left($attempt->language);
    } else {
        $wordrtl = right_to_left();
    }
    $reverseprint = ($wordrtl != right_to_left());

    if ($game->toptext != '') {
        echo $game->toptext . '<br>';
    }

    $max = $game->param10;  // Maximum number of wrongs.
    if ($max <= 0) {
        $max = 6;
    }
    hangman_showpage(
        $done,
        $correct,
        $wrong,
        $max,
        $wordline,
        $wordline2,
        $links,
        $game,
        $attempt,
        $hangman,
        $query,
        $onlyshow,
        $showsolution,
        $context,
        $course,
        $cm
    );

    if (!$done) {
        if ($wrong > $max) {
            $wrong = $max;
        }
        if ($game->param3 == 0) {
            $game->param3 = 1;
        }
        echo "\r\n<br/><img src=\"" . game_pix_url('hangman/' . $game->param3 . '/hangman_' . $wrong, 'mod_game') . "\"";
        $message = sprintf(get_string('hangman_wrongnum', 'game'), $wrong, $max);
        echo ' ALIGN="MIDDLE" BORDER="0" HEIGHT="100" alt="' . $message . '"/>';

        if ($wrong >= $max) {
            // This word is incorrect. If reach the max number of word I have to finish else continue with next word.
            hangman_onincorrect(
                $cm,
                $wordline,
                $query->answertext,
                $game,
                $attempt,
                $hangman,
                $onlyshow,
                $showsolution,
                $course,
                $wordline2
            );
        } else {
            $i = $max - $wrong;
            if ($i > 1) {
                echo ' ' . get_string('hangman_restletters_many', 'game', $i);
            } else {
                echo ' ' . get_string('hangman_restletters_one', 'game');
            }
            if ($reverseprint) {
                echo '<SPAN dir="' . ($wordrtl ? 'rtl' : 'ltr') . '">';
            }

            echo "<br/><font size=\"5\">\n$wordline</font>\r\n";
            if ($wordline2 != '') {
                echo "<br/><font size=\"5\">\n$wordline2</font>\r\n";
            }

            if ($reverseprint) {
                echo "</SPAN>";
            }

            if ($hangman->finishedword == false) {
                echo "<br/><br/><BR/>" . get_string('hangman_letters', 'game') . ' ' . $links . "\r\n";
            }
        }
    } else {
        // This word is correct. If reach the max number of word I have to finish else continue with next word.
        hangman_oncorrect($cm, $wordline, $game, $attempt, $hangman, $query, $course, $onlyshow, $showsolution);
    }

    echo "<br/><br/>" . get_string('grade', 'game') . ' : ' . round($query->percent * 100) . ' %';
    if ($hangman->maxtries > 1) {
        $percent = ($correct - $wrong / $max) / game_strlen($query->answertext);
        if ($done || $onlyshow || $showsolution) {
            $percent = 0;
        }
        $score = $hangman->corrects / $hangman->maxtries + $percent / $hangman->maxtries;
        echo '<br/><br/>' . get_string('hangman_gradeinstance', 'game') . ' : ' .
            round($score * 100) . ' %';
    }

    if ($game->bottomtext != '') {
        echo '<br><br>' . $game->bottomtext;
    }
}

/**
 * Shows page.
 *
 * @param boolean $done
 * @param boolean $correct
 * @param boolean $wrong
 * @param int $max
 * @param string $wordline
 * @param string $wordline2
 * @param array $links
 * @param stdClass $game
 * @param stdClass $attempt
 * @param stdClass $hangman
 * @param stdClass $query
 * @param boolean $onlyshow
 * @param boolean $showsolution
 * @param stdClass $context
 * @param stdClass $course
 * @param stdClass $cm
 */
function hangman_showpage(
    &$done,
    &$correct,
    &$wrong,
    $max,
    &$wordline,
    &$wordline2,
    &$links,
    $game,
    &$attempt,
    &$hangman,
    &$query,
    $onlyshow,
    $showsolution,
    $context,
    $course,
    $cm
) {
    global $CFG, $DB, $cm;

    $word = $query->answertext;

    $newletter = optional_param('newletter', "", PARAM_TEXT);
    $userplayed = $newletter != '';
    if ($newletter == '_') {
        $newletter = ' ';
    }

    $letters = $hangman->letters;
    if ($newletter != null) {
        if (game_strpos($letters, $newletter) === false) {
            $letters .= $newletter;
        }
    }

    $links = "";

    $alpha = $hangman->allletters;
    $wrong = 0;

    if ($query->questionid) {
        $questiontext = str_replace(["\'", '\"'], ["'", '"'], $query->questiontext);
        $query->questiontext = game_filterquestion($questiontext, $query->questionid, $context->id, $game->course);
    } else {
        $glossary = $DB->get_record_sql("SELECT id,course FROM {$CFG->prefix}glossary WHERE id={$game->glossaryid}");
        $cmglossary = get_coursemodule_from_instance('glossary', $game->glossaryid, $glossary->course);
        $contextglossary = game_get_context_module_instance($cmglossary->id);
        $query->questiontext = game_filterglossary(
            str_replace('\"', '"', $query->questiontext),
            $query->glossaryentryid,
            $contextglossary->id,
            $game->course
        );
    }

    if ($game->param5) {
        $s = trim(game_filtertext($query->questiontext, $game->course));
        if ($s != '.' && $s <> '') {
            echo "<br/><b>" . $s . '</b>';
        }
        if ($query->attachment != '') {
            $args = explode('/', $query->attachment);
            $sql = "SELECT id,mimetype,filesize,filename FROM {$CFG->prefix}files " .
            "WHERE component='mod_glossary' AND filearea='attachment' AND itemid =" . $args[2] .
            " ORDER BY filesize DESC LIMIT 1";
            $entry = $DB->get_record_sql($sql);
            if ($entry != null) {
                if (substr($entry->mimetype, 0, 6) == 'image/') {
                    $file = "{$CFG->wwwroot}/pluginfile.php/{$contextglossary->id}/mod_glossary/attachment/";
                    $file .= "{$query->glossaryentryid}/{$entry->filename}";
                    echo "<img src=\"$file\" />";
                }
            }
        }
        echo "<br/><br/>";
    }

    $wordline = $wordline2 = "";

    $len = game_strlen($word);

    $done = 1;
    $answer = '';
    $correct = 0;
    for ($x = 0; $x < $len; $x++) {
        $char = game_substr($word, $x, 1);

        if ($showsolution) {
            $wordline2 .= ($char == " " ? '&nbsp; ' : $char);
            $done = 0;
        }

        if (game_strpos($letters, $char) === false) {
            $wordline .= "_<font size=\"1\">&nbsp;</font>\r\n";
            $done = 0;
            $answer .= '_';
        } else {
            $wordline .= ($char == " " ? '&nbsp; ' : $char);
            $answer .= $char;
            $correct++;
        }
    }

    $lenalpha = game_strlen($alpha);
    $fontsize = 5;

    for ($c = 0; $c < $lenalpha; $c++) {
        $char = game_substr($alpha, $c, 1);

        if (game_strpos($letters, $char) === false) {
            // User doesn't select this character.
            $params = 'id=' . $cm->id . '&amp;newletter=' . urlencode($char);
            if ($onlyshow || $showsolution) {
                $links .= $char;
            } else {
                $links .= "<font size=\"$fontsize\"><a href=\"attempt.php?$params\">$char</a></font>\r\n";
            }
            continue;
        }

        if (game_strpos($word, $char) === false) {
            $links .= "\r\n<font size=\"$fontsize\" color=\"red\">$char </font>";
            $wrong++;
        } else {
            $links .= "\r\n<B><font size=\"$fontsize\">$char </font></B> ";
        }
    }
    $finishedword = ($done || $wrong >= $max);
    $finished = false;

    $updrec = new stdClass();
    $updrec->id = $hangman->id;
    $updrec->letters = $letters;
    if ($finishedword) {
        if ($hangman->finishedword == 0) {
            // Only one time per word increace the variable try.
            $hangman->try = $hangman->try + 1;
            if ($hangman->try > $hangman->maxtries) {
                $finished = true;
            }
            if ($done && !$onlyshow) {
                $hangman->corrects = $hangman->corrects + 1;
                $updrec->corrects = $hangman->corrects;
            }
        }

        $updrec->try = $hangman->try;
        $updrec->finishedword = 1;
    }

    $query->percent = ($correct - $wrong / $max) / game_strlen($word);
    if ($query->percent < 0) {
        $query->percent = 0;
    }

    if ($onlyshow || $showsolution) {
        return;
    }

    if (!$DB->update_record('game_hangman', $updrec)) {
        throw new moodle_exception('hangman_error', 'game', "hangman_showpage: Can't update game_hangman id=$updrec->id");
    }

    if ($done) {
        $score = 1;
    } else if ($wrong >= $max) {
        $score = 0;
    } else {
        $score = -1;
    }
    if ($hangman->maxtries > 0) {
        $percent = ($correct - $wrong / $max) / game_strlen($word);
        $score = $hangman->corrects / $hangman->maxtries + $percent / $hangman->maxtries;
    }
    if ($userplayed) {
        game_updateattempts($game, $attempt, $score, $finished, $cm, $course);
    }
    game_update_queries($game, $attempt, $query, $score, $answer);
}

/**
 * This word is correct. If reach the max number of words I have to finish else continue with next word.
 *
 * @param stdClass $cm
 * @param string $wordline
 * @param stdClass $game
 * @param stdClass $attempt
 * @param stdClass $hangman
 * @param stdClass $query
 * @param stdClass $course
 * @param boolean $onlyshow
 * @param boolean $showsolution
 */
function hangman_oncorrect($cm, $wordline, $game, $attempt, $hangman, $query, $course, $onlyshow, $showsolution) {
    global $DB;

    echo "<br/><br/><font size=\"5\">\n$wordline</font>\r\n";

    echo '<p><br/><font size="5" color="green">' . get_string('win', 'game') . '</font><BR/><BR/></p>';
    if ($query->answerid) {
        $feedback = $DB->get_field('question_answers', 'feedback', ['id' => $query->answerid]);
        if ($feedback != '') {
            echo "$feedback<br>";
        }
    }

    if ($onlyshow || $showsolution) {
        return;
    }

    game_hangman_show_nextword($cm, $game, $attempt, $hangman, $course);
}

/**
 * On incorrect.
 *
 * @param stdClass $cm
 * @param string $wordline
 * @param string $word
 * @param stdClass $game
 * @param stdClass $attempt
 * @param stdClass $hangman
 * @param boolean $onlyshow
 * @param boolean $showsolution
 * @param stdClass $course
 * @param string $wordline2
 */
function hangman_onincorrect($cm, $wordline, $word, $game, $attempt, $hangman, $onlyshow, $showsolution, $course, $wordline2) {
    echo "\r\n<br/><br/><font size=\"5\">\n$wordline</font>\r\n";

    if ($showsolution && $wordline2 != '') {
        echo "<br/><font size=\"5\">\n$wordline2</font>\r\n";
    }

    if ($onlyshow || $showsolution) {
        return;
    }

    echo '<p><BR/><font size="5" color="red">' . get_string('hangman_loose', 'game') . '</font><BR/><BR/></p>';

    if ($game->param6) {
        // Show the correct answer.
        if (game_strpos($word, ' ') != false) {
            echo '<br/>' . get_string('hangman_correct_phrase', 'game');
        } else {
            echo '<br/>' . get_string('hangman_correct_word', 'game');
        }
        echo '<B>' . $word . "</B><BR/><BR/>\r\n";
    }

    game_hangman_show_nextword($cm, $game, $attempt, $hangman, $course);
}

/**
 * Shows the next word.
 *
 * @param stdClass $cm
 * @param stdClass $game
 * @param stdClass $attempt
 * @param stdClass $hangman
 * @param stdClass $course
 */
function game_hangman_show_nextword($cm, $game, $attempt, $hangman, $course) {
    global $CFG, $DB;

    echo '<br/>';
    if (($hangman->try < $hangman->maxtries) || ($hangman->maxtries == 0)) {
        // Continue to next word.
        $params = "id={$cm->id}&action2=nextword\">" . get_string('nextword', 'game') . '</a> &nbsp; &nbsp; &nbsp; &nbsp;';
        echo "<a href=\"{$CFG->wwwroot}/mod/game/attempt.php?$params";
    } else {
        game_hangman_onfinishgame($cm, $game, $attempt, $hangman, $course);

        if (game_can_start_new_attempt($game)) {
            echo "<a href=\"{$CFG->wwwroot}/mod/game/attempt.php?id={$cm->id}\">" .
                get_string('nextgame', 'game') . '</a> &nbsp; &nbsp; &nbsp; &nbsp; ';
        }
    }

    echo "<a href=\"{$CFG->wwwroot}/course/view.php?id=$course->id\">" . get_string('finish', 'game') . '</a> ';
}
