/*
This file is part of SystemTestPortal.
Copyright (C) 2017  Institute of Software Technology, University of Stuttgart

SystemTestPortal 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.

SystemTestPortal 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 SystemTestPortal.  If not, see <http://www.gnu.org/licenses/>.
*/

$.getScript("/static/js/util/ajax.js");
$.getScript("/static/js/util/common.js");

/** Adds the listeners on page load */
function initializeExecutionClickListener() {

    $("#buttonExecuteFirstTestStep").on("click", buttonExecuteFirstTestStepPressed);
    $("#buttonExecuteNextTestStep").on("click", buttonExecuteNextTestStepPressed);
    $("#buttonSummaryFinish").on("click", buttonSummaryFinishPressed);
    $("#buttonAbort").on("click", buttonAbortPressed);
    $("#buttonPause").on("click", buttonPausePressed);

    var $check = $(".preconditionCheckbox"), el;
    $check
   .data('checked',0)
   .click(function(e) {
        el = $(this);
        clearSelection();
        preconditionSelection(e,el)
    });

}

var timerID;
var secondsElement;
var minutesElement;
var hoursElement;
$(window).on('load', initTimer());

/** Will start the test execution timer */
function initTimer() {

    secondsElement = $('#timeSeconds');
    minutesElement = $('#timeMinutes');
    hoursElement = $('#timeHours');

    let sec = parseInt(secondsElement.text());
    let min = parseInt(minutesElement.text());
    let hour = parseInt(hoursElement.text());

    secondsElement.text(sec.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping: false}));
    minutesElement.text(min.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping: false}));
    hoursElement.text(hour.toString());

    resumeTimer();
}

function buttonPausePressed() {

    clearInterval(timerID);

    $("#buttonPause")
        .off()
        .on("click", resumeTimer);

    $(".buttonPauseIcon")
        .removeClass("fa-play fa-pause")
        .addClass("fa-play");
}

function resumeTimer() {

    clearInterval(timerID);
    timerID = setInterval(tickSec, 1000);

    $("#buttonPause")
        .off()
        .on("click", buttonPausePressed);

    $(".buttonPauseIcon")
        .removeClass("fa-pause fa-play")
        .addClass("fa-pause");
}

/**
 * Displays an abort dialog which will delegate back to overview on abort confirm
 * @param event the event which invokes this method
 */
function buttonAbortPressed(event) {
    showAbortModalWith(() => ajaxRequestFragment(event, getTestURL().toString(), "", "GET"));
}

/**
 * Saves inputs and requests for first step execution page
 * @param event the event which invokes this method
 */
function buttonExecuteFirstTestStepPressed(event) {
    ajaxRequestFragment(event, currentURL().toString(), getExecutionStartPageData(), "POST");
}

/**
 * Saves inputs and requests for next step execution page
 * @param event the event which invokes this method
 */
function buttonExecuteNextTestStepPressed(event) {
    ajaxRequestFragment(event, currentURL().toString(), getExecutionStepPageData(), "POST");
}

/**
 * Saves inputs and redirects
 * @param event the event which invokes this method
 */
function buttonSummaryFinishPressed(event) {

    const path = currentURL().removeLastSegments(1).toString();
    const data = getSummaryPageData();

    disableAbortWarnings();

    if (data.case === "0" || data.case === "-1")
        ajaxRequestFragmentWithHistory(event, currentURL().toString(), data, "POST", path);
    else
        ajaxRequestFragment(event, currentURL().toString(), data, "POST");
}

/** Shows next second on the timer */
function tickSec() {

    let sec = parseInt(secondsElement.text()) + 1;
    if (sec >= 60) {
        sec -= 60;
        tickMin()
    }
    secondsElement.text(sec.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping: false}));
}

/** Shows next minute on the timer */
function tickMin() {

    let min = parseInt(minutesElement.text()) + 1;
    if (min >= 60) {
        min -= 60;
        tickHour();
    }
    minutesElement.text(min.toLocaleString('en-US', {minimumIntegerDigits: 2, useGrouping: false}));
}

/** Shows next hour on the timer */
function tickHour() {

    const hour = parseInt(hoursElement.text()) + 1;
    hoursElement.text(hour.toString());
}

/** Returns an object with the information given on the execution start page */
function getExecutionStartPageData() {
    return {
        fragment: true,
        step: 0,
        case: $('#inputTestCaseNumber').val(),
        inputSUTVersion: $('#inputTestObjectSUTVersions').val(),
        inputSUTVariant: $('#inputTestObjectSUTVariants').val(),
        seconds: $('#timeSeconds').text(),
        minutes: $('#timeMinutes').text(),
        hours: $('#timeHours').text(),
        preconditions: getPreconditionResults(),
        isAnonymous: $("#optionAnonymous:checkbox:checked").length > 0
    }
}

/** Returns an object with the information given on the execution step page */
function getExecutionStepPageData() {
    return {
        fragment: true,
        step: $('#inputTestStepNumber').val(),
        case: $('#inputTestCaseNumber').val(),
        result: $("input:radio[name ='testResults']:checked").val(),
        notes: $('#inputTestStepNotes').val(),
        inputTestStepActualResult: $('#inputTestStepActualResult').val(),
        seconds: $('#timeSeconds').text(),
        minutes: $('#timeMinutes').text(),
        hours: $('#timeHours').text()
    }
}

/** Returns an object with the information given on the summary page */
function getSummaryPageData() {
    return {
        fragment: true,
        step: $('#inputTestStepNumber').val(),
        case: $('#inputTestCaseNumber').val(),
        notes: $('#inputTestComment').val(),
        result: $("input:radio[name ='testResults']:checked").val(),
        seconds: $('#timeSeconds').text(),
        minutes: $('#timeMinutes').text(),
        hours: $('#timeHours').text()
    }
}

/** Sets up abort listener displaying a modal if user accidentally hits non execution controls. */
function initializeAbortListener() {
    enableAbortWarnings();
}

/** Turns on abort warnings if the user accidentally hits non execution controls. */
function enableAbortWarnings() {

    $("a, img")
        .not($(".No-Warning-On-Current-Action-Abort"))
        .not($("#tabTestCases a"))
        .addClass("Warning-On-Current-Action-Abort-Active")
        .on("click.execution-abort", event => showAbortModalWith(() => $(event.target)[0].click()));
}

/** Turns off abort warnings if the user accidentally hits non execution controls. */
function disableAbortWarnings() {

    $(".Warning-On-Current-Action-Abort-Active")
        .off("click.execution-abort")
        .removeClass("Warning-On-Current-Action-Abort-Active");
}

/**
 * Sets up and shows the abort modal
 * @param abortFunction {function} action when pressing "Abort"
 * @returns {boolean} always false to prevent event default action
 */
function showAbortModalWith(abortFunction) {

    const abortModal = $("#execution-abort-modal");
    const confirmAbortButton = abortModal.find("#buttonAbortConfirm");

    // on abort pressed
    confirmAbortButton.on("click", () => {
        abortModal.on('hidden.bs.modal', abortFunction);
        disableAbortWarnings();
        return true;
    });

    abortModal
        .on('hidden.bs.modal', () => confirmAbortButton.off("click"))
        .modal("show");

    return false;
}

/**
 *
 * @param event
 * @param el
 */
function preconditionSelection(event, el) {

    switch (el.data('checked')) {

        // unchecked, going checked
        case 0:
            el.data('checked', 1);
            el.prop('indeterminate', false);
            break;

        // checked, going indeterminate
        case 1:
            el.data('checked', 2);
            el.prop('indeterminate', true);
            el.prop('checked', true);
            break;

        // indeterminate, going unchecked
        default:
            el.data('checked', 0);
            el.prop('indeterminate', false);
            el.prop('checked', false);
    }
}

/**
 *
 * @returns {string}
 */
function getPreconditionResults() {

    const checkboxes = document.getElementsByClassName("preconditionCheckbox");
    const results = [];

    for (let i = 0; i < checkboxes.length; i++){
        if (checkboxes[i].indeterminate)
            results.push("partially fulfilled");
        else if (checkboxes[i].checked)
            results.push("fulfilled");
        else
            results.push("not fulfilled");
    }

    return JSON.stringify(results)
}