// com.tts.initial.html5.quiz.button.evaluation
// HTML4 / HTML5: No differences
define( [
    "jquery",
    "./locals",
    "./accessibility.builder"
], function (
    jq,
    uiText,
    AccessibilityBuilder
) {

    "use strict";

    /**
     * @constructor
     */
    return function (context, metadata) {

		var isStandardPlayer = context.getPlayerName() === "standard",
            contentLanguage = metadata.stage.getContentLanguage(),
            isNextLearning = metadata.parameters.asBool( "next_learning" ),
            isNextAssessment = metadata.parameters.asBool( "next_assessment" ),
            instance,
            evaluateButton,
            buttonHotspot,
            mouseUpDetected = false,
            accessibilityTooltipEvaluate,
            accessibilityKeyEvaluate = metadata.parameters.get( "accessibility-key-evaluate", null ),
            accessibilityTooltipSolution,
            accessibilityKeySolution = metadata.parameters.get( "accessibility-key-solution", null ),
            accessibilityTooltipEvaluation,
            accessibilityKeyEvaluation = metadata.parameters.get( "accessibility-key-evaluation", null ),
            accessibilityLocation = metadata.parameters.asNumber( "accessibility-location", 0 ),
            accessibilityPositionX = metadata.parameters.asNumber( "accessibility-position-x", -6 ),
            accessibilityPositionY = metadata.parameters.asNumber( "accessibility-position-y", -6 ),

            ButtonMode = {
                EVALUATE: "EVALUATE",
                SUBMIT: "SUBMIT",
                GOTO_USER_SOLUTION: "GOTO_USER_SOLUTION",
                GOTO_BEST_PRACTICE_SOLUTION: "GOTO_BEST_PRACTICE_SOLUTION",
                INACTIVE: "INACTIVE"
            },

            currentMode = ButtonMode.EVALUATE,

            ButtonState = {
                Default : "btn_state_default",
                Hover : "btn_state_hover",
                Pressed : "btn_state_pressed",
                Inactive : "btn_state_inactive"
            },

            currentState = ButtonState.Inactive,

            sPageEvaluatedId = metadata.page.getId() + "_evaluated",
            sElementVariableNameSpace = "com_tts_quiz",

            pointerDownEventNames,
            pointerMoveEventNames,
            pointerUpEventNames,
            pointerReleaseEventNames,

            // in case that the display_text parameter does not exist, display the text
            // the parameter was removed from the component for a limited time span
            displayText = !metadata.parameters.get("display_text") ? true : metadata.parameters.asBool("display_text"),

            isInAuthoringMode = context.stage.isInAuthoringMode(),
            isAssessmentMode = context.stage.isInAssessmentMode(),
            isLearningMode = context.stage.isInLearningMode(),
            hasStageTrigger = !!context.stage.trigger,
            background_position = {},

            BUTTON_TEXT = {
                EVALUATE: getText("textEvaluate","player.quiz.button.evaluate"),
                SUBMIT: getText("textSubmit","player.quiz.button.submit"),
                GOTO_BEST_PRACTICE_SOLUTION: getText("textGoToSampleSolution","player.quiz.button.bestPracticeSolution"),
                GOTO_USER_SOLUTION: getText("textBackToEvaluation","player.quiz.button.userSolution")
            },
            BUTTON_TEXT_COLOR = {
                EVALUATE: metadata.parameters.get("colorEvaluate",""),
                SUBMIT: metadata.parameters.get("colorSubmit",""),
                GOTO_BEST_PRACTICE_SOLUTION: metadata.parameters.get("colorGoToSampleSolution",""),
                GOTO_USER_SOLUTION: metadata.parameters.get("colorBackToEvaluation",""),
                INACTIVE: metadata.parameters.get("colorInactive","")
            },
            BUTTON_TOOLTIP = {
                EVALUATE: getText( "tooltipEvaluate", false ),
                SUBMIT: getText( "tooltipSubmit", false ),
                GOTO_BEST_PRACTICE_SOLUTION: getText( "tooltipGotToSampleSolution", false ),
                GOTO_USER_SOLUTION: getText( "tooltipBackToEvaluation", false )
            };

        function getText( parameterName, defaultTextName ) {
            var paramValue = jq.trim( metadata.parameters.get( parameterName, "" ) );

            if ( paramValue.length > 0 ) {
                return paramValue;
            } else {
                if ( !defaultTextName ) {
                    return "";
                } else {
                    return uiText.get( defaultTextName, contentLanguage );
                }
            }
        }

        function getFontFamilyString(fontFamily) {
            switch (parseInt(fontFamily)) {
                case 2:
                    return "'Times New Roman', Times, serif";
                case 3:
                    return "Verdana, Geneva, sans-serif";
                case 4:
                    return "'Courier New', Courier, monospace";
                case 1:
                default:
            }
            return "Arial, Helvetica, sans-serif";
        }

        function isOnTarget( e ) {

            var elem = e.target,
                origEvent = e.originalEvent,
                changedTouch = origEvent.changedTouches && origEvent.changedTouches.length > 0 ? origEvent.changedTouches[0] : undefined;

            if ( changedTouch ) {
                elem = document.elementFromPoint( changedTouch.clientX, changedTouch.clientY );
            }

            return e.target === elem;
        }

        function setupShellElement() {

            var shellElement = jq(context.getElement()),
                backgroundImage = metadata.parameters.get("bg_image", null),
                backgroundFileName,
                bg_width = 200,
                bg_height = 50;

            if (backgroundImage) {
                backgroundFileName = context.stage.getSharedPath() + backgroundImage.fileName;
                bg_width = backgroundImage.width / 3;
                bg_height = backgroundImage.height / 4;
            } else {
                backgroundFileName = context.getPath() + "evaluate_button.png";
            }

            initBackgroundPositions(bg_width, bg_height);

            shellElement.css({
                "width": bg_width + "px",
                "height": bg_height + "px"
            });

            return {
                width : bg_width,
                height : bg_height,
                filename : backgroundFileName
            };
        }

        function createButton( backgroundImage ) {

            var shellElement = jq( context.getElement() ),
                button = jq(document.createElement("div"))
                    .attr({
                        "id": "evaluateQuizButton",
                        "class": "quiz-button"
                    })
                    .css({
                        "width": backgroundImage.width + "px",
                        "height": backgroundImage.height + "px",
                        "font-family": getFontFamilyString(metadata.parameters.asNumber("font-family",1)),
                        "font-size": metadata.parameters.asNumber("font-size",14) + "px",
                        "text-align": metadata.parameters.get("text_orientation","center"),
                        "box-sizing": "border-box",
                        "paddingTop": metadata.parameters.get("padding-top","15") + "px",
                        "paddingRight": metadata.parameters.get("padding-right","15") + "px",
                        "paddingLeft": metadata.parameters.get("padding-left","15") + "px",
                        "color": getButtonColor()
                    })
                    .html( getButtonText() );

            if ( metadata.parameters.asBool( "text_vertical_centered" ) ) {
                button.css( {
                    "display": "table-cell",
                    "vertical-align": "middle"
                })
            }

            if (metadata.parameters.asBool("display_background") === true) {
                button.css({
                    "background-image": "url(\"" + backgroundImage.filename + "\")",
                    "background-position": isAssessmentMode
                        ? getButtonImagePosition( ButtonMode.SUBMIT, ButtonState.Default )
                        : getButtonImagePosition( ButtonMode.EVALUATE, ButtonState.Default )
                });
            }

            shellElement.append( button );

            if ( accessibilityKeyEvaluate ) {
                accessibilityTooltipEvaluate = new AccessibilityBuilder( accessibilityKeyEvaluate, accessibilityLocation, accessibilityPositionX, accessibilityPositionY ).build();
                shellElement.append( accessibilityTooltipEvaluate.getElement() );
            }

            if ( accessibilityKeySolution ) {
                accessibilityTooltipSolution = new AccessibilityBuilder( accessibilityKeySolution, accessibilityLocation, accessibilityPositionX, accessibilityPositionY ).build();
                shellElement.append( accessibilityTooltipSolution.getElement() );
            }

            if ( accessibilityKeyEvaluation ) {
                accessibilityTooltipEvaluation = new AccessibilityBuilder( accessibilityKeyEvaluation, accessibilityLocation, accessibilityPositionX, accessibilityPositionY ).build();
                shellElement.append( accessibilityTooltipEvaluation.getElement() );
            }

            if (isInAuthoringMode) {
                createAuthoringShield(shellElement);
                return;
            }

            createButtonHotspot({
                width: backgroundImage.width,
                height: backgroundImage.height
            } );

            return {
                getRootElement : function(){
                    return button;
                },
                getHotspotElement : function(){
                    return buttonHotspot;
                },
                hasState : function( buttonState ){
                    return buttonState === currentState;
                },
                changeState : function( buttonState ){
                    if( this.hasState( buttonState ) ){
                        return;
                    }

                    var enabled = buttonState !== ButtonState.Inactive;

                    button.removeClass( currentState );
                    currentState = buttonState;
                    button.addClass( buttonState );
                    button.css({
                        "background-position" : getButtonImagePosition( currentMode, buttonState )
                    } );
                    buttonHotspot.css( {
                        "cursor": ( enabled && currentMode !== ButtonMode.INACTIVE ) ? "pointer" : "default"
                    } );
                },
                changeMode: function( buttonMode ) {
                    if( currentMode === buttonMode ){
                        return;
                    }

                    button.removeClass( currentMode );
                    currentMode = buttonMode;
                    button.addClass( buttonMode );
                    button.css({
                        "color": getButtonColor(),
                        "background-position": getButtonImagePosition( currentMode, currentState )
                    });
                }
            };
        }

        function getButtonText(){
            if( !displayText || typeof(BUTTON_TEXT[currentMode]) === "undefined"){
                return "";
            }

            return BUTTON_TEXT[currentMode];
        }

        function getButtonTooltip() {
            if ( typeof ( BUTTON_TEXT[currentMode] ) === "undefined" ) {
                return "";
            }
            return BUTTON_TOOLTIP[currentMode];
        }

        function getButtonColor(){
            if( !displayText || typeof(BUTTON_TEXT_COLOR[currentMode]) === "undefined"){
                return "";
            }

            return BUTTON_TEXT_COLOR[currentMode];
        }

        function createButtonHotspot( size ){

            var shellElement = jq(context.getElement());

            buttonHotspot = jq(document.createElement("div"))
                .attr({
                    "class": "quiz-button-hotspot",
                    "title": getButtonTooltip()
                })
                .css({
                    "position": "absolute",
                    "left": "0",
                    "top": "0",
                    "background-color": "#ffffff",
                    "opacity": "0.0",
                    "width": size.width + "px",
                    "height": size.height + "px"
                });

            shellElement.append( buttonHotspot );
        }

        function lockNavigation() {
            if (isInAuthoringMode || !hasStageTrigger) {
                return;
            }
            context.stage.trigger.lock(metadata.getId());
        }

        function unlockNavigation() {
            if (isInAuthoringMode || !hasStageTrigger) {
                return;
            }
            context.stage.trigger.unlock(metadata.getId());
        }

        function preventDefault(e) {
            e.preventDefault ? e.preventDefault() : true;
        }

        function initBackgroundPositions( tileImageWidth, tileImageHeight ) {

            var buttonOrder = [
                    "EVALUATE",
                    "GOTO_BEST_PRACTICE_SOLUTION",
                    "GOTO_USER_SOLUTION",
                    "SUBMIT"
                ],
                buttonPosX = -1 * tileImageWidth,
                buttonPosY = - 1 * tileImageHeight,
                currentButtonName,
                stateIndex;

            background_position = {};
            jq.each( buttonOrder, function( orderIndex, buttonName ){
                stateIndex = 0;
                jq.each( ButtonState, function( key, buttonState ){
                    currentButtonName = buttonName + "_" + buttonState;
                    background_position[ currentButtonName.toUpperCase() ] = (orderIndex * buttonPosX) + "px " + (stateIndex * buttonPosY) + "px";
                    stateIndex++;
                });
            });
        }

        // create an object shield so we are able to select and drag element
        function createAuthoringShield(shellElement) {
            var objShield = jq(document.createElement("div"))
                .css({
                    "position": "absolute",
                    "left": "0",
                    "top": "0",
                    "background-color": "#ffffff",
                    "opacity": "0.4",
                    "width": "100%",
                    "height": "100%",
                    "z-index": "9999"
                });

            if (metadata.parameters.asBool("display_background") === false ) {
                objShield.css({
                    "background-image": "url(\"" + context.getPath() + "invis.png\")"
                });
            }
            shellElement.append(objShield);
        }

        function getButtonImagePosition( buttonMode, state ){
            return background_position[ buttonMode + "_" + state.toUpperCase() ];
        }

        function getHotspotElementNodeName() {
            return evaluateButton.getHotspotElement().get()
                ? evaluateButton.getHotspotElement().get(0).nodeName
                : "document";
        }

        function initPointerEventNames() {
            if( pointerDownEventNames ) {
                return;
            }

            var nodeName = getHotspotElementNodeName();
            pointerDownEventNames = context.device.getDownEvents( nodeName );
            pointerUpEventNames = context.device.getUpEvents( nodeName );
            pointerMoveEventNames = context.device.getMoveEvents( nodeName );
            pointerReleaseEventNames = context.device.getReleaseEvents( nodeName );
        }

        function onMouseLeave() {
            unlockNavigation();

            if( isEnabled() ) {
                evaluateButton.changeState( ButtonState.Default );
            }
        }

        function onMouseOver() {
            if( isEnabled() && !evaluateButton.hasState( ButtonState.Pressed ) ) {
                evaluateButton.changeState( ButtonState.Hover );
            }
        }

        function onMouseDown() {
            lockNavigation();

            if( isEnabled() ) {
                evaluateButton.changeState( ButtonState.Pressed );
            }

            return true;
        }

        function triggerButton() {
            if ( !isEnabled() ) {
                return;
            }

            context.stage.accessibility.turnAccessibilityModeOff();

            if ( currentMode === ButtonMode.EVALUATE || currentMode === ButtonMode.SUBMIT ) {
                context.page.quiz.evaluate();

                if ( ( isAssessmentMode && isNextAssessment ) || ( isLearningMode && isNextLearning ) ) {
                    var isMainPath = true,
                        getLearningPath;

                    if ( metadata.page && typeof metadata.page.getLearningPath === "function" ) {
                        getLearningPath = metadata.page.getLearningPath();
                        if ( typeof getLearningPath.isMainLearningPath === "function" ) {
                            isMainPath = getLearningPath.isMainLearningPath();
                        }
                    }
                    ( isLastPage() && isMainPath ) ?
                        context.stage.navigation.terminate() :
                        context.stage.navigation.nextPage();
                }
            }
            else if ( currentMode === ButtonMode.GOTO_BEST_PRACTICE_SOLUTION ) {
                context.page.quiz.switchToBestPracticeSolution();
            }
            else if ( currentMode === ButtonMode.GOTO_USER_SOLUTION ) {
                context.page.quiz.switchToUserSolution();
            }
        }

        function onMouseUp(e) {
            mouseUpDetected = wasMouseEvent(e);

            unlockNavigation();

            if( !isEnabled() ) {
                return;
            }

            evaluateButton.changeState( ButtonState.Hover );

            if ( !isOnTarget(e) ) {
                return;
            }

            triggerButton();
        }

        function isLastPage() {

            var allPages = metadata.stage.pages,
                lastPage;

            if ( !allPages || allPages.length === 0 ) {
                return false;
            }

            lastPage = allPages[allPages.length - 1];

            return lastPage.getId() === metadata.page.getId();
        }

        function wasMouseEvent( jqEvent ){
            return (jqEvent && jqEvent.originalEvent.pointerType) ? jqEvent.originalEvent.pointerType === "mouse" : false;
        }

        function bindEvents() {

            if( isInAuthoringMode || !buttonHotspot ) {
                return;
            }

            removeEvents();
            context.device.attachFirstSupportedEvent( evaluateButton.getHotspotElement(), pointerDownEventNames, onMouseDown );
            context.device.attachFirstSupportedEvent( evaluateButton.getHotspotElement(), pointerMoveEventNames, onMouseOver );
            context.device.attachSupportedEvents( evaluateButton.getHotspotElement(), pointerReleaseEventNames, onMouseLeave );
            context.device.attachFirstSupportedEvent( evaluateButton.getHotspotElement(), pointerUpEventNames, onMouseUp );
        }

        function removeEvents() {

            if(!buttonHotspot) {
                return;
            }

            initPointerEventNames();

            context.device.removeFirstSupportedEvent( evaluateButton.getHotspotElement(), pointerDownEventNames, onMouseDown );
            context.device.removeFirstSupportedEvent( evaluateButton.getHotspotElement(), pointerMoveEventNames, onMouseOver );
            context.device.removeSupportedEvents( evaluateButton.getHotspotElement(), pointerReleaseEventNames, onMouseLeave );
            context.device.removeFirstSupportedEvent( evaluateButton.getHotspotElement(), pointerUpEventNames, onMouseUp );
        }

        function refreshButton() {
            evaluateButton.getRootElement()
                .html( getButtonText() )
                .show()

            buttonHotspot.attr( { "title": getButtonTooltip() } );
        }

        function showEvaluateButton() {
            enableButton( isAssessmentMode ? ButtonMode.SUBMIT : ButtonMode.EVALUATE );
        }

        function showGotoUserSolutionButton() {
            enableButton( ButtonMode.GOTO_USER_SOLUTION );
        }

        function showGotoBestPracticeSolutionButton() {
            enableButton( ButtonMode.GOTO_BEST_PRACTICE_SOLUTION );
        }

        function showSubmitExceededButton() {
            if( displayText ) {
                evaluateButton.getRootElement()
                    .html( getText( "textSubmitExceeded", "player.quiz.button.submitExceeded" ) )
            }

            buttonHotspot.attr( { "title": getText( "tooltipSubmitExceeded", false ) } )

            disableButton();
        }

        function hideButton() {
            evaluateButton.getRootElement().hide();
            removeEvents();
        }

        function isEnabled() {
            return currentState !== ButtonState.Inactive;
        }

        function enableButton( buttonMode ) {
            evaluateButton.changeState( ButtonState.Default );
            evaluateButton.changeMode( buttonMode );
            refreshButton();
            bindEvents();
        }

        function disableButton() {
            if( !isEnabled() ){
                return;
            }

            evaluateButton.changeState( ButtonState.Inactive );
            evaluateButton.changeMode( ButtonMode.INACTIVE );
            removeEvents();
        }

        function isEvaluated() {

            if (context.stage.isInPreviewMode()) {
                return false;
            }

            if (isStandardPlayer) {
                return context.stage.variable.get(sPageEvaluatedId, sElementVariableNameSpace);
            }

            return context.page.quiz.hasQuestion() && context.page.quiz.getQuestion().isFinalized();
        }

        function setMouseOverState(){
            if( mouseUpDetected ) {
                evaluateButton.changeState( ButtonState.Hover );
                mouseUpDetected = false;
            }
        }

        function switchToUserSolution() {
            context.page.event.trigger(instance, "switch_to_evaluation");

            if ( isAssessmentMode ) {
                showSubmitExceededButton();
                setMouseOverState();
                return;
            }

            if (metadata.parameters.asNumber("enable_sample_solution", 1)) {
                showGotoBestPracticeSolutionButton();
                setMouseOverState();
                return;
            }

            disableButton();
        }

        function switchToBestPracticeSolution() {

            context.page.event.trigger(instance, "switch_to_sample_solution");

            if (metadata.parameters.asNumber("enable_sample_solution", 1)) {
                showGotoUserSolutionButton();
                setMouseOverState();
            }
            else {
                disableButton();
            }
        }

        function createDOM(){

            var bgImage = setupShellElement();

            evaluateButton = createButton( bgImage );

            if (isInAuthoringMode) {
                return;
            }

            hideButton();
        }

        function bindApiEvents(){

            if (isInAuthoringMode) {
                return;
            }

            context.page.event.bindOnEnter(instance);
            context.page.quiz.event.bindOnEvaluateTestRun(instance);
            context.page.quiz.event.bindOnUserSolution(instance);
            context.page.quiz.event.bindOnBestPracticeSolution(instance);
        }

        // revealing public API
        return {
            onLoading: function () {
                instance = this;
                createDOM();
                bindApiEvents();
                context.stage.accessibility.bindOnAccessibilityModeChanged( this );
            },

            onEnterPage: function () {
                if (!isStandardPlayer && !context.page.quiz.hasQuestion()) {
                    hideButton();
                    return;
                }

                if (isEvaluated()) {

                    (currentMode === ButtonMode.GOTO_BEST_PRACTICE_SOLUTION) ? switchToUserSolution() : switchToBestPracticeSolution();

                    if (isAssessmentMode) {
                        showSubmitExceededButton();
                    }

                    return;
                }

                showEvaluateButton();
            },

            onExitPage: function() {
                removeEvents();
                context.stage.accessibility.turnAccessibilityModeOff();
            },

            onEvaluateTestRun : function( dataHTML5 ){

                context.page.event.trigger(instance, "evaluation");
                if ( isStandardPlayer ) {
                    return;
                }

                if ( dataHTML5.isFinalized || dataHTML5.currentTestRun >= dataHTML5.testRuns) {
                    context.page.quiz.switchToUserSolution();
                }
            },

            onUserSolution: switchToUserSolution,
            onBestPracticeSolution: switchToBestPracticeSolution,

            onAccessibilityModeChanged: function ( dataHTML5, dataHTML4 ) {
                var params = dataHTML4 || dataHTML5;

                if ( params.isActive ) {
                    if ( ( currentMode === ButtonMode.EVALUATE || currentMode === ButtonMode.SUBMIT ) ) {
                        accessibilityTooltipEvaluate.show();
                        accessibilityTooltipSolution.hide();
                        accessibilityTooltipEvaluation.hide();
                    }
                    else if ( currentMode === ButtonMode.GOTO_BEST_PRACTICE_SOLUTION ) {
                        accessibilityTooltipSolution.show();
                        accessibilityTooltipEvaluate.hide();
                        accessibilityTooltipEvaluation.hide();
                    }
                    else if ( currentMode === ButtonMode.GOTO_USER_SOLUTION ) {
                        accessibilityTooltipEvaluation.show();
                        accessibilityTooltipEvaluate.hide();
                        accessibilityTooltipSolution.hide();
                    }
                } else {
                    accessibilityTooltipEvaluate.hide();
                    accessibilityTooltipSolution.hide();
                    accessibilityTooltipEvaluation.hide();
                }
            },
            onAccessibilityKeyPressed: function ( dataHTML5, dataHTML4 ) {
                var params = dataHTML4 || dataHTML5;

                if ( ( currentMode === ButtonMode.EVALUATE || currentMode === ButtonMode.SUBMIT ) && params.keyCode == accessibilityTooltipEvaluate.getKeyCode() ) {
                    triggerButton();
                }
                else if ( currentMode === ButtonMode.GOTO_BEST_PRACTICE_SOLUTION && params.keyCode == accessibilityTooltipSolution.getKeyCode() ) {
                    triggerButton();
                }
                else if ( currentMode === ButtonMode.GOTO_USER_SOLUTION && params.keyCode == accessibilityTooltipEvaluation.getKeyCode()) {
                    triggerButton();
                }
            }
        };
    };
});
