
/*
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/common.js");
$.getScript("/static/js/util/ajax.js");

// newID is the id of the edited test case from the response header
// It is needed to load the correct sut variants and versions after the name
// and therefore the id of a test case was edited
var newID;

function assignButtonsTestCase() {
    /* Button Assignment */
//List
    $("#buttonNewTestCase").click(newTestCase);
    $("#buttonNewTestCaseDisabled").click(showSigninHint);
    $("#buttonFirstTestCase").click(newTestCase);
    $("#buttonNewLabel").click(function (event) { /* nothing yet */
    });
    $(".testCaseLine").click(showTestCase);
    $(".filterBadge").click(filterTestCaseListWithBadge);
//Show
    $("#buttonBack").click(backToTestCaseList);
    $("#buttonDeleteConfirmed").click(deleteTestCase);
    $("#buttonEdit").click(editTestCase);
    $("#buttonHistory").click(showTestCaseHistory);
//$("#buttonRevertConfirmed").click(function () { revertTestCase);
//History
    $("#buttonBackToCase").click(backToTestCase);
    $(".versionLine").click(showTestCaseVersion);
//New
    $("#buttonAbort").click(backToTestCaseList);
    $("#buttonSaveNew").click(saveTestCase);
//Edit
    $("#buttonSave").click(updateTestCase);
    $("#buttonAbortEdit").click(backToTestCase);
//Execute
    $("#buttonExecute").click(execute);

    $("#buttonAddTestStep").click(function (event) {
        newTestStep(event);
    });
    $(".buttonDeleteTestStep").click(function (event) {
        buttonDeleteTestStepConfirm(event);
    });
    $(".buttonDeleteTestStepConfirm").click(function (event) {
        deleteTestStep(event);
    });
    $(".buttonEditTestStep").click(function (event) {
        editTestStep(event);
    });
    $("#buttonFinishTestStepEditing").click(function (event) {
        finishEditTestStep(event);
    });

    $('#modal-teststep-edit').on('shown.bs.modal', function () {
        $('#inputTestStepActionEditField').focus();
    });
}

/* AJAX-Functions */

/* loads the new test case form */
function newTestCase(event) {
    ajaxRequestFragment(event, "new", "", "GET");
}

/*show sign in hint if not signed in and button is pressed*/
function showSigninHint(event) {
    event.preventDefault();
    $("#signin-link").tooltip('show');
}

/* loads the chosen test case */
function showTestCase(event) {
    ajaxRequestFragment(event, event.target.id, "", "GET");
}

/* loads the chosen test case version*/
function showTestCaseVersion(event) {
    var url = urlify(window.location.pathname).takeFirstSegments(5).toString();
    // Get version number. When clicking on an element that is in the .versionLine, check the parent of
    // this element until the parent is the versionLine with the id
    var ind = event.target.id;
    while (ind === "") {
        event.target = event.target.parentNode;
        ind = event.target.id;
    }
    ajaxRequestFragment(event, url + "?version=" + ind, "", "GET");
}

/* loads the chosen test case version*/
function showTestCaseVersionFromTestSequence(event) {
    var url = urlify(window.location.pathname).takeFirstSegments(3).toString();
    // Get version number. When clicking on an element that is in the .versionLine, check the parent of
    // this element until the parent is the versionLine with the id
    var ind = event.target.id;
    while (ind === "") {
        event.target = event.target.parentNode;
        ind = event.target.id;
    }
    ajaxRequestFragment(event, url +"/testcases/" + ind , "", "GET");
}

/* saves the test case */
function saveTestCase(event) {
    var history = urlify(window.location.pathname).removeLastSegments(1).toString() + "/";
    ajaxRequestFragmentWithHistory(event, "save", JSON.stringify(getTestCaseData()), "POST", history);
}

/* loads the start page of the test case execution */
function execute(event) {
    ajaxRequestFragment(event, window.location.pathname + "/execute", "", "GET");
}

/* saves the test case */
function updateTestCase(event) {
    $('#modal-testCase-save').on
    (
        'hidden.bs.modal',
        handleEdit(event, $('#minorUpdate').is(':checked'))
    ).modal('hide');
}

/* deletes a test case */
function deleteTestCase(event) {
    var history = urlify(window.location.pathname).removeLastSegments(1).toString() + "/";
    $('#deleteModal').on('hidden.bs.modal', function () {
        ajaxRequestFragmentWithHistory(event, window.location.pathname, null, "DELETE", history);
    }).modal('hide');
}

/* edits a test case */
function editTestCase(event) {
    var ver = $('#inputTestCaseVersion').find("option:selected").val();
    ajaxRequestFragment(event, window.location.pathname + "/edit", {version: ver}, "GET");
}

/* show test case history */
function showTestCaseHistory(event) {
    ajaxRequestFragment(event, window.location.pathname + "/history", "", "GET");
}

/* revert test case to selected version */
function revertTestCase(event) {
    // not yet implemented
}

/* steps back to the test case  */
function backToTestCase(event) {
    var requestURL = urlify(window.location.pathname).takeFirstSegments(5).toString();
    ajaxRequestFragment(event, requestURL, "", "GET");
}

/* steps back to the test case list */
function backToTestCaseList(event) {
    var requestURL = getProjectURL() + "/" + "testcases" + "/";
    ajaxRequestFragment(event, requestURL, "", "GET");
}

/* helper */
function getTestResult(){
    var radioButtons = document.getElementsByName("testResults");
    var selectedButton;

    for(var i = 0; i < radioButtons.length; i++) {
        if(radioButtons[i].checked)
            selectedButton = radioButtons[i].value;
    }
    return selectedButton
}

// getTestCaseData returns an array with the test case information
function getTestCaseData() {
    return {
        inputTestCaseName: $('#inputTestCaseName').val(),
        inputTestCaseDescription: $('#inputTestCaseDescription').val(),
        inputTestCasePreconditions: $('#inputTestCasePreconditions').val(),
        inputTestCaseSUTVariants: removeEmptyVariants(selectedVersions),
        inputTestCaseLabels: getTestCaseLabelsInput(),
        inputHours: getHours(),
        inputMinutes: getMinutes(),
        inputSteps: getStepData()
    }
}

// getTestCaseLabelsInput returns a list with the selected labels
function getTestCaseLabelsInput() {
    // testCaseLabels contains the the labels of the test case
    var testCaseLabels = [];
    //  Get index of selected labels in dropdown
    var labelsValues = $('#labels').find('option:selected').map(function(a, item){return item.value;});

    // Add the selected labels to testCaseLabels
    $.each(labelsValues, function(index, value) {
        testCaseLabels.push(projectLabels[value])
    });

    return testCaseLabels;
}

// getDataEdit return an array with information of the test case to edit
function getTestCaseDataEdit(isMinor) {
    return {
        isMinor: isMinor,
        inputCommitMessage: $('#inputCommitMessage').val(),
        data: getTestCaseData()
    }
}

// removeEmptyVariants removes all variants from an array of variants that contain no versions
function removeEmptyVariants(sutVariants) {
    $.each(sutVariants, function(index, variant) {
        if (Object.keys(variant.Versions).length < 1) {
            delete sutVariants[variant.Name]
        }
    });
    return sutVariants
}

// handleEdit either updates the current version or saves the edited version
// as newest version, depending on the handling parameter
function handleEdit(event, isMinor) {
    event.preventDefault();

    var url = urlify(window.location.pathname).removeLastSegments(1);

    var posting = $.ajax({
        url: url.appendSegment("update?fragment=true").toString(),
        type: "PUT",
        data: JSON.stringify(getTestCaseDataEdit(isMinor))
    });
    posting.done(function (response) {
        //Save the new id of the test case after editing
        newID = posting.getResponseHeader("newName");

        var historyText = urlify(window.location.pathname).takeFirstSegments(4).toString();
        historyText = historyText + "/" + posting.getResponseHeader("newName");
        $('#tabTestCases').empty().append(response);
        history.pushState('data', '', historyText);
    }).fail(function (response) {
        $("#modalPlaceholder").empty().append(response.responseText);
        $('#errorModal').modal('show');
    });
}

// getHours returns 0 if no hours duration was given
function getHours() {
    var hours = parseInt($('#inputHours').val());
    if (isNaN(hours)) {
        return 0;
    }
    return hours;
}

// getMinutes returns 0 if no minutes duration was given
function getMinutes() {
    var mins = parseInt($('#inputMinutes').val());
    if (isNaN(mins)) {
        return 0;
    }
    return mins;
}

// 2562047 is the max of int64 as nanoseconds converted to minutes
var HOUR_HARD_LIMIT = 2562047;

// checkMinutes sets the minutes between 0 and 59
function checkMins(form) {
    minutes = Math.min(Math.max(0, form.value), 59);
    $("#inputMinutes").val(minutes);
}

// checkHour sets the input between 0 and the biggest number that can be shown
// by a test case
function checkHours(form) {
    hours = Math.min(Math.max(0, form.value), HOUR_HARD_LIMIT);
    $("#inputHours").val(hours);
}

var hours = getHours();
var minutes = getMinutes();

$("#hour-plus").click(function () {
    if (hours < HOUR_HARD_LIMIT) {
        hours++;
        $("#inputHours").val(hours);
    }
});
$("#hour-minus").click(function () {
    hours = Math.max(0, hours - 1);
    $("#inputHours").val(hours);
});
$("#minute-plus").click(function () {
    minutes = (minutes + 1) % 60;
    if (minutes === 0 && hours < HOUR_HARD_LIMIT) {
        hours++;
        $("#inputHours").val(hours);
        $("#inputMinutes").val(minutes);
    } else if (hours < HOUR_HARD_LIMIT) {
        $("#inputMinutes").val(minutes);
    }
});
$("#minute-minus").click(function () {
    if (minutes <= 0 && hours > 0) {
        hours--;
        minutes = 59;
        $("#inputHours").val(hours);
    } else if (minutes <= 0) {
        minutes = 0;
    } else {
        minutes--;
    }
    $("#inputMinutes").val(minutes);
});

// buttonDeleteTestStepConfirm manages the change of the delete-button,
// to confirm the delete-intent of the user
function buttonDeleteTestStepConfirm(event) {
    $(event.target).next().removeClass("d-none");
    $(event.target).addClass("d-none");
}

// deleteTestStep removes the test step-list element from the GUI
function deleteTestStep(event) {
    $(event.target).parent().parent().remove();
}

// editTestStep handles the click-event of an existing test-steps edit-button,
// calls the test-step-edit-modal with the data from the test step in the
// input-fields
function editTestStep(event) {
    var id = $(event.target).closest("li").prop("id");
    var actText = $('#ActionField', $("#" + id)).text();
    var textAreaA = $('#inputTestStepActionEditField');
    textAreaA.val(actText.toString().replace(/^\s+|\s+$/g, ''));

    var expText = $('#ExpectedResultField', $("#" + id)).text();
    var textAreaE = $('#inputTestStepExpectedResultEditField');
    textAreaE.val(expText.toString().replace(/^\s+|\s+$/g, ''));

    var idArea = $('#testStepIdField');
    idArea.val(id.toString());
    $('#modal-teststep-edit').modal('show');
}

// finishEditTestStep handles the submit of the test-step-edit-modal,
// in case of being called from an existing test-steps edit-button
function finishEditTestStep(event) {
    var id = $('#testStepIdField').val();

    var actText = $('#inputTestStepActionEditField').val();
    if(actText.trim()) {
        if (id.toString().match(/^\w*-1/g)) {
            finishAddingNewTestStep(event, id);
        } else {
            var actField = $('#ActionField', $("#" + id));
            actField.text(actText.toString());

            var expField = $('#ExpectedResultField', $("#" + id));
            var expText = $('#inputTestStepExpectedResultEditField').val();
            expField.text(expText.toString());

            $('#modal-teststep-edit').modal('hide');
            event.preventDefault();
        }
    }

}

// newTestStep handles the click-event of the add-test-step-button,
// calls the test-step-edit-modal with empty input fields
function newTestStep(event) {
    var textAreaA = $('#inputTestStepActionEditField');
    textAreaA.val('');
    var textAreaE = $('#inputTestStepExpectedResultEditField');
    textAreaE.val('');
    var idArea = $('#testStepIdField');
    idArea.val("-1");

    $('#modal-teststep-edit').modal('show');
}

// finishAddingNewTestStep processes the the submitting of the test-step-
// edit-modal when the modal was requested via the add-test-step-button
function finishAddingNewTestStep(event, id) {
    var ind = $("#testStepsAccordion").find("li").length;
    var l = $("#testStepsAccordion").find("li:last");
    var lastId;
    if (ind > 0) {
        lastId = parseInt($(l).attr("id").replace(/^[^\d]+/g, ''), 10);
        ind = lastId + 1;
    } else {
        ind = 0;
    }

    var entry = $("#emptyTestStepElement").find("li");
    entry = entry.clone(true, true);
    $(entry).find("*").each(function () {
        if (this.id === "testStepsAccordion00000") {
            this.id = this.id.toString().replace(/\d+/g, ind);
        }
    });
    entry.find("button").each(function () {
        if (this.classList.contains("buttonDeleteTestStep")) {
            $(this).on("click", null, function (event) {
                buttonDeleteTestStepConfirm(event)
            });
        }
        if (this.classList.contains("buttonDeleteTestStepConfirm")) {
            $(this).on("click", null, function (event) {
                deleteTestStep(event)
            });
        }
        if (this.classList.contains("buttonEditTestStep")) {
            $(this).on("click", null, function (event) {
                editTestStep(event)
            });
        }
    });

    entry[0].id = "testStep" + ind;
    if (ind > 0) {
        $("#testStep" + (ind - 1)).after(entry);
        $(entry).insertAfter($("#testStepsAccordion").lastChild);
    } else {
        $("#testStepsAccordion").append(entry[0]);
    }
    var text = $("#ActionField", entry);
    text.attr("href", "#testStepsAccordion" + ind);
    text.attr("aria-controls", "testStepsAccordion" + ind);

    var actField = $('#ActionField', entry);
    var actText = $('#inputTestStepActionEditField').val();
    actField.text(actText.toString());

    var expField = $('#ExpectedResultField', entry);
    var expText = $('#inputTestStepExpectedResultEditField').val();
    expField.text(expText.toString());

    $('#modal-teststep-edit').modal('hide');
    event.preventDefault();
}

// getStepData returns an array of arrays containing the ID, action and
// expected result data of the test step GUI elements
function getStepData() {
    var steps = [];
    var temp = {};
    var stepsRaw = $("#testStepsAccordion").find("li");
    stepsRaw.each(function (index, element) {
        temp.ID = index;
        temp.actual = $("#ActionField", element).text().replace(/^\s+|\s+$/g, '');
        temp.expected = $("#ExpectedResultField", element).text().replace(/^\s+|\s+$/g, '');
        steps.push(temp);
        temp = {};
    });
    return steps;
}

function filterTestCaseListWithBadge(event) {
    event.preventDefault();
    var url = urlify(window.location.pathname);
    var requestURL = url.takeFirstSegments(3).appendSegment("testcases").toString() + "/";
    var posting = $.get(requestURL + "?fragment=true&filter=" + event.target.id);

    /* Alerts the results */
    posting.done(function (response) {
        $('#tabarea').empty().append(response);
    }).fail(function (response) {
        $("#modalPlaceholder").empty().append(response.responseText);
        $('#errorModal').modal('show');
    });

    return false;
}
