var qa_counter = 1;
var reco_flag = 0;

var config = {};

var state = {
    taskIndex: gup("skipto") ? parseInt(gup("skipto")) : 0,
    taskInputs: {},
    taskOutputs: [],
    //assignmentId: gup("assignmentId"),
    assignmentId: Math.floor(Math.random() * 1000),
    //workerId: gup("workerId"),
    workerId: Math.floor(Math.random() * 1000),
    hitId: gup("hitId")
};

// Debug log
var bugout = new debugout();
var rectBugout = new debugout();

/* HELPERS */
function saveTaskData() {
    var data;
    if (isDemoSurvey()) {
        data = demoSurvey.collectData();
    } else {
        data = custom.collectData(getTaskInputs(state.taskIndex), state.taskIndex, getTaskOutputs(state.taskIndex));
    }
    if (config.meta.aggregate) {
        $.extend(state.taskOutputs, data);
    } else {
        state.taskOutputs[state.taskIndex] = data;
    }
}

function getTaskInputs(i) {
    return config.meta.aggregate ? state.taskInputs : state.taskInputs[i];
}
``

function getTaskOutputs(i) {
    return config.meta.aggregate ? state.taskOutputs : state.taskOutputs[i];
}

function updateTask() {
    //console.log(state.taskIndex);
    if (config.advanced.hideIfNotAccepted && hideIfNotAccepted()) {
        return;
    }
    $("#progress-bar").progress("set progress", state.taskIndex + 1);
    if (isDemoSurvey()) {
        demoSurvey.showTask();
    } else {
        // show the user's task
        demoSurvey.hideSurvey();
        $('#custom-experiment').show();
        custom.showTask(getTaskInputs(state.taskIndex), state.taskIndex, getTaskOutputs(state.taskIndex));
    }
    if (state.taskIndex == config.meta.numSubtasks + config.advanced.includeDemographicSurvey - 1) {
        // last page 
        $("#next-button").hide();
        $("#qa-button").hide();
        $('#nq-button').hide();
        $("#reco-button").hide();
        if (state.taskIndex != 0) {
            $("#prev-button").removeClass("disabled");
        } else {
            $("#prev-button").addClass("disabled");
        }
        $("#submit-button").removeClass("disabled");
        $("#disclaimer").show();
        $("#final-task-fields").css("display", "block"); // added this to custom.js only on the last page (last subtask) of the last task
        // NOTE: comments in the above 2 lines only refer to the case where demographic survey is not shown
    } else if (state.taskIndex == 0) {
        // first page 
        $("#next-button").removeClass("disabled");
        $("#prev-button").addClass("disabled");
        $("#submit-button").addClass("disabled");
        $("#final-task-fields").css("display", "none");
        $("#disclaimer").hide();
    } else {
        // intermediate page
        $("#next-button").removeClass("disabled");
        $("#prev-button").removeClass("disabled");
        $("#submit-button").addClass("disabled");
        $("#final-task-fields").css("display", "none");
        $("#disclaimer").hide();
    }
}

function nextTask() {
    spanPosition();
    dd = new Date();
    bugout.log('next button clicked for task:' + state.taskIndex + ', at: ' + dd);
    bugout.log(dd.getTime());
    console.log("moving to next task");
    if (qa_counter == 5) {
        custom.updateAnswers(qa_counter);
        qa_counter = 1;
    }
    if (state.taskIndex == 79) {
        custom.recoAnswers();
    }
    if (state.taskIndex < (config.meta.numSubtasks + config.advanced.includeDemographicSurvey) - 1) {
        saveTaskData();

        var failedValidation;
        if (isDemoSurvey()) {
            failedValidation = demoSurvey.validateTask();
        } else {
            failedValidation = custom.validateTask(getTaskInputs(state.taskIndex), state.taskIndex, getTaskOutputs(state.taskIndex));
        }

        if (failedValidation == false) {
            state.taskIndex++;
            updateTask();
            clearMessage();
            console.log("Current collected data", state.taskOutputs);
        } else {
            generateMessage("negative", failedValidation.errorMessage);
        }
    }
}

function prevTask() {
    if (state.taskIndex > 0) {
        saveTaskData();
        state.taskIndex--;
        updateTask();
    }
}

function toggleInstructions() {
    dd = new Date();
    bugout.log('Entering recall stage: ' + dd);
    bugout.log(dd.getTime());
    rectBugout.log("id x y width height top right bottom left");

    if ($("#experiment").css("display") == "none") {
        $("#experiment").css("display", "flex");
        $("#instructions").css("display", "none");
        $("#disclaimer").hide();
        updateTask();
    } else {
        saveTaskData();
        $("#experiment").css("display", "none");
        $("#instructions").css("display", "flex");
        $("#disclaimer").show();
    }
}

function clearMessage() {
    $("#message-field").html("");
}

function generateMessage(cls, header) {
    clearMessage();
    if (!header) return;
    var messageStr = "<div class='ui message " + cls + "'>";
    messageStr += "<i class='close icon'></i>";
    messageStr += "<div class='header'>" + header + "</div></div>";

    var newMessage = $(messageStr);
    $("#message-field").append(newMessage);
    newMessage.click(function() {
        $(this).closest(".message").transition("fade");
    });
}

function addHiddenField(form, name, value) {
    // form is a jQuery object, name and value are strings
    var input = $("<input type='hidden' name='" + name + "' value=''>");
    input.val(value);
    form.append(input);
}

function submitHIT() {
    console.log("submitting");

    $("#copy-key-button").click(function() {
        selectText('submit-code');
    });

    saveTaskData();
    clearMessage();
    $("#submit-button").addClass("loading");
    for (var i = 0; i < config.meta.numSubtasks; i++) {
        var failedValidation = custom.validateTask(getTaskInputs(i), i, getTaskOutputs(i));
        if (failedValidation) {
            cancelSubmit(failedValidation.errorMessage);
            return;
        }
    }
    if (config.advanced.includeDemographicSurvey) {
        var failedValidation = demoSurvey.validateTask();
        if (failedValidation) {
            cancelSubmit(failedValidation.errorMessage);
            return;
        }
    }

    var results = custom.getUploadPayload(state.taskOutputs);
    var payload = {
        'assignmentId': state.assignmentId,
        'workerId': state.workerId,
        'hitId': state.hitId,
        //'tag': gup('tag'),
        'origin': state.origin,
        'results': results
    }

    var submitUrl;
    if (config.advanced.externalSubmit) {
        submitUrl = config.advanced.externalSubmitUrl;
        externalSubmit(submitUrl, payload);
    } else {
        submitUrl = decodeURIComponent(gup("turkSubmitTo")) + "/mturk/externalSubmit";
        mturkSubmit(submitUrl, payload);
    }
}

function cancelSubmit(err) {
    console.log("cancelling submit");
    $("#submit-button").removeClass("loading");
    generateMessage("negative", err);
}

function gup(name) {
    var regexS = "[\\?&]" + name + "=([^&#]*)";
    var regex = new RegExp(regexS);
    var tmpURL = window.location.href;
    var results = regex.exec(tmpURL);
    if (results == null) return "";
    else return results[1];
}

/* SETUP FUNCTIONS */
function populateMetadata(config) {
    $(".meta-title").html(config.meta.title);
    $(".meta-desc").html(config.meta.description);
    $(".instructions-simple").html(config.instructions.simple);
    for (var i = 0; i < config.instructions.steps.length; i++) {
        $(".instructions-steps").append($("<li>" + config.instructions.steps[i] + "</li>"));
    }
    $(".disclaimer-text").html(config.meta.disclaimer);
    if (config.instructions.images.length > 0) {
        $("#sample-task").css("display", "block");
        var instructionsIndex = Math.floor(Math.random() * config.instructions.images.length);
        var imgEle = "<img class='instructions-img' src='";
        imgEle += config.instructions.images[instructionsIndex] + "'></img>";
        $("#instructions-demo").append($(imgEle));

    }
    $("#progress-bar").progress({
        total: config.meta.numSubtasks + config.advanced.includeDemographicSurvey,
    });
}

function setupButtons() {
    $("#next-button").click(nextTask);
    $("#prev-button").click(prevTask);
    $(".instruction-button").click(toggleInstructions);
    $("#submit-button").click(submitHIT);
    $("#qa-button").click(qaSubmit);
    $("#nq-button").click(qaSubmit);
    $("#reco-button").click(recognition_stage);
    if (state.assignmentId == "ASSIGNMENT_ID_NOT_AVAILABLE") {
        $("#submit-button").remove();
    }
}

function recognition_stage() {
    spanPosition();
    dd = new Date();
    bugout.log('Entering recognition stage: ' + dd);
    bugout.log(dd.getTime());

    if (qa_counter == 5) {
        custom.updateAnswers(qa_counter);
        qa_counter = 1;
    }
    $('#question-answer-subtask').hide();
    $('#show-image-subtask').hide();
    $('#reco-subtask').show();
    $('#qa-button').hide();
    $('#next-button').show();
    $('#nq-button').hide();
    $("#reco-button").hide();
}

function updateQA() {
    custom.updateAnswers(qa_counter)
    $('#question').html(state.taskInputs[state.taskIndex].QA['Q' + qa_counter].question);
    $('label[for=A]').html(state.taskInputs[state.taskIndex].QA['Q' + qa_counter].A);
    $('label[for=B]').html(state.taskInputs[state.taskIndex].QA['Q' + qa_counter].B);
    $('label[for=C]').html(state.taskInputs[state.taskIndex].QA['Q' + qa_counter].C);
}

function spanPosition() {
    // Span postion of answer
    var allQuestion = document.getElementById("question");
    var span = allQuestion.getElementsByTagName("span");
    var qSkip = true;
    for (j of span) {
        var rectQuestion = j.getBoundingClientRect();
        var rectQ = j.id + " ";
        for (var key in rectQuestion) {
            var item = rectQuestion[key];
            if (!isNaN(item) && item != 0) {
                rectQ = rectQ + item.toString() + " ";
            } else if (item == 0) {
                qSkip = false;
                break;
            }
        }

        // Skip recording data when the "next" button  is clicked during encoding interface
        if (qSkip) {
            rectBugout.log(rectQ);
        }

    }

    // Span position of answer
    var allSelection = document.getElementsByClassName("selection");
    aSkip = true;
    for (i of allSelection) {
        var span = i.getElementsByTagName("span");
        for (j of span) {
            var rectAnswer = j.getBoundingClientRect();
            var rectA = j.id + " ";
            for (var key in rectAnswer) {
                var item = rectAnswer[key];
                if (!isNaN(item) && item != 0) {
                    rectA = rectA + item.toString() + " ";
                } else if (item == 0) {
                    aSkip = false;
                    break;
                }
            }

            // Skip recording data when the "next" button  is clicked during encoding interface
            if (aSkip) {
                rectBugout.log(rectA);
            }
        }
    }
}

function qaSubmit() {
    spanPosition();
    dd = new Date();
    bugout.log('QA button clicked, question No' + qa_counter + ': ' + dd);
    bugout.log(dd.getTime());
    if (state.taskIndex < TARGET_NUM && state.taskIndex % 4 > 1) {
        if (qa_counter <= 5) {
            qa_counter = qa_counter + 1;
            updateQA()
            $('#question-answer-subtask').show();
            $('#qa-button').hide();
            $("#reco-button").hide();
            if (qa_counter === 5) {
                if (state.taskIndex === TARGET_NUM - 1) {
                    $('#next-button').hide();
                    $('#nq-button').hide();
                    $('#reco-button').show();
                } else {
                    $('#next-button').show();
                    $('#nq-button').hide();
                }
            } else {
                $('#next-button').hide();
                $('#nq-button').show();
            }
            $('#show-image-subtask').show();
        }
    } else {
        nextTask()
    }
    $('#remembered-char-subtask').hide();
}
/* USEFUL HELPERS */

function isDemoSurvey() {
    var useSurvey = config.advanced.includeDemographicSurvey;
    var lastTask = state.taskIndex == config.meta.numSubtasks + config.advanced.includeDemographicSurvey - 1;
    return useSurvey && lastTask;
}

// Hides the task UI if the user is working within an MTurk iframe and has not accepted the task 
// Returns true if the task was hidden, false otherwise
function hideIfNotAccepted() {
    if (state.assignmentId == "ASSIGNMENT_ID_NOT_AVAILABLE") {
        console.log("Hiding if not accepted");
        $('#experiment').hide();
        $("#hit-not-accepted").show();
        return true;
    }
    return false;
}

// Code to show the user's validation code; only used if task is configured as an external link
function showSubmitKey(key) {
    $('#submit-code').text(key);
    $('#experiment').hide();
    $('#succesful-submit').show();
    selectText('submit-code');
}

// highlights/selects text within an html element
// copied from:
// https://stackoverflow.com/questions/985272/selecting-text-in-an-element-akin-to-highlighting-with-your-mouse
function selectText(node) {
    node = document.getElementById(node);

    if (document.body.createTextRange) {
        const range = document.body.createTextRange();
        range.moveToElementText(node);
        range.select();
        document.execCommand("copy");
    } else if (window.getSelection) {
        const selection = window.getSelection();
        const range = document.createRange();
        range.selectNodeContents(node);
        selection.removeAllRanges();
        selection.addRange(range);
        document.execCommand("copy");
    } else {
        console.warn("Could not select text in node: Unsupported browser.");
    }
}

/* SUBMIT FUNCTIONS */

// submit to MTurk as a back-end. MTurk only accepts form submissions and frowns
// upon async POSTs.
function mturkSubmit(submitUrl, results) {
    var form = $("#submit-form");
    addHiddenField(form, 'assignmentId', state.assignmentId);
    addHiddenField(form, 'workerId', state.workerId);
    addHiddenField(form, 'results', JSON.stringify(results));
    addHiddenField(form, 'feedback', $("#feedback-input").val());

    $("#submit-form").attr("action", submitUrl);
    $("#submit-form").attr("method", "POST");
    // if (DEBUG) {
    //     return;
    // }
    $("#submit-form").submit();
    $("#submit-button").removeClass("loading");
    generateMessage("positive", "Thanks! Your task was submitted successfully.");
    $("#submit-button").addClass("disabled");
}

// submit to a customized back-end. 
function externalSubmit(submitUrl, results) {
    dd = new Date();
    bugout.log('Submitting study:' + dd);
    bugout.log(dd.getTime());
    bugout.log(results);
    console.log("payload", results);
    console.log("submitUrl", submitUrl);
    bugout.downloadLog();
    rectBugout.downloadLog();

    $.ajax({
        url: submitUrl,
        type: 'POST',
        data: JSON.stringify(results),
        dataType: 'json'
    }).then(function(response) {
        showSubmitKey(response['key']);
    }).catch(function(error) {
        // This means there was an error connecting to the DEVELOPER'S
        // data collection server. 
        // even if there is a bug/connection problem at this point,
        // we want people to be paid. 
        // use a consistent prefix so we can pick out problem cases,
        // and include their worker id so we can figure out what happened
        console.log("ERROR", error);
        key = "mturk_key_" + state.workerId + "_" + state.assignmentId;
        showSubmitKey(key);
    })
}

/* MAIN */
$(document).ready(function() {
    $.getJSON("config.json").done(function(data) {
        config = data;
        config.meta.aggregate = true;
        state.taskOutputs = {};
        custom.loadTasks().done(function(taskInputData) {
            config.meta.numSubtasks = taskInputData[1];
            state.taskInputs = taskInputData[0];
            populateMetadata(config);
            demoSurvey.maybeLoadSurvey(config);
            setupButtons(config);
        });
    });
});