// com.tts.initial.html5.sound.onoff
// HTML4 / HTML5: No differences
define([
    "jquery",
    "./locals",
    "./button.state",
    "./button.toggle.state",
    "./image.button.builder",
    "./svg.button.builder",
    "./accessibility.builder"
],
function(
    jq,
    uiText,
    ButtonState,
    ButtonToggleState,
    ImageButtonBuilder,
    SvgButtonBuilder,
    AccessibilityBuilder
){

    "use strict";

    /**
     * @constructor
     */
    return function (context, metadata) {
        var shellElement,
            instance,
			enabled = true,
            button,
            buttonInitialized = false,
            isStandardPlayer = context.getPlayerName() === "standard",
            hasStageTriggerSupport = true,
            isInAuthoringMode = false,
            pointerUpEventName,
            pointerDownEventName,
            pointerMoveEventNames,
            pointerLeaveEventNames,
            accessibilityTooltip,
            accessibilityTabOrder = metadata.parameters.asNumber("tab-order", -1),
            exludeFromTabControl = metadata.parameters.asBool("exclude-from-tab-control", false),
            accessibilityKey = metadata.parameters.get("accessibility-key", "KeyNone"),
            accessibilityLocation = metadata.parameters.asNumber( "accessibility-location", 0 ),
            accessibilityPositionX = metadata.parameters.asNumber( "accessibility-position-x", -6 ),
            accessibilityPositionY = metadata.parameters.asNumber( "accessibility-position-y", -6 );

        function loadBackgroundImage() {

            var deferred = jq.Deferred(),
                defaultImage = new Image(),
                metadataParameters = metadata.parameters,
                backgroundImage = metadataParameters.get("bg_image", null),
                backgroundFileName,
                result = {};

            defaultImage.onload = function() {
                result.width = this.width / 2;
                result.height = this.height / 4;
                deferred.resolve(result);
            };

            if (backgroundImage) {
                backgroundFileName = context.stage.getSharedPath() + backgroundImage.fileName;
            }
            else {
                backgroundFileName = context.getPath() + "sound_on_off.png";
            }

            result.fileName = backgroundFileName;
            defaultImage.src = backgroundFileName;

            return deferred.promise();
        }

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

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

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

        function onMouseOver() {
            if( enabled && !button.hasState( ButtonState.Pressed ) ) {
                button.changeState( ButtonState.Hover, getCurrentAudioToggleState() );
            }
		}

        function onMouseLeave() {
            unlockNavigation();
            if( enabled ) {
                button.changeState( ButtonState.Default, getCurrentAudioToggleState() );
			}
        }

        function onMouseDown(e) {
            cancelEvent(e);
            lockNavigation();
            button.changeState( ButtonState.Pressed, getCurrentAudioToggleState() );
        }

        function getCurrentAudioToggleState(){
            return context.stage.audio.isOn() ? ButtonToggleState.On : ButtonToggleState.Off;
        }

        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 onMouseUp(e) {

            cancelEvent(e);
            unlockNavigation();

            if( !enabled ) {
                return;
            }

            if(isOnTarget(e)) {
                button.changeState( ButtonState.Hover, getCurrentAudioToggleState() );
                toggleAudio();
            }
            else {
                button.changeState( ButtonState.Default, getCurrentAudioToggleState() );
            }
        }

        function toggleAudio() {
            context.stage.accessibility.turnAccessibilityModeOff();

            if( context.stage.audio.isOn() ){
                context.stage.audio.off();
                fireTriggerOnAudioOff();
            }
            else {
                context.stage.audio.on();
                fireTriggerOnAudioOn();
            }
        }

        function fireTriggerOnAudioOn() {
            setTimeout( function () {
                context.page.event.trigger( instance, "tg_audioon" );
            }, 10 );
        }

        function fireTriggerOnAudioOff() {
            setTimeout( function () {
                context.page.event.trigger( instance, "tg_audiooff" );
            }, 10 );
        }

        function initPointerEventNames() {
            if( !pointerUpEventName ) {
                var nodeName = getHotspotElementNodeName();
                pointerDownEventName = context.device.getDownEvents( nodeName );
                pointerUpEventName = context.device.getUpEvents( nodeName );
                pointerMoveEventNames = context.device.getMoveEvents( nodeName );
                pointerLeaveEventNames = context.device.getReleaseEvents( nodeName );
            }
        }

        function getHotspotElementNodeName() {
            return button.getHotspotElement().nodeName
                ? button.getHotspotElement().nodeName
                : "document";
        }

        function cancelEvent( e ){
            e.preventDefault();
            e.stopPropagation();
        }

        function bindEvents() {

            if (context.stage.isInAuthoringMode()) {
                return;
            }

            if (!button || !buttonInitialized) {
                return;
            }

            removeEvents();
            context.device.attachFirstSupportedEvent( button.getHotspotElement(), pointerDownEventName, onMouseDown );
            context.device.attachFirstSupportedEvent( button.getHotspotElement(), pointerMoveEventNames, onMouseOver );
            context.device.attachFirstSupportedEvent( button.getHotspotElement(), pointerLeaveEventNames, onMouseLeave );
            context.device.attachFirstSupportedEvent( button.getHotspotElement(), pointerUpEventName, onMouseUp );

            jq(button.getHotspotElement()).on("dblclick", cancelEvent );
        }

        function removeEvents() {
            unlockNavigation();
            if (!button || !buttonInitialized) {
                return;
            }

            initPointerEventNames();
            context.device.removeFirstSupportedEvent( button.getHotspotElement(), pointerDownEventName, onMouseDown );
            context.device.removeFirstSupportedEvent( button.getHotspotElement(), pointerMoveEventNames, onMouseOver );
            context.device.removeFirstSupportedEvent( button.getHotspotElement(), pointerLeaveEventNames, onMouseLeave );
            context.device.removeFirstSupportedEvent( button.getHotspotElement(), pointerUpEventName, onMouseUp );

            jq(button.getHotspotElement()).off("dblclick", cancelEvent );
        }

        function initializeButton(){

        	if( buttonInitialized ){
                return;
            }
            buttonInitialized = true;

            shellElement.css({
                "width": metadata.getWidth() + "px",
                "height": metadata.getHeight() + "px"
                });

            button = metadata.parameters.asBool("use_svg") ? createSvgButton() : createImageButton();
            shellElement.append( button.getHotspotElement() );

            accessibilityTooltip = new AccessibilityBuilder(accessibilityKey, accessibilityLocation, accessibilityPositionX, accessibilityPositionY, context).build();
            if ( accessibilityTooltip.getElement() ) {
                shellElement.append( accessibilityTooltip.getElement() );
            }

            context.page.interaction.provokesFeedback( button.getHotspotElement(), false );
            context.page.interaction.provokesAutosolve( button.getHotspotElement(), false );

            if (isInAuthoringMode) {
                createAuthoringShield( shellElement );
            }

            button.changeState( ButtonState.Default, getCurrentAudioToggleState() );
            }

        function createImageButton(){

            var scParams = metadata.parameters,
                imageButton = new ImageButtonBuilder({
                    width: metadata.getWidth(),
                    height: metadata.getHeight(),
                    caption: uiText.get("player.sound.on", metadata.stage.getContentLanguage()),
                    captionOff: uiText.get("player.sound.off", metadata.stage.getContentLanguage()),
                    ariaLabel: ((metadata.parameters.get("aria-label", false) || "").trim() === "") ? false : metadata.parameters.get("aria-label", false),
                    ariaLabelOff: ((metadata.parameters.get("aria-label-off", false) || "").trim() === "") ? false : metadata.parameters.get("aria-label-off", false),
                    id: "svg_sound_onoff" + "_" + metadata.getId(),
                    color : scParams.get("color", "#919191"),
                    text : {
                        content : scParams.get("text", ""),
                        fontFamily : getFontStyle( scParams.asNumber("font-family", "1") ),
                        fontSize : scParams.asNumber("font-size", "14"),
                        orientation : scParams.get("text_orientation", "center"),
                        verticalAlignment: scParams.get("text_vertical_align", "middle"),
                        paddingLeft : Math.abs(scParams.asNumber("padding-left", "10")),
                        paddingRight : Math.abs(scParams.asNumber("padding-right", "10")),
                        paddingTop : Math.abs(scParams.asNumber("padding-top", "10")),
                        paddingBottom : Math.abs(scParams.asNumber("padding-bottom", "10"))
                    }
                }).build();

            loadBackgroundImage().then( function( buttonImage ) {
                applyButtonImage( buttonImage );
                });

            return imageButton;
        }

        function createSvgButton() {

            var scParams = metadata.parameters;

            return new SvgButtonBuilder({
                id: "svg_sound_onoff" + "_" + metadata.getId(),
                width: metadata.getWidth(),
                height: metadata.getHeight(),
                caption: uiText.get("player.sound.on", metadata.stage.getContentLanguage()),
                captionOff: uiText.get("player.sound.off", metadata.stage.getContentLanguage()),
                ariaLabel: ((metadata.parameters.get("aria-label", false) || "").trim() === "") ? false : metadata.parameters.get("aria-label", false),
                ariaLabelOff: ((metadata.parameters.get("aria-label-off", false) || "").trim() === "") ? false : metadata.parameters.get("aria-label-off", false),
                colors: {
                    default: {
                        icon: scParams.get("color_svg_icon_default", "#ffffff"),
                        bg: scParams.get("color_svg_background_default", "#707070")
                    },
                    hover: {
                        icon: scParams.get("color_svg_icon_hover", "#ffffff"),
                        bg: scParams.get("color_svg_background_hover", "#fd7e2f")
                    },
                    pressed: {
                        icon: scParams.get("color_svg_icon_pressed", "#ffffff"),
                        bg: scParams.get("color_svg_background_pressed", "#df7a3b")
                    },
                    inactive: {
                        icon: scParams.get("color_svg_icon_inactive", "#a9a9a9"),
                        bg: scParams.get("color_svg_background_inactive", "#707070")
            }
        }
            }).build();
        }

        function getFontStyle( paramValue ) {
            switch( paramValue ) {
                case 2:
                    return "\"Times New Roman\", Times, serif";
                case 3:
                    return "Verdana, Geneva, sans-serif";
                case 4:
                    return "\"Courier New\", Courier, monospace";
                default:
                    return "Arial, Helvetica, sans-serif";
            }
        }

        function applyButtonImage( buttonImage ){

            var buttonWidth = buttonImage.width,
                buttonHeight = buttonImage.height;

            shellElement.css({
                "width": buttonWidth + "px",
                "height": buttonHeight + "px"
            });

            button.changeImage( buttonWidth, buttonHeight, buttonImage.fileName );
        }

        function isFirstPage() {

            if( !metadata.page || !metadata.page.getId ){
                return false;
            }

            var currentPageId = metadata.page.getId(),
                firstPage = getFirstPageInLearningPath( currentPageId );

            return firstPage && firstPage.getId() === currentPageId;
        }

        function getFirstPageInLearningPath( currentPageId ){

            if( typeof metadata.page.getLearningPath === "function") {
                var currentLearningPath = metadata.page.getLearningPath(currentPageId);
                return currentLearningPath ? currentLearningPath.pages[0] : null;
            }

            if(metadata.stage && metadata.stage.pages) {
                return metadata.stage.pages[0];
            }

            return null;
        }

        function isMainLearningPath() {
            var currentLearningPath = (isStandardPlayer) ? metadata.page.getLearningPath() : metadata.stage,
                isMainPath = true;

            try {
                if (typeof currentLearningPath.isMainLearningPath === "function") {
                    isMainPath = currentLearningPath.isMainLearningPath();
                }
            }
            catch (err) {
                isMainPath = true;
            }

            return isMainPath;
        }

        // revealing public API
        return {
            onLoading: function () {
                instance = this;
                context.page.event.bindOnEnter(this);
                context.page.event.bindOnExit(this);
                context.stage.event.bindOnAudioControlChanged( this );
                context.stage.accessibility.bindOnAccessibilityModeChanged(this);
                if (!isStandardPlayer) {
                    context.page.event.bind(instance, "onTabNavigationOff");
                    context.page.event.bind(instance, "onTabNavigationSelection");
                    context.page.event.bind(instance, "onTabNavigationFire");
                }

                hasStageTriggerSupport = !!context.stage.trigger;
                isInAuthoringMode = !!context.stage.isInAuthoringMode();

                shellElement = jq(context.getElement());

                // because of some problems with loading SVG while it is hidden on page,
                // we initialize SVG button onEnterPage
                if (!isStandardPlayer || isInAuthoringMode) {
                    initializeButton();
                }
            },
            onEnterPage: function () {

                // context.stage.audio.isOn() Api method returns wrong initial state on pages
                // where no sound objects are placed on, until it is set once manually.
                // so if we are on first page, we set it to on once
                if( isFirstPage() && isMainLearningPath() ) {
                    var soundStateHasBeenInitialized = context.stage.variable.get('soundOnOffInitialStateHack', 'tts.soundOnOffButton');
                    if( !soundStateHasBeenInitialized ) {
                        context.stage.audio.on();
                        context.stage.variable.set('soundOnOffInitialStateHack', true, 'tts.soundOnOffButton');
                    }
                }

                // because of some problems with loading SVG while it is hidden on page,
                // we initialize SVG button onEnterPage
				if( isStandardPlayer ) {
                    initializeButton();
                }

                onMouseLeave();

                bindEvents();

                if (!isStandardPlayer && !exludeFromTabControl) {
                    accessibilityTooltip.registerTabNavigation(metadata.getId(), accessibilityTabOrder);
                }

				unlockNavigation();

                if ( context.stage.audio.isOn() ) {
                    fireTriggerOnAudioOff();
                } else {
                    fireTriggerOnAudioOn();
                }
            },
            onExitPage: function() {
                removeEvents();
            },
            onAudioControlChanged: function() {
                button.changeState( null, getCurrentAudioToggleState() );

                if ( context.stage.audio.isOn() ) {
                    fireTriggerOnAudioOff();
                } else {
                    fireTriggerOnAudioOn();
                }
            },
            onAccessibilityModeChanged: function ( dataHTML5, dataHTML4 ) {
                var params = dataHTML4 || dataHTML5;

                if ( params.isActive ) {
                    accessibilityTooltip.show();
                } else {
                    accessibilityTooltip.hide();
                }
            },
            onAccessibilityKeyPressed: function ( dataHTML5, dataHTML4 ) {
                var params = dataHTML4 || dataHTML5;

                if (params.keyCode == accessibilityTooltip.getKeyCode()) {
                    button.changeState(ButtonState.Hover, getCurrentAudioToggleState());
                    toggleAudio();
                }
            },
            onTabNavigationSelection: function (dataHTML5, dataHTML4, data) {
                if (data && data.id && data.id == metadata.getId()) {
                    button.focusButton();
                } else {
                    button.blurButton();
                }
            },
            onTabNavigationOff: function (dataHTML5, dataHTML4) {
                button.blurButton();
            },
            onTabNavigationFire: function (dataHTML5, dataHTML4, data) {
                if (data && data.id && data.id == metadata.getId()) {
                    button.changeState(ButtonState.Hover, getCurrentAudioToggleState());
                    toggleAudio();
                }
            }
        };
    };
});
