<?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/>.
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

/**
 * CrossDB class
 *
 * @package mod_game
 * @copyright 2007 Vasilis Daloukas
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */

/**
 * This class is a cross that can load and save to a table
 *
 * @package mod_game
 * @copyright 2007 Vasilis Daloukas
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 **/
class CrossDB extends Cross {
    /** @var int length horizontal. */
    public $mlegendh;
    /** @var int Length vertical. */
    public $mlegendv;

    /**
     * Save cross.
     *
     * @param stdClass $game
     * @param array $crossm
     * @param array $crossd
     * @param int $id
     */
    public function savecross($game, &$crossm, $crossd, $id) {
        global $DB, $USER;

        $crossm->id = $id;
        $crossm->sourcemodule = $game->sourcemodule;

        $this->delete_records($id);

        if (!(game_insert_record("game_cross", $crossm))) {
            throw new moodle_exception('cross_error', 'game', 'Insert page: new page game_cross not inserted');
        }

        foreach ($crossd as $rec) {
            $rec->attemptid = $id;
            $rec->questiontext = $rec->questiontext;

            $rec->gamekind = $game->gamekind;
            $rec->gameid = $game->id;
            $rec->userid = $USER->id;
            $rec->sourcemodule = $game->sourcemodule;

            if (!$DB->insert_record('game_queries', $rec)) {
                throw new moodle_exception('cross_error', 'game', 'Insert page: new page game_queries not inserted');
            }
            game_update_repetitions($game->id, $USER->id, $rec->questionid, $rec->glossaryentryid);
        }

        return true;
    }

    /**
     * Delete records.
     *
     * @param int $id
     */
    public function delete_records($id) {
        global $DB;

        if (!$DB->delete_records('game_queries', ['attemptid' => $id])) {
            throw new moodle_exception('cross_error', 'game', "Can't delete from game_queries attemptid=$id");
        }
        if (!$DB->delete_records('game_cross', ['id' => $id])) {
            throw new moodle_exception('cross_error', 'game', "Can't delete from game_cross id=$id");
        }
    }


    /**
     * Load cross.
     *
     * @param string $g
     * @param boolean $done
     * @param string $html
     * @param stdClass $game
     * @param stdClass $attempt
     * @param stdClass $crossrec
     * @param boolean $onlyshow
     * @param boolean $showsolution
     * @param boolean $finishattempt
     * @param boolean $showhtmlsolutions
     * @param string $language
     * @param boolean $showstudentguess
     * @param stdClass $context
     * @param stdClass $course
     * @param stdClass $cm
     */
    public function loadcross(
        $g,
        &$done,
        &$html,
        $game,
        $attempt,
        $crossrec,
        $onlyshow,
        $showsolution,
        &$finishattempt,
        $showhtmlsolutions,
        &$language,
        $showstudentguess,
        $context,
        $course,
        $cm
    ) {
        global $DB;

        $info = '';
        $correctletters = 0;
        $allletters = 0;
        $wrongletters = 0;
        $html = '';
        $done = false;

        $loadfromdb = ($g == "");

        $this->mmincol = $this->mminrow = 0;
        $this->mmaxcol = $crossrec->usedcols;
        $this->mmaxrow = $crossrec->usedrows;

        if ($g == "") {
            $g = str_repeat(' ', $this->mmaxcol * $this->mmaxrow);
        }

        $load = false;

        $puzzle = str_repeat('.', $this->mmaxrow * $this->mmaxcol);
        if ($recs = $DB->get_records('game_queries', ['attemptid' => $crossrec->id])) {
            $a = [];
            foreach ($recs as $rec) {
                if ($rec->horizontal) {
                    $key = sprintf('h%10d %10d', $rec->myrow, $rec->mycol);
                } else {
                    $key = sprintf('v%10d %10d', $rec->mycol, $rec->myrow);
                }
                $a[$key] = $rec;
            }

            ksort($a);
            $b = [];
            $correctletters = $wrongletters = $restletters = 0;

            foreach ($a as $rec) {
                $this->updatecrossquestions(
                    $rec,
                    $g,
                    $pos,
                    $correctletters,
                    $wrongletters,
                    $restletters,
                    $game,
                    $attempt,
                    $crossrec,
                    $loadfromdb
                );
                $b[] = $rec;

                if (($rec->mycol != 0) && ($rec->myrow != 0)) {
                    $load = true;
                }
                if ($language == '') {
                    $language = game_detectlanguage($rec->answertext);
                }
            }
            $info = $this->game_cross_computecheck(
                $correctletters,
                $wrongletters,
                $restletters,
                $game,
                $attempt,
                $done,
                $onlyshow,
                $showsolution,
                $finishattempt,
                $course,
                $cm
            );
            $html = $this->showhtml_base($crossrec, $b, $showsolution, $showhtmlsolutions, $showstudentguess, $context, $game);
        }

        if ($load == false) {
            $finishattempt = true;
        }

        return $info;
    }

    /**
     * Compute check.
     *
     * @param int $correctletters
     * @param int $wrongletters
     * @param string $restletters
     * @param stdClass $game
     * @param stdClass $attempt
     * @param boolean $done
     * @param boolean $onlyshow
     * @param boolean $showsolution
     * @param boolean $finishattempt
     * @param stdClass $course
     * @param stdClass $cm
     */
    public function game_cross_computecheck(
        $correctletters,
        $wrongletters,
        $restletters,
        $game,
        $attempt,
        &$done,
        $onlyshow,
        $showsolution,
        $finishattempt,
        $course,
        $cm
    ) {
        $a = [];
        if ($correctletters) {
            $a[] = $correctletters . ' ' .
                ($correctletters > 1 ? get_string('cross_corrects', 'game') : get_string('cross_correct', 'game'));
        }
        if ($wrongletters) {
            $a[] = '<b>' . $wrongletters . ' ' .
                ($wrongletters > 1 ? get_string('cross_errors', 'game') : get_string('cross_error', 'game')) . '</b>';
        }

        if ($correctletters > 1 || $wrongletters > 1) {
            $ret = get_string('cross_found_many', 'game');
        } else if (count($a)) {
            $ret = get_string('cross_found_one', 'game');
        } else {
            $ret = '';
        }

        $i = 0;
        foreach ($a as $msg) {
            $i++;

            if ($i == 1) {
                $ret .= ' ' . $msg;
            } else if ($i == count($a)) {
                $ret .= ' ' . get_string('and', 'game') . ' ' . $msg;
            } else {
                $ret .= ', ' . $msg;
            }
        }

        $done = ($restletters == 0 ? true : false);

        if ($finishattempt == false) {
            if ($onlyshow || $showsolution) {
                return $ret;
            }
        } else {
            $done = 1;
        }

        $score = $correctletters / ($correctletters + $restletters);
        $ret .= '<br>' . get_string('grade', 'game') . ' ' . round($score * 100) . ' %';

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

        return $ret;
    }

    /**
     * Update cross questions.
     *
     * @param stdClass $rec  (is a record of cross_questions).
     * @param string $g
     * @param int $pos
     * @param int $correctletters
     * @param int $wrongletters
     * @param int $restletters
     * @param stdClass $game
     * @param stdClass $attempt
     * @param stdClass $crossrec
     * @param boolean $loadfromdb
     */
    public function updatecrossquestions(
        &$rec,
        &$g,
        &$pos,
        &$correctletters,
        &$wrongletters,
        &$restletters,
        $game,
        $attempt,
        $crossrec,
        $loadfromdb
    ) {
        global $DB;

        $word = $rec->answertext;
        $len = game_strlen($word);

        if ($loadfromdb) {
            $guess = $rec->studentanswer;
        } else {
            $guess = game_substr($g, $pos, $len);
        }

        $lenguess = game_strlen($guess);
        $pos += $len;

        $isempty = true;
        for ($i = 0; $i < $len; $i++) {
            if ($i < $lenguess) {
                $letterguess = game_substr($guess, $i, 1);
            } else {
                $letterguess = " ";
            }

            if ($letterguess != ' ') {
                $isempty = false;
            }
            $letterword = game_substr($word, $i, 1);
            if ($letterword != $letterguess) {
                if (($letterguess != ' ' && $letterguess != '_')) {
                    $wrongletters++;
                }
                game_setchar($guess, $i, '_');
                $restletters++;
            } else if ($letterguess == ' ') {
                if ($guess == $word) {
                    $correctletters++;
                }
            } else {
                $correctletters++;
            }
        }

        if ($isempty) {
            return;
        }
        if (($rec->studentanswer == $guess )) {
            return;
        }

        $rec->studentanswer = $guess;

        $updrec = new stdClass();
        $updrec->studentanswer = $guess;
        $updrec->id = $rec->id;
        if (!$DB->update_record('game_queries', $updrec, $rec->id)) {
            throw new moodle_exception('cross_error', 'game', 'Update game_queries: not updated');
        }

        $score = $correctletters / $len;
        game_update_queries($game, $attempt, $rec, $score, $guess);
    }
}
