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

    "use strict";

	var ButtonState = {
            Default : "btn_state_default",
            Hover : "btn_state_hover",
            Pressed : "btn_state_pressed"
        },
        ButtonToggleState = {
            On : "btn_state_on",
            Off : "btn_state_off"
        },
        isIOS = (/iphone|ipad|ipod/i.test( navigator.userAgent.toLowerCase() ) ),
        variableID,
        variableNamespace,
               
//Was macht das hier?
        getClassName = function( toggleState, buttonState ){
            return toggleState + "_" + buttonState;
        },

        ButtonBuilder = function( options ){

            var backgroundColors = {},
                textColors = {},
                textContent = {};

            backgroundColors[ ButtonToggleState.On ] = {};
            backgroundColors[ ButtonToggleState.On ][ ButtonState.Default ] = options.colorOn.background;
            backgroundColors[ ButtonToggleState.On ][ ButtonState.Hover ] = options.colorOn.backgroundHover;
            backgroundColors[ ButtonToggleState.On ][ ButtonState.Pressed ] = options.colorOn.backgroundPressed;

            backgroundColors[ ButtonToggleState.Off ] = {};
            backgroundColors[ ButtonToggleState.Off ][ ButtonState.Default ] = options.colorOff.background;
            backgroundColors[ ButtonToggleState.Off ][ ButtonState.Hover ] = options.colorOff.backgroundHover;
            backgroundColors[ ButtonToggleState.Off ][ ButtonState.Pressed ] = options.colorOff.backgroundPressed;

            textColors[ ButtonToggleState.On ] = {};
            textColors[ ButtonToggleState.On ][ ButtonState.Default ] = options.colorOn.text;
            textColors[ ButtonToggleState.On ][ ButtonState.Hover ] = options.colorOn.textHover;
            textColors[ ButtonToggleState.On ][ ButtonState.Pressed ] = options.colorOn.textPressed;

            textColors[ ButtonToggleState.Off ] = {};
            textColors[ ButtonToggleState.Off ][ ButtonState.Default ] = options.colorOff.text;
            textColors[ ButtonToggleState.Off ][ ButtonState.Hover ] = options.colorOff.textHover;
            textColors[ ButtonToggleState.Off ][ ButtonState.Pressed ] = options.colorOff.textPressed;

            textContent[ ButtonToggleState.On ] = options.textOn.content;

            textContent[ ButtonToggleState.Off ] = options.textOff.content;

            function createTextContent() {

                if (jq.trim(options.textOff.content) === "") {
                    return "";
                }

                var textContainer = "";
                if (options.textParams.verticalAlignment === "middle") {
                    textContainer = jq(document.createElement("div"))
                        .attr({
                            "id" : "textContent" + options.id
                        })
                        .css({
                            "width": "auto",
                            "padding-right": options.textParams.paddingRight + "px",
                            "padding-left": options.textParams.paddingLeft + "px",
                            "vertical-align": "middle",
                            "display": "table-cell"
                        });
                }
                else {
                    textContainer = jq(document.createElement("div"))
                        .attr({
                            "id" : "textContent" + options.id
                        })
                        .css({
                            "position": "absolute",
                            "padding": options.textParams.paddingTop + "px " + options.textParams.paddingRight + "px " + options.textParams.paddingBottom + "px " + options.textParams.paddingLeft + "px"
                        });

                    if (options.textParams.verticalAlignment === "bottom" || options.textParams.verticalAlignment === "top" ) {
                        textContainer.css(options.textParams.verticalAlignment, "0");
                    }

                    if( options.textParams.orientation === "right" ) {
                        textContainer.css(options.textParams.orientation, "0");
                    }
                }

                if(options.tooltip){
                    textContainer
                        .attr({
                            "title" : options.tooltip
                        })
                }

                textContainer.html(options.textOff.content);
                return textContainer;
            }

            function createButton() {

                var currentState = ButtonState.Default,
                    currentToggleState = ButtonToggleState.Off,
                    button = jq(document.createElement("div"))
                        .attr({
                            "class" : currentState
                        })
                        .css({
                        "width": options.width + "px",
                        "height": options.height + "px",
                        "text-align": options.textParams.orientation,
                        "font-family": options.textParams.fontFamily,
                        "color": options.colorOff.text,
                        "background-color": options.colorOff.background,
                        "-webkit-tap-highlight-color": "rgba(0,0,0,0)",
                        "font-size": Math.min( Math.abs(options.textParams.fontSize), 100) + "px",
                        "cursor": "pointer"
                    })
                    
                    .on("touchmove", function(e) {
                        e.preventDefault ? e.preventDefault() : true;
                    });

                if (options.textParams.verticalAlignment === "middle") {
                    button.css("display", "table");
                }

                if(options.initialState == ButtonToggleState.Off && !options.state.saved) {
                    currentToggleState = ButtonToggleState.Off;
                }else{
                    if(options.initialState == ButtonToggleState.On && !options.state.saved) {
                        currentToggleState = ButtonToggleState.On;
                    }else{
                        if(options.state.saved) {
                            currentToggleState == options.state.saved;
                        }else{
                            currentToggleState = ButtonToggleState.Off;
                        }
                    }
                }

                if(options.tooltip){
                    button
                        .attr({
                            "title" : options.tooltip
                        })
                }

                button.append( createTextContent() );

                return {
                    getRootElement : function(){
                        return button;
                    },
                    getHotspotElement : function(){
                        return button;
                    },
                    getCurrentToggleState : function(){
                        return currentToggleState;
                    },
                    getVariableID : function(){
                        return variableID;
                    },
                    getVariableNamespace : function(){
                        return variableNamespace;
                    },
                    hasState : function( buttonState ){
                        return buttonState === currentState;
                    },
                    hasToggleState : function( buttonToggleState ){
                        return buttonToggleState === currentToggleState;
                    },
                    changeState : function( buttonState, toggleState ){
                        if( !toggleState ){
                            toggleState = currentToggleState;
                        }
            
                        if( !buttonState ){
                            buttonState = currentState;
                        }
            
                        var oldClassName = getClassName( currentToggleState, currentState ),
                            newClassName = getClassName( toggleState, buttonState );
            
                        button.removeClass( oldClassName );
                        currentState = buttonState;
                        currentToggleState = toggleState;
                        button.addClass( newClassName );
            
                        button.css({
                            "background-color": backgroundColors[toggleState][buttonState],
                            "color": textColors[toggleState][buttonState],
                            "cursor": "pointer"
                        });
                        button.children("#textContent" + options.id).html(textContent[toggleState]);
                    }
                };
            }

            return {
                build : createButton
            };
        },
        
        EventUtil = (function() {

        function getFirstSupportedEvent(tagName, eventNames) {
            var result = "";
            jq.each(eventNames.split(" "), function (i, evtName) {
                if (isEventSupported(evtName, tagName)) {
                    result = evtName;
                    return false;
                }
            });
            return result;
        }

        function isEventSupported(eventName, tagName) {
            var elem = tagName ? document.createElement(tagName) : document,
                onEventName = "on" + eventName,
                isSupported;

            isSupported = !!(onEventName in elem);
            if (!isSupported && typeof elem.setAttribute !== "undefined") {
                elem.setAttribute(onEventName, "return;");
                isSupported = typeof elem[onEventName] === "function";
            }

            return isSupported;
        }

        return {
            /**
             * Attach the event handler <b>handler</b> for the first supported event specified by <b>eventNames</b>
             * to the element <b>jqObject</b>.
             * Example: attachFirstSupportedEvent( myObject, "pointerdown mousedown touchend", myHandler );
             *
             * @param element
             * @param {String} eventNames
             * @param handler
             * @return {String} the event name or ""
             */
            attachFirstSupportedEvent: function (element, eventNames, handler) {
                var jqObject = jq(element),
                    evtName = getFirstSupportedEvent(element.nodeName, eventNames);

                if (!evtName) {
                    return "";
                }

                jqObject.on(evtName, handler);
                return evtName;
            },

            /**
             * Remove attached event handler <b>handler</b> for the first supported event specified by <b>eventNames</b>
             * from the element <b>jqObject</b>.
             * Example: removeFirstSupportedEvent( myObject, "pointerdown mousedown touchend", myHandler );
             *
             * @param element
             * @param {String} eventNames
             * @param handler
             * @return {String} the event name or ""
             */
            removeFirstSupportedEvent: function (element, eventNames, handler) {
                var jqObject = jq(element),
                    evtName = getFirstSupportedEvent(element.nodeName, eventNames);

                if (!evtName) {
                    return "";
                }

                jqObject.off(evtName, handler);
                return evtName;
            },
            
            getPointerDownEvent: function( element ) {
                if( !isIOS ) {
                    return getFirstSupportedEvent( element.nodeName, "pointerdown mousedown touchstart" );
                }

                // iOS 9.3 unterstützt zwar click und mouseup, weshalb sich auf diese Events attached wird, aber sie werden
                //  aus unbekannten Gründen nicht gesendet.
                return "touchstart";
            },

            getPointerUpEvent: function( element ) {

                if( !isIOS ) {
                    return getFirstSupportedEvent( element.nodeName, "click pointerup mouseup touchend" );
                }

                // iOS 9.3 unterstützt zwar click und mouseup, weshalb sich auf diese Events attached wird, aber sie werden
                //  aus unbekannten Gründen nicht gesendet.
                return "touchend";
            }
        };
    })();

    /**
     * @constructor
     */
    return function (context, metadata) {
        var instance,
            shellElement,
            button,
            buttonInitialized = false,
            hasStageTriggerSupport = true,
            isInAuthoringMode = false,
            isInPreviewMode = false,
            pointerUpEventName,
            pointerDownEventName,
            pointerMoveEventName,
            pointerLeaveEventName,
            accessibilityTooltip,
            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 asRgbaValue(colorParameterName, defaultColor, transparencyParameterName) {

            var color = hexToRgb(metadata.parameters.get(colorParameterName, defaultColor)),
                alpha = asAlpha(metadata.parameters.asNumber(transparencyParameterName, 0));

            return "rgba(" + color.r + ", " + color.g + ", " + color.b + ", " + alpha + ")";
        }

        function hexToRgb(hex) {
            var parsingResult = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
            return parsingResult ? {
                r: parseInt(parsingResult[1], 16),
                g: parseInt(parsingResult[2], 16),
                b: parseInt(parsingResult[3], 16)
            } : {
                    r: 0,
                    g: 0,
                    b: 0
                };
        }

        function asAlpha(percentValue) {
            return (100 - percentValue) / 100;
        }

        // 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( !button.hasState( ButtonState.Pressed ) ) {
                button.changeState( ButtonState.Hover, button.getCurrentToggleState() );
            }
        }

        function onMouseLeave() {
            unlockNavigation();
            button.changeState( ButtonState.Default, button.getCurrentToggleState() );
        }

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

        function isOnTarget( e ) {
            var elem = e.target,
                origEvent = e.originalEvent,
                changedTouch;

            if ( !origEvent ) {
                return true;
            } else {
                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();

            button.changeState( ButtonState.Default, button.getCurrentToggleState() );

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

            toggleCurrentButtonToggleState();
            fireTrigger();
        }

        function onAccessibilityKeyPressed() {
            button.changeState(ButtonState.Default, button.getCurrentToggleState());
            toggleCurrentButtonToggleState();
            fireTrigger();
        }

        function cancelEvent(e){
            e.preventDefault();
            e.stopPropagation();
        }
        
        function toggleCurrentButtonToggleState(){
            if(button.hasToggleState(ButtonToggleState.On)){
                button.changeState( ButtonState.Default, ButtonToggleState.Off );
                context.stage.variable.set( button.variableID, ButtonToggleState.Off, button.variableNamespace );
            }else{
                button.changeState( ButtonState.Default, ButtonToggleState.On );
                context.stage.variable.set( button.variableID, ButtonToggleState.On, button.variableNamespace );
            }
        }

        function fireTrigger(){
            setTimeout(function(){
                if( button.getCurrentToggleState() ===  ButtonToggleState.On){
                    context.page.event.trigger(instance , "offToOn");
                } else {
                    context.page.event.trigger(instance, "onToOff");
                }}, 10);
        }

        function initPointerEventNames(element) {
            isInPreviewMode = !!context.stage.isInPreviewMode();
            if( !pointerUpEventName ) {
                pointerUpEventName = isInPreviewMode ? "mouseup" : EventUtil.getPointerUpEvent( element );
                pointerDownEventName = isInPreviewMode ? "mousedown" : EventUtil.getPointerDownEvent( element );
                pointerMoveEventName = isInPreviewMode ? "mousemove" : "pointermove mousemove";
                pointerLeaveEventName = isInPreviewMode ? "mouseend mouseout" : "pointerout mouseout";
            }
        }

        function bindEvents() {

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

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

            removeEvents();
            
            EventUtil.attachFirstSupportedEvent( button.getHotspotElement(), pointerDownEventName, onMouseDown );
            EventUtil.attachFirstSupportedEvent( button.getHotspotElement(), pointerMoveEventName, onMouseOver );
            EventUtil.attachFirstSupportedEvent( button.getHotspotElement(), pointerLeaveEventName, onMouseLeave );
            EventUtil.attachFirstSupportedEvent( button.getHotspotElement(), pointerUpEventName, onMouseUp );
        }

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

            initPointerEventNames(button.getHotspotElement());
            EventUtil.removeFirstSupportedEvent( button.getHotspotElement(), pointerDownEventName, onMouseDown );
            EventUtil.removeFirstSupportedEvent( button.getHotspotElement(), pointerMoveEventName, onMouseOver );
            EventUtil.removeFirstSupportedEvent( button.getHotspotElement(), pointerLeaveEventName, onMouseLeave );
            EventUtil.removeFirstSupportedEvent( button.getHotspotElement(), pointerUpEventName, onMouseUp );
        }

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

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

            button = createButton();
            button.variableID = metadata.parameters.asNumber("id", "1");
            button.variableNamespace = "textToggle" + button.variableID;

            shellElement.append( button.getRootElement() );

            if ( accessibilityKey !== "KeyNone" ) {
                accessibilityTooltip = new AccessibilityBuilder( accessibilityKey, accessibilityLocation, accessibilityPositionX, accessibilityPositionY ).build();
                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, button.getCurrentToggleState() );
            refreshSavedState();
        }

        function refreshSavedState(){
            var savedSessionState = context.stage.variable.get( button.variableID, button.variableNamespace );

            if(savedSessionState){
                if(savedSessionState == ButtonToggleState.On){
                    button.changeState( ButtonState.Default, ButtonToggleState.On );        
                }else{
                    button.changeState( ButtonState.Default, ButtonToggleState.Off )
                }
            }else{
                context.stage.variable.set( button.variableID, metadata.parameters.get("initial_state", ButtonToggleState.Off), button.variableNamespace );
                button.changeState( ButtonState.Default, metadata.parameters.get("initial_state", ButtonToggleState.Off) );
            };
        }

        function createButton(){
            var scParams = metadata.parameters,
                variableID = metadata.parameters.asNumber("id", "1"),
                button = new ButtonBuilder({
                    width: metadata.getWidth(),
                    height: metadata.getHeight(),
                    tooltip : scParams.get("tooltip", ""),
                    colorOff : {
                        background: asRgbaValue("background-color", "#999999", "background-color-transparency"),
                        backgroundHover: asRgbaValue("background-color-hover", "#adadad", "background-color-hover-transparency"),
                        backgroundPressed: asRgbaValue("background-color-pressed", "#fd7326", "background-color-pressed-transparency"),
                        text : scParams.get("text-color", "#000000"),
                        textHover : scParams.get("text-color-hover", "#000000"),
                        textPressed : scParams.get("text-color-pressed", "#000000")
                    },
                    colorOn : {
                        background: asRgbaValue("background-color-on", "#999999", "background-color-on-transparency"),
                        backgroundHover: asRgbaValue("background-color-hover-on", "#adadad", "background-color-hover-on-transparency"),
                        backgroundPressed: asRgbaValue("background-color-pressed-on", "#fd7326", "background-color-pressed-on-transparency"),
                        text : scParams.get("text-color-on", "#000000"),
                        textHover : scParams.get("text-color-hover-on", "#000000"),
                        textPressed : scParams.get("text-color-pressed-on", "#000000")
                    },
                    textOff : {
                        content : scParams.get("text", "Off")
                    },
                    textOn : {
                        content : scParams.get("textOn", "On")
                    },
                    textParams : {
                        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"))
                    },
                    state : {
                        initial : scParams.get("initial_state", ButtonToggleState.Off),
                        saved : context.stage.variable.get( variableID, "textGoggle" + variableID )
                    },
                    id : metadata.getId()
                }).build();

            return button;
        }

        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";
            }
        }

        // revealing public API
        return {
            onLoading: function () {
                instance = this;
                context.page.event.bindOnEnter(this);
                context.page.event.bindOnExit( this );
                if ( accessibilityKey !== "KeyNone" ) {
                    context.stage.accessibility.bindOnAccessibilityModeChanged( this );
                }

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

                shellElement = jq(context.getElement());

                initializeButton();
            },

            onEnterPage: function () {
                refreshSavedState();
                bindEvents();
                fireTrigger();
                unlockNavigation();
            },

            onExitPage: function() {
                removeEvents();
            },

            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() ) {
                    onAccessibilityKeyPressed();
                    context.stage.accessibility.turnAccessibilityModeOff();
                }
            }
        };
    };
});
