define(
    ['jquery', 'core/log', 'mod_minilesson/definitions', 'core/templates', 'core/ajax',
        'mod_minilesson/dictation', 'mod_minilesson/dictationchat', 'mod_minilesson/multichoice', 'mod_minilesson/multiaudio',
        'mod_minilesson/speechcards', 'mod_minilesson/listenrepeat',
        'mod_minilesson/page', 'mod_minilesson/smartframe', 'mod_minilesson/shortanswer',
        'mod_minilesson/listeninggapfill', 'mod_minilesson/typinggapfill', 'mod_minilesson/speakinggapfill',
        'mod_minilesson/spacegame', 'mod_minilesson/fluency', 'mod_minilesson/freespeaking',
        'mod_minilesson/freewriting', 'mod_minilesson/passagereading', 'mod_minilesson/h5p',
        'mod_minilesson/conversation', 'mod_minilesson/compquiz', 'mod_minilesson/passagegapfill',
        'mod_minilesson/audiochat', 'mod_minilesson/wordshuffle', 'mod_minilesson/scatter',
        'mod_minilesson/slides', 'mod_minilesson/fiction', 'mod_minilesson/progresstimer'],
    function (
        $,
        log,
        def,
        templates,
        Ajax,
        dictation,
        dictationchat,
        multichoice,
        multiaudio,
        speechcards,
        listenrepeat,
        page,
        smartframe,
        shortanswer,
        listeninggapfill,
        typinggapfill,
        speakinggapfill,
        spacegame,
        fluency,
        freespeaking,
        freewriting,
        passagereading,
        h5p,
        conversation,
        compquiz,
        passagegapfill,
        audiochat,
        wordshuffle,
        scatter,
        slides,
        fiction,
        progresstimer
    ) {
        "use strict"; // jshint ;_;

        /*
        This file is to manage the quiz stage
         */

        log.debug('MiniLesson Quiz helper: initialising');

        return {

            //original spliton_regexp: new RegExp(/([,.!?:;" ])/, 'g'),
            // V2 spliton_regexp new RegExp(/([!"# ¡¿$%&'()。「」、*+,-.\/:;<=>?@[\]^_`{|}~])/, 'g'),
            //v3 we removed the apostrophe because it was not counting words correcting in listen and speak
            spliton_regexp: new RegExp(/([!"# ¡¿$%&()。「」、*+,-.\/:;<=>?@[\]^_`{|}~])/, 'g'),
            //nopunc is diff to split on because it does not match on spaces
            nopunc_regexp: new RegExp(/[!"#¡¿$%&'()。「」、*+,-.\/:;<=>?@[\]^_`{|}~]/, 'g'),
            nonspaces_regexp: new RegExp(/[^ ]/, 'g'),
            autoplaydelay: 800,

            controls: {},
            submitbuttonclass: 'mod_minilesson_quizsubmitbutton',
            stepresults: [],

            init: function (quizcontainer, activitydata, cmid, attemptid, polly) {
                this.quizdata = activitydata.quizdata;
                this.region = activitydata.region;
                this.ttslanguage = activitydata.ttslanguage;
                this.controls.quizcontainer = quizcontainer;
                this.attemptid = attemptid;
                this.courseurl = activitydata.courseurl;
                this.cmid = cmid;
                this.reattempturl = decodeURIComponent(activitydata.reattempturl).replace(/&amp;/g, "&");
                this.activityurl = decodeURIComponent(activitydata.activityurl).replace(/&amp;/g, "&");
                this.backtocourse = activitydata.backtocourse;
                this.stt_guided = activitydata.stt_guided;
                this.wwwroot = activitydata.wwwroot;
                this.useanimatecss = activitydata.useanimatecss;
                this.showitemreview = activitydata.showitemreview;
                this.stepresults = activitydata.stepresults;

                this.prepare_html();
                this.init_questions(this.quizdata, polly);
                this.register_events();
                this.start_quiz();
            },

            prepare_html: function () {

                // this.controls.quizcontainer.append(submitbutton);
                this.controls.quizfinished = $("#mod_minilesson_quiz_finished");

            },

            init_questions: function (quizdata, polly) {
                var dd = this;
                $.each(quizdata, function (index, item) {
                    switch (item.type) {
                        case def.qtype_dictation:
                            dictation.clone().init(index, item, dd, polly);
                            break;
                        case def.qtype_dictationchat:
                            dictationchat.clone().init(index, item, dd, polly);
                            break;
                        case def.qtype_multichoice:
                            multichoice.clone().init(index, item, dd);
                            break;
                        case def.qtype_multiaudio:
                            multiaudio.clone().init(index, item, dd);
                            break;
                        case def.qtype_speechcards:
                            //speechcards init needs to occur when it is visible. lame.
                            // so we do that in do_next function, down below
                            speechcards.clone().init(index, item, dd);
                            break;
                        case def.qtype_listenrepeat:
                            listenrepeat.clone().init(index, item, dd);
                            break;

                        case def.qtype_page:
                            page.clone().init(index, item, dd);
                            break;

                        case def.qtype_smartframe:
                            smartframe.clone().init(index, item, dd);
                            break;

                        case def.qtype_shortanswer:
                            shortanswer.clone().init(index, item, dd);
                            break;

                        case def.qtype_listeninggapfill:
                            listeninggapfill.clone().init(index, item, dd);
                            break;

                        case def.qtype_typinggapfill:
                            typinggapfill.clone().init(index, item, dd);
                            break;

                        case def.qtype_speakinggapfill:
                            speakinggapfill.clone().init(index, item, dd);
                            break;

                        case def.qtype_spacegame:
                            spacegame.clone().init(index, item, dd);
                            break;

                        case def.qtype_fluency:
                            fluency.clone().init(index, item, dd);
                            break;

                        case def.qtype_freespeaking:
                            freespeaking.clone().init(index, item, dd);
                            break;

                        case def.qtype_freewriting:
                            freewriting.clone().init(index, item, dd);
                            break;

                        case def.qtype_passagereading:
                            passagereading.clone().init(index, item, dd);
                            break;

                        case def.qtype_h5p:
                            h5p.clone().init(index, item, dd);
                            break;

                        case def.qtype_conversation:
                            conversation.clone().init(index, item, dd);
                            break;

                        case def.qtype_compquiz:
                            compquiz.clone().init(index, item, dd);
                            break;

                        case def.qtype_passagegapfill:
                            passagegapfill.clone().init(index, item, dd);
                            break;

                        case def.qtype_audiochat:
                            audiochat.clone().init(index, item, dd);
                            break;

                        case def.qtype_wordshuffle:
                            wordshuffle.clone().init(index, item, dd);
                            break;

                        case def.qtype_scatter:
                            scatter.clone().init(index, item, dd);
                            break;

                        case def.qtype_slides:
                            slides.clone().init(index, item, dd);
                            break;

                        case def.qtype_fiction:
                            fiction.clone().init(index, item, dd);
                            break;
                    }

                });

                //TTS in question headers
                $("audio.mod_minilesson_itemttsaudio").each(function () {
                    var that = this;
                    polly.fetch_polly_url($(this).data('text'), $(this).data('ttsoption'), $(this).data('voice')).then(function (audiourl) {
                        $(that).attr("src", audiourl);
                    });
                });

            },

            register_events: function () {
                $('.' + this.submitbuttonclass).on('click', function () {
                    //do something
                });
            },
            render_quiz_progress: function (current, total) {
                var array = [];
                for (var i = 0; i < total; i++) {
                    array.push(i);
                }

                if (total <= 1) {
                    $(".minilesson_quiz_progress").hide();
                    return;
                }

                if (total < 6) {
                    var slice = array.slice(0, 5);
                    var slicelength = slice.length > 1 ? (slice.length - 1) : slice.length;
                    var itemWidth = 100 / slicelength;
                    var innerclass, innerhtml, html = "";
                    slice.forEach(function (i) {
                        innerclass = i < current ? "minilesson_quiz_progress_completed" : "minilesson_quiz_progress_incompleted";
                        innerhtml = (i !== (slice.length - 1)) ? "<div class='" + innerclass + "' style='width: " + itemWidth + "%; '></div>" : "";
                        if (i === current) {
                            html += "<div class='minilesson_quiz_progress_current'>";
                        }
                        html += "<div class='minilesson_quiz_progress_item " +
                            (i === current ? 'minilesson_quiz_progress_item_current' : '') + " " +
                            (i < current ? 'minilesson_quiz_progress_item_completed' : '') + "'>" +
                            (i < current ? '<i class="fa fa-check"></i>' : i + 1) + "</div>";
                        if (i === current) {
                            html += "</div>";
                        }
                        html += innerhtml;
                    });
                } else {
                    if (current > total - 6) {
                        var slice = array.slice(total - 5, total - 1);
                    } else {
                        var slice = array.slice(current, current + 4);
                    }
                    var slicelength = slice.length > 1 ? (slice.length - 1) : slice.length;
                    var itemWidth = 100 / slicelength;
                    var html = "", innerhtml, innerclass;
                    var lastvalue = slice[slice.length - 1];
                    slice.forEach(function (i) {
                        if (i === current) {
                            html += "<div class='minilesson_quiz_progress_current'>";
                        }
                        html += "<div class='minilesson_quiz_progress_item " + (i === current ? 'minilesson_quiz_progress_item_current' : '') + " " + (i < current ? 'minilesson_quiz_progress_item_completed' : '') + "'>" + (i < current ? '<i class="fa fa-check"></i>' : i + 1) + "</div>";
                        innerclass = (i === lastvalue && i < total - 2) ? "minilesson_quiz_progress_dashedline" : i < current ? "minilesson_quiz_progress_completed" : "minilesson_quiz_progress_incompleted";
                        innerhtml = "<div class='" + innerclass + "' style='width: " + itemWidth + "%; '></div>";
                        if (i === current) {
                            html += "</div>";
                        }
                        html += innerhtml;
                    });
                    //end marker
                    html += "<div class='minilesson_quiz_progress_finalitem'>" + (total) + "</div>";
                }

                html += "";
                $(".minilesson_quiz_progress").html(html);

            },

            do_next: function (stepdata) {
                var dd = this;
                //get current question
                var currentquizdataindex = stepdata.index;
                var currentitem = this.quizdata[currentquizdataindex];
                //in preview mode do no do_next
                if (currentitem.preview === true) {
                    return;
                }

                //post grade
                // log.debug("reporting step grade");
                dd.report_step_grade(stepdata);
                // log.debug("reported step grade");

                //show next question or End Screen
                if (dd.quizdata.length > currentquizdataindex + 1) {
                    // we want to hide current question - before show new one
                    var theoldquestion = $("#" + currentitem.uniqueid + "_container");
                    theoldquestion.hide();

                    var nextindex = currentquizdataindex + 1;
                    var nextitem = dd.quizdata[nextindex];
                    //show the question

                    dd.showStep($("#" + nextitem.uniqueid + "_container"), nextindex);
                    //any per question type init that needs to occur can go here
                    switch (nextitem.type) {
                        case def.qtype_speechcards:
                            //speechcards.init(nextindex, nextitem, dd);
                            break;
                        case def.qtype_dictation:
                        case def.qtype_dictationchat:
                        case def.qtype_multichoice:
                        case def.qtype_multiaudio:
                        case def.qtype_listenrepeat:
                        case def.qtype_smartframe:
                        case def.qtype_shortanswer:
                        case def.qtype_spacegame:
                        case def.qtype_fluency:
                        case def.qtype_freespeaking:
                        case def.qtype_freewriting:
                        case def.qtype_passagereading:
                        case def.qtype_h5p:
                        case def.qtype_conversation:
                        case def.qtype_compquiz:
                        case def.qtype_audiochat:
                        case def.qtype_slides:
                        case def.qtype_fiction:
                        default:
                    }//end of nextitem switch
                } else {
                    //just reload and re-fetch all the data to display
                    $(".minilesson_nextbutton").prop("disabled", true);
                    window.location.href = dd.activityurl;
                    /*
                    setTimeout(function () {
                    log.debug("forwarding to finished page");
                    window.location.href=dd.activityurl;
                    }, 500);
                    */

                    return;

                    //no longer do this
                    /*
                  var results = dd.stepresults.filter(function(e){return e.hasgrade;});
                  var correctitems = 0;
                  var totalitems = 0;
                  results.forEach(function(result,i){
                    result.index=i+1;
                    result.title=dd.quizdata[i].title;
                    correctitems += result.correctitems;
                    totalitems += result.totalitems;
                  });
                  var totalpercent = Math.round((correctitems/totalitems)*100);
                  console.log(results,correctitems,totalitems,totalpercent);
                  var finishedparams ={results:results,total:totalpercent, courseurl: this.courseurl};
                  if(this.reattempturl!=''){finishedparams.reattempturl = this.reattempturl;}
                  if(this.backtocourse!=''){finishedparams.backtocourse = true;}
                  templates.render('mod_minilesson/quizfinished',finishedparams).then(
                    function(html,js){
                    dd.controls.quizfinished.html(html);
                    dd.controls.quizfinished.show();
                    templates.runTemplateJS(js);
                    }
                  );
                  */
                }//end of if has more questions

                this.render_quiz_progress(stepdata.index + 1, this.quizdata.length);

                //we want to destroy the old question in the DOM also because iframe/media content might be playing
                theoldquestion.remove();

            },

            report_step_grade: function (stepdata) {
                var dd = this;

                //store results locally
                this.stepresults.push(stepdata);

                //push results to server
                var isasync = false;
                var ret = Ajax.call([{
                    methodname: 'mod_minilesson_report_step_grade',
                    args: {
                        cmid: dd.cmid,
                        step: JSON.stringify(stepdata),
                    },
                }], isasync)[0];
                log.debug("report_step_grade success: " + ret);

            },

            showStep: function ($container, index = 0) {
                $container.show();
                $container.on('showElement', () => {
                    $container.find('[data-region="activity-wrapper"]').show();
                    $container.find('[data-region="splashscreen"]').hide();
                    //autoplay audio if we need to
                    var ttsquestionplayer = $("#" + this.quizdata[index].uniqueid + "_container audio.mod_minilesson_itemttsaudio");
                    if (ttsquestionplayer.data('autoplay') == "1") {
                        var that = this;
                        setTimeout(function () {
                            ttsquestionplayer[0].play();
                        }, that.autoplaydelay);
                    }
                });
                this.render_quiz_progress(index, this.quizdata.length);
                const $splashscreen = $container.find('[data-region="splashscreen"]');
                if ($splashscreen.length > 0) {
                    $splashscreen.show();
                    $splashscreen.on('click', '[data-action="startmodule"]', () => $container.trigger("showElement"));
                    return;
                }
                $container.trigger("showElement");
            },

            start_quiz: function () {
                const resumeindex = this.stepresults.length;
                const $container = $("#" + this.quizdata[resumeindex].uniqueid + "_container");
                this.showStep($container, resumeindex);
            },

            //this function is overridden by the calling class
            onSubmit: function () {
                alert('quiz submitted. Override this');
            },

            mobile_user: function () {

                if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
                    return true;
                } else {
                    return false;
                }
            },

            chrome_user: function () {
                if (/Chrome/i.test(navigator.userAgent)) {
                    return true;
                } else {
                    return false;
                }
            },

            //this will always be true these days
            use_ttrecorder: function () {
                return true;
            },
            is_stt_guided: function () {
                return this.stt_guided;
            },

            //count words
            count_words: function (transcript) {
                return transcript.trim().split(/\s+/).filter(function (word) {
                    return word.length > 0;
                }).length;
            },

            //text comparison functions follow===============

            similarity: function (s1, s2) {
                //we remove spaces because JP transcript and passage might be different. And who cares about spaces anyway?
                s1 = s1.replace(/\s+/g, '');
                s2 = s2.replace(/\s+/g, '');

                var longer = s1;
                var shorter = s2;
                if (s1.length < s2.length) {
                    longer = s2;
                    shorter = s1;
                }
                var longerLength = longer.length;
                if (longerLength === 0) {
                    return 100;
                }
                return 100 * ((longerLength - this.editDistance(longer, shorter)) / parseFloat(longerLength));
            },
            editDistance: function (s1, s2) {
                s1 = s1.toLowerCase();
                s2 = s2.toLowerCase();

                var costs = [];
                for (var i = 0; i <= s1.length; i++) {
                    var lastValue = i;
                    for (var j = 0; j <= s2.length; j++) {
                        if (i === 0) {
                            costs[j] = j;
                        } else {
                            if (j > 0) {
                                var newValue = costs[j - 1];
                                if (s1.charAt(i - 1) !== s2.charAt(j - 1)) {
                                    newValue = Math.min(
                                        Math.min(newValue, lastValue),
                                        costs[j]
                                    ) + 1;
                                }
                                costs[j - 1] = lastValue;
                                lastValue = newValue;
                            }
                        }
                    }
                    if (i > 0) {
                        costs[s2.length] = lastValue;
                    }
                }
                return costs[s2.length];
            },

            cleanText: function (text) {
                var lowertext = text.toLowerCase();
                var punctuationless = lowertext.replace(this.nopunc_regexp, "");
                var ret = punctuationless.replace(/\s+/g, " ").trim();
                return ret;
            },

            //this will return the promise, the result of which is an integer 100 being perfect match, 0 being no match
            checkByPhonetic: function (passage, transcript, passagephonetic, language) {
                return Ajax.call([{
                    methodname: 'mod_minilesson_check_by_phonetic',
                    args: {
                        'spoken': transcript,
                        'correct': passage,
                        'language': language,
                        'phonetic': passagephonetic,
                        'region': this.region,
                        'cmid': this.cmid
                    },
                    async: false
                }])[0];

            },

            comparePassageToTranscript: function (passage, transcript, passagephonetic, language, alternatives = "") {
                return Ajax.call([{
                    methodname: 'mod_minilesson_compare_passage_to_transcript',
                    args: {
                        passage: passage,
                        transcript: transcript,
                        alternatives: alternatives,
                        phonetic: passagephonetic,
                        language: language,
                        region: this.region,
                        cmid: this.cmid
                    },
                    async: false
                }])[0];
            },

            //this will return the promise, the result of which is an object containing marks, corrections and feedback
            evaluateTranscript: function (transcript, itemid) {
                return Ajax.call([{
                    methodname: 'mod_minilesson_evaluate_transcript',
                    args: {
                        'transcript': transcript,
                        'itemid': itemid,
                        'cmid': this.cmid
                    },
                    async: false
                }])[0];
            },

        }; //end of return value
    }
);
