define([
    "./toggleicon.builder",
    "jquery",
	"css!./accordion.css"
],
function(
    ToggleIconbuilder,
    jq
){

    "use strict";

    /**
     * @constructor
     */

    return function(options, context, metadata){
        var accordion,
            elements = new Array(),
            pointerUpEventName, pointerDownEventName,
            pointerMoveEventNames, pointerLeaveEventNames,
            buttonInitialized = false,
            buttonState = {
                Default : "btn_state_default",
                Hover : "btn_state_hover",
                Pressed : "btn_state_pressed"
            },
            currentState = buttonState.Default;

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

        function asRgbaValue( colorValue, transparencyValue ) {

            var color = hexToRgb( colorValue ),
                alpha = asAlpha( transparencyValue );

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

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

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

            accordion = jq(document.createElement("div"))
                    .attr({
                        "id" : "accordion" + options.instanceId
                    })
                    .addClass("accordion");

            for (var i = 0; i < options.elements.length ; i++) {
                var element = new Array();

                element = {
                    titleElement : createTitleElement(i),
                    textElement : createTextElement(i),
                    expand : false
                }

                accordion.append(element.titleElement.getElement());
                accordion.append(element.textElement);
                elements.push(element);
            }
        }

        function createTitleElement(number) {

            var backgroundColor = options.title.backgroundColor,
                backgroundTransparency = options.title.backgroundTransparency,
                color = options.title.textColor,
                numberingColor = options.numberingColor,
                text = options.elements[number].title,
                fontFamily = options.title.fontFamily,
                fontSize = options.title.fontSize,
                paddingLeft = options.title.paddingLeft,
                paddingRight = options.title.paddingRight,
                paddingTop = options.title.paddingTop,
                paddingBottom = options.title.paddingBottom,
                widthParam = options.width - paddingLeft - paddingRight,
                maxHeight,
                textOrientation = options.title.textOrientation,
                element = jq(document.createElement("div"))
                    .attr({
                        "id" : "titleElement" + number + options.instanceId
                    })
                    .css({
                        "background-color" : asRgbaValue( backgroundColor, backgroundTransparency),
                        "font-family" : fontFamily,
                        "font-size" : fontSize + "px",
                        "color" : color,
                        "padding-left" : paddingLeft + "px",
                        "padding-right" : paddingRight + "px",
                        "padding-top" : paddingTop + "px",
                        "padding-bottom" : paddingBottom + "px",
                        "text-align" : textOrientation
                    })
                    .addClass("accordionTitleElement")
                    .text(text),
                iconElement = new ToggleIconbuilder({
                    fileNameURL : options.icons.fileNameURL, 
                    width : options.icons.width,
                    height : options.icons.height / 2,
                    name : "accordionIcon"}, context, metadata).build(),
                numberingElement = jq(document.createElement("div"))
                    .attr({
                        "id" : "numberingElement" + number + options.instanceId
                    })
                    .css({
                        "font-family" : fontFamily,
                        "font-size" : fontSize + "px",
                        "color" : numberingColor,
                        "padding-left" : paddingLeft + "px",
                        "padding-right" : paddingRight + "px",
                        "padding-top" : paddingTop + "px",
                        "padding-bottom" : paddingBottom + "px",
                        "text-align" : textOrientation,
                        "font-weight" : "bold"
                    })
                    .addClass("accordionNumberingElement")
                    .text(number + 1);
                
                if(options.showNumbering){
                    var newPaddingLeft = parseInt(paddingLeft) + 15;

                        widthParam = widthParam - 15;

                        element.css({
                            "padding-left" : newPaddingLeft + "px"
                        });
                }

                if(options.showIcons){
                    var newPaddingRight = parseInt(paddingRight) + parseInt(options.icons.width);

                        widthParam = widthParam - options.icons.width;
                        element.css({
                            "padding-right" : newPaddingRight + "px"
                        });
                }

                element.css({
                    "width" : widthParam + "px"
                });

                maxHeight = getRenderedHeight(element) - paddingTop - paddingBottom;

                if(maxHeight < options.icons.height / 2){
                   maxHeight =  options.icons.height / 2;
                }

                element.css({
                    "height" : maxHeight + "px"
                });

                if(options.showNumbering){
                    element.append(numberingElement);
                }

                if(options.showIcons){
                    element.append(iconElement.getElement());
                }

            return{
                getElement : function(){
                    return element.get(0);
                },
                toggleIcon : function(){
                    if(!(options.showIcons)){
                        return;
                    }
                    iconElement.toggleIcon();
                },
                addElement : function(elem){
                    element.append(elem);
                },
                changeCss : function(cssParams){
                    element.css(cssParams.title);
                    numberingElement.css(cssParams.numbering);
                },
                removeEvents : function(){
                    element.unbind();
                },
                addEvent : function(listener, action){
                    element.on(listener, action);
                }
            };
        }

        function getRenderedHeight(elem){
            var renderedHeight,
                clonedElem = elem.clone();

            clonedElem.appendTo('body');
            renderedHeight = clonedElem.innerHeight();
            clonedElem.remove();

            return renderedHeight;
        }

        function createTextElement(number) {

            var backgroundColor = options.text.backgroundColor,
                backgroundTransparency = options.text.backgroundTransparency,
                color = options.text.textColor,
                text = options.elements[number].text,
                fontFamily = options.text.fontFamily,
                fontSize = options.text.fontSize,
                paddingLeft = options.text.paddingLeft,
                paddingRight = options.text.paddingRight,
                paddingTop = options.text.paddingTop,
                paddingBottom = options.text.paddingBottom,
                textOrientation = options.text.textOrientation,
                widthParam = options.width - paddingLeft - paddingRight,
                maxHeight,
                element = jq(document.createElement("div"))
                    .attr({
                        "id" : "textElement" + number + options.instanceId
                    })
                    .css({
                        "background-color" : asRgbaValue(backgroundColor, backgroundTransparency),
                        "font-family" : fontFamily,
                        "font-size" : fontSize + "px",
                        "color" : color,
                        "padding-left" : paddingLeft + "px",
                        "padding-right" : paddingRight + "px",
                        "padding-top" : paddingTop + "px",
                        "padding-bottom" : paddingBottom + "px",
                        "text-align" : textOrientation
                    })
                    .addClass("accordionTextElement")
                    .html(text);

            if(options.showNumbering){
                var newPaddingLeft = parseInt(paddingLeft) + 15;

                widthParam = widthParam - 15;

                element.css({
                    "padding-left" : newPaddingLeft + "px"
                });
            }

            element.css({
                "width" : widthParam + "px"
            });

            maxHeight = getRenderedHeight(element) - paddingTop - paddingBottom;

            element.css({
                "height" : maxHeight + "px",
            });

            return element;
        }

        function collapseAllTextElements(){
            elements.forEach(function(elem, index){
                if(elem.expand){
                    elem.titleElement.toggleIcon();
                    elem.textElement.slideToggle("expand");
                    elem.expand = false;
                }
            })
        }

        function collapseAllOtherTextElements( elemToSkip ) {
            elements.forEach( function ( elem, index ) {
                if ( elem.expand && elem !== elemToSkip ) {
                    elem.titleElement.toggleIcon();
                    elem.textElement.slideToggle( "expand" );
                    elem.expand = false;
                }
            } )
        }

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

        function getHotspotElementNodeName() {
            return elements[0].titleElement.getElement().nodeName
                ? elements[0].titleElement.getElement().nodeName
                : "document";
        }

        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 lockNavigation() {
            if (context.stage.isInAuthoringMode() || (typeof(context.stage.trigger) === "undefined")) {
                return;
            }
            context.stage.trigger.lock( metadata.getId() );
        }

        function unlockNavigation() {
            if (context.stage.isInAuthoringMode() || (typeof(context.stage.trigger) === "undefined")) {
                return;
            }
            context.stage.trigger.unlock( metadata.getId() );
        }

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

        function fireTrigger(index){
            var triggerName = "title" + (index + 1) + "opened";

            setTimeout(function(){
                context.page.event.trigger(options.instance, triggerName);
            }, 10);
        }

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

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

            removeEvents();
            elements.forEach(function(elem, index){
                var backgroundColor = options.title.backgroundColor,
                    mouseoverBackgroundColor = options.title.mouseoverBackgroundColor,
                    backgroundTransparency = options.title.backgroundTransparency,
                    color = options.title.textColor,
                    mouseoverTextColor = options.title.mouseoverTextColor,
                    numberingColor = options.numberingColor,
                    numberingMouseOverColor = options.numberingMouseOverColor;

                context.device.attachFirstSupportedEvent( elem.titleElement.getElement(), pointerMoveEventNames, function(){
                    if(currentState !== buttonState.Pressed){
                        elem.titleElement.changeCss({
                            title : {
                                "background-color" : asRgbaValue(mouseoverBackgroundColor, backgroundTransparency),
                                "color" : mouseoverTextColor
                            },
                            numbering : {
                                "color" : numberingMouseOverColor
                            }
                        })
                        currentState = buttonState.Hover;
                    }
                });
                
                context.device.attachFirstSupportedEvent( elem.titleElement.getElement(), pointerLeaveEventNames, function(){
                    unlockNavigation();
                    elem.titleElement.changeCss({
                        title : {
                            "background-color" : asRgbaValue(backgroundColor, backgroundTransparency),
                            "color" : color
                        },
                        numbering : {
                            "color" : numberingColor
                        }   
                    })
                    currentState = buttonState.Default;
                });

                context.device.attachFirstSupportedEvent( elem.titleElement.getElement(), pointerDownEventName, function(){
                    lockNavigation();
                    elem.titleElement.changeCss({
                        title : {
                            "background-color" : asRgbaValue(mouseoverBackgroundColor, backgroundTransparency),
                            "color" : mouseoverTextColor
                        },
                        numbering : {
                            "color" : numberingMouseOverColor
                        }
                    })
                    currentState = buttonState.Pressed;
                });

                context.device.attachFirstSupportedEvent( elem.titleElement.getElement(), pointerUpEventName, function(e){
                    cancelEvent(e);
                    unlockNavigation();

                    elem.titleElement.changeCss({
                        title : {
                            "background-color" : asRgbaValue(backgroundColor, backgroundTransparency),
                            "color" : color
                        },
                        numbering : {
                            "color" : numberingColor
                        }   
                    })
                    currentState = buttonState.Default;

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

                    if(options.expandOnlyOne){
                        collapseAllOtherTextElements(elem);
                    }

                    elem.textElement.slideToggle("expand");
                    elem.titleElement.toggleIcon();
                    if(elements[index].expand){
                        elements[index].expand = false;
                    }else{
                        elements[index].expand = true;
                    };

                    fireTrigger(index);
                });
            })
        }

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

            initPointerEventNames();

            elements.forEach(function(elem, index){
                elem.titleElement.removeEvents();
            })
        }

        return {
            build : function(){
                createAccordion();
                return{
                    getElement : function(){
                        return accordion.get(0);
                    },
                    collapseAll : function(){
                        collapseAllTextElements();
                    },
                    bindEvents : function(){
                        bindEvents();
                    },
                    removeEvents : function(){
                        removeEvents();
                    }
                }
            }
        }
    }
});