define(["jquery"], function (jq) {

	"use strict";

	var	CounterSenderListenerFactory = function( options, context, metadata ){

		var type = metadata.parameters.get("type", "sender"),
			id = metadata.parameters.get("id", 1),
			globalValueCounter = new GlobalCountProvider( context, {
				"scInstance" : options.scInstance,
				"variableId" : "senderListenerCounter" + id,
				"groupId" : "tts.senderListener",
				"behaviour" : metadata.parameters.get("behaviour", "once"),
				"onceClickedId": "senderListenerCounterClickedOnce" + metadata.getId(),
				"maximum" : metadata.parameters.asNumber("maximum", 1)
			});

		function getFont(index) {
			var fonts = [
					'Arial, Helvetica, sans-serif',
					'"Times New Roman", Times, serif',
					'Verdana, Geneva, sans-serif',
					'"Courier New", Courier, monospace',
					'Roboto, "Helvetica Neue", Helvetica, Arial, sans-serif',
					'"Droid Serif", "Times New Roman", Times, serif'
				],
				fontIndex = (index > 0 && index < fonts.length) ? index - 1 : 0;

			return fonts[fontIndex];
		}

		return {
			create: function () {

				if( context.stage.isInAuthoringMode() ){
					return new AuthoringView( globalValueCounter, context, {
						"bgImage" : "url(\"" + context.getPath() + "invis.png\")",
						"caption" : type === "sender" ? "sender" : "listener"
					});
				}

				if (type === "listener") {
					return new ListenerView( globalValueCounter, context, {
						"textAlign" : metadata.parameters.get("text_orientation", "center"),
						"lineHeight" : metadata.getHeight() + "px",
						"color": metadata.parameters.asCssColor("color", "#000000"),
						"font": {
							"size": metadata.parameters.asNumber("font_size", 14) + "px",
							"family": getFont( metadata.parameters.asNumber("font_family", 0) )
						}
					});
				}

				return new SenderButton( globalValueCounter, context, {
					"cursor" : metadata.parameters.get("cursor", "pointer"),
					"targetListenerElementClass" : options.listenerClassId
				});
			}
		};
	},

	GlobalCountProvider = function( context, options ){

		function countUp(){

			var counter = getCounter();

			counter++;
			context.stage.variable.set( options.variableId, counter, options.groupId);
		}

		function getCounter(){
			var counter = context.stage.variable.get( options.variableId, options.groupId);
			if( counter > 0 ){
				return parseInt(counter);
			}
			return 0;
		}

		return {
			reset : function(){
				context.stage.variable.set(options.onceClickedId, false, options.groupId);
				context.stage.variable.set( options.variableId, 0, options.groupId );
			},
			applyValue : function(){

				var isClickedOnce = context.stage.variable.get(options.onceClickedId, options.groupId);
				if( options.behaviour === "once" && isClickedOnce ) {
					return;
				}

				context.stage.variable.set( options.onceClickedId, true, options.groupId);
				countUp();
			},
			checkValue : function(){

				var currentCounter = getCounter(),
					buttonText = (currentCounter >= options.maximum) ? options.maximum : currentCounter;

				if( currentCounter >= options.maximum ) {
					setTimeout(function () {
						context.page.event.trigger( options.scInstance, "triggered");
					}, 10);
				}

				return buttonText;
			}
		};
	},

	SenderButton = function( globalValueMediator, context, options ){

		var	button = jq(document.createElement("span"))
			.css({
				"width" : "100%",
				"height" : "100%",
				"display" : "block",
				"background": "transparent url('./invis.png') repeat center top"
			}),
            EVENT_THRESHOLD = 100,	// ignore events for x ms.
			lastEventTime,
			pointerUpEventName, pointerDownEventName,
			pointerMoveEventName, pointerLeaveEventName;

		jq(context.getPositioningElement())
			.css("cursor", options.cursor);

		initPointerEventNames();

        function isValidEvent( ) {
            return typeof lastEventTime === "undefined" || new Date().getTime() - lastEventTime > EVENT_THRESHOLD;
        }

		function onUserAction( e ) {
			if( !isValidEvent() ) {
				return;
			}

            lastEventTime = new Date().getTime();

			globalValueMediator.applyValue(e);
			notifyListenerOnCurrentPage();
		}

		function notifyListenerOnCurrentPage() {
			jq("." + options.targetListenerElementClass).trigger("senderListenerSamePageRefresh");
		}

		function initPointerEventNames() {
			if (!pointerUpEventName) {
				var nodeName = getHotspotElementNodeName();

				pointerUpEventName = context.device.getUpEvents(nodeName);
				pointerDownEventName = context.device.getDownEvents(nodeName);
				pointerMoveEventName = context.device.getMoveEvents(nodeName);
				pointerLeaveEventName = context.device.getReleaseEvents(nodeName);
			}
		}

		function getHotspotElementNodeName() {
			return "document";
		}

		return {
			getElement : function(){
				return button;
			},
			bindEvents: function () {
				var buttonElement = context.getPositioningElement();
				context.device.attachFirstSupportedEvent(buttonElement, pointerUpEventName, onUserAction);
			},
			removeEvents: function () {
				var buttonElement = context.getPositioningElement();
				context.device.removeFirstSupportedEvent(buttonElement, pointerUpEventName, onUserAction);
			},
			count : function(){},
			refresh : function(){
				notifyListenerOnCurrentPage();
			}
		};
	},

	ListenerView = function( globalValueMediator, context, options ){

		var shellElement = jq(context.getElement()),
			view = jq(document.createElement("span"))
				.css({
					"width" : "100%",
					"height" : "100%",
					"display" : "block",
					"text-align": options.textAlign,
					"line-height" : options.lineHeight,
					"color": options.color,
					"font-size": options.font.size,
					"font-family": options.font.family
				});

		function refresh(){
			view.text( globalValueMediator.checkValue() );
		}

		return {
			getElement : function(){
				return view;
			},
			bindEvents : function(){
				// if sender and listener are on same page, we have to make sure listener
				// will refresh after sender action occured
				shellElement.on("senderListenerSamePageRefresh", refresh);
			},
			removeEvents : function(){
				shellElement.off("senderListenerSamePageRefresh", refresh);
			},
			count : function(){},
			refresh : refresh
		};
	},

	AuthoringView = function( globalValueMediator, context, options ){

		var view = jq(document.createElement("div"))
			.css({
				"width": "100%",
				"height": "100%",
				"display": "block",
				"opacity": "0.15",
				"background-image": options.bgImage,
				"overflow" : "hidden"
			}),
			caption = jq(document.createElement("span"))
				.css({
					"position" : "absolute",
					"display" : "block",
					"top" : "100%",
					"left" : "5px",
					"color" : "#000000",
					"font-size" : "16px",
					"line-height" : "100%"
				})
				.text( options.caption );

		view.append( caption );
		globalValueMediator.reset();

		return {
			getElement : function(){
				return view;
			},
			bindEvents : function(){
			},
			removeEvents : function(){
			},
			count : function(){
			},
			refresh : function(){
			}
		};
	};

	return function (context, metadata) {

        var scElementId_prefix = "senderListenerCounter_",
            scElementId_postfix = "_" + metadata.parameters.get("id", 1) + "_" + metadata.page.getId(),
	        eventsAdded = false,
            component;

        function createHTML( scInstance ) {

	        var objElement = jq( context.getElement() )
				.addClass( scElementId_prefix + metadata.parameters.get("type", "sender") + scElementId_postfix )
				.css({
					"width" : metadata.getWidth(),
					"height" : metadata.getHeight()
				});

	        component = new CounterSenderListenerFactory( {
					"listenerClassId" : scElementId_prefix + "listener" + scElementId_postfix,
                	"scInstance" : scInstance
            	}, context, metadata ).create();
	        objElement.append( component.getElement() );
        }

        function bindEvents(){
            eventsAdded = true;
	        component.bindEvents();
		}

        function removeEvents(){
            eventsAdded = false;
	        component.removeEvents();
		}

        return {
            onLoading: function () {
				context.page.event.bindOnEnter(this);
                context.page.event.bindOnExit(this);
                createHTML( this );
            },

			onEnterPage: function () {
                if( !eventsAdded ) {
                    bindEvents();
                }

				component.refresh();
			},

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

			onAllComponentsReady: function () {
				component.refresh();
			}
        };
    };
});
