/*
	Copyright (c) 2006-2010, ePages GmbH
	All Rights Reserved.

	epages.widget.tooltip $Revision: 1.29 $
*/
dojo.provide("epages.widget.Tooltip");
dojo.require("epages.widget");
dojo.require("epages.string");
dojo.declare("epages.widget.Tooltip", [dijit._Widget, dijit._Templated], {

		/**
		 * public properties
		 */
		disabledBodyClickHide : false,
		tooltipLayerFrame     : undefined,
		tooltipAreaId         : '',
		tooltipArea           : undefined,
		tooltipNode           : undefined,
		interactive           : '',	// String - Is the user able to use the content of the tooltip? i.e. if there's links in the tooltip text
		tooltipShowDelay      : 0,
		tooltipHideDelay      : 0,
		currentYPosition      : 0,
		currentXPosition      : 0,
		hideDelay             : null,
		fadeDelay             : null,
		showDelay             : null,
		bgcolor               : '',
		forceOrientation      : '',	// String - B - bottom, T - top , L - left, R - right (combinations are possible e.g BR)
		target                : "default",
		findAreaMethod        : "",

		/**
		 * private properties
		 */
		_findAreaMethodMapping: {
			'default'           : 'parentNode',
			'previous'          : 'previousSibling',
			'next'              : 'nextSibling'
		},													// Object - which node should be used to connect to the tooltip activation events (mouseover-area)
		_doc                  :	null,				// DomNode - owner document, i.e. to calculate the widget position
		_bodyConnect          : undefined,	// to store event connect to document's body, i.e. for hiding the tooltip when clicked somewhere else on the page
		_windowConnect        : undefined,	// to store event connect to the window for capturing keypress events

		/**
		 * dojo widget properties
		 */
		templateString        : '<div class="Tooltip"><div dojoAttachPoint="containerNode"></div></div>',


		/**
		 * dojo lifecycle methods
		 */
		postCreate: function() {
			// summary: widget lifecycle postCreate handler
			// description:
			//		Initializes widget parameters and find dom element for displaying the tooltip widget
			//		(see _findAreaMethodMapping values). Then create dom elements for the tooltip bubble
			//		and connect the keyboard/mouse event handlers.
			this.inherited("postCreate", arguments);
			this.tooltipNode = this.domNode;
			// catch tooltip area node
			var tooltipArea = undefined;
			if(this.tooltipArea) {
				tooltipArea = this.tooltipArea;
			}
			else if(this.tooltipAreaId!="") {
				tooltipArea= $(this.tooltipAreaId);
			}
			else {
				var findAreaMethod = this._findAreaMethodMapping[this.findAreaMethod || this.target];
				tooltipArea = this.domNode[findAreaMethod];
				if(tooltipArea.nodeType!= 1) {
					if(findAreaMethod == 'previousSibling') {
						tooltipArea=tooltipArea.previousSibling; // skip spaces
					}
					if(findAreaMethod == 'nextSibling') {
						tooltipArea=tooltipArea.nextSibling;     // skip spaces
					}
				}
			}

			if(this.bgcolor !=''){
				this.domNode.style.backgroundColor = this.bgcolor;
			}

			if(!tooltipArea || tooltipArea.nodeType!=1 ){
				console.warn('TooltipArea not found by using find method "'+this.findAreaMethod+'" in '+this.declaredClass);
			} else {
				this.tooltipArea = tooltipArea;
				this._doc = this.tooltipArea.ownerDocument;
				this.tooltipIsInteractive = epages.string.toBoolean(this.interactive);
				this.tooltipShowDelay = 600;
				this.tooltipHideDelay = this.tooltipIsInteractive ? 1400 : 400;
				this.tooltipLayerFrame = this._doc.createElement("div");
				this.tooltipShadow = this._doc.createElement("div");
				dojo.style(this.tooltipNode, "opacity", 0);

				this._bodyConnect = dojo.connect(dojo.body(),"onmouseup",this, "onBodyClick");
				this._windowConnect = dojo.connect(window,"onkeypress", this,"onKeypress");
				this.connect(this.tooltipArea, "onmousemove", "onElementMove");
				this.connect(this.tooltipArea, "onmouseover", "onElementOver");
				this.connect(this.tooltipArea, "onmouseout", "onElementOut");
				this.connect(this.tooltipArea, "onmousedown", "onElementClick");
				if(this.tooltipIsInteractive) {
					this.connect(this.tooltipNode, "onmouseover", "onTooltipOver");
					this.connect(this.tooltipNode, "onmouseout", "onTooltipOut");
				}
			}
		},

		destroy: function(){
			// summary: widget lifecycle destroy handler
			// description:
			//		Disconnect event handlers to body and window of the widget-containing document.
			this.inherited("destroy", arguments);
			dojo.disconnect(this._bodyConnect);
			dojo.disconnect(this._windowConnect);
		},


		/**
		 * public methods
		 */
		setContent: function(/* string */ html) {
			this.containerNode.innerHTML=html;
			this.setPosition();
		},

		isActive: function() {
			// summary: Is the tooltip dom node visible?
			// returns:  false if zero opacity, otherwise true
			return dojo.style(this.tooltipNode, "opacity") == 0? false : true;
		},

		setPosition: function() {
			// summary: Move the tooltip
			// description:
			//		Depending on the orientation mode set by the forceOrientation variable move the tooltip
			//		domNode to the position determined by currentYPosition and currentXPosition. This depends
			//		on the document parenting the tooltip node as well as possible window scroll bars.
			var forceRight  = (this.forceOrientation.match('R')) ? true : false;
			var forceLeft   = (this.forceOrientation.match('L')) ? true : false;
			var forceBottom = (this.forceOrientation.match('B')) ? true : false;
			var forceTop    = (this.forceOrientation.match('T')) ? true : false;

			// horizontal position
			var docWidth = epages.Browser.engine == "WebKit" ? this._doc.body.clientWidth : this._doc.documentElement.clientWidth;
			var rightSideX = this.tooltipNode.offsetWidth + this.currentXPosition + 16 + 3 - (this._doc.documentElement.scrollLeft || this._doc.body.scrollLeft);	// 16px = dist. from mouse ; 3px = shadow iframe
			if((rightSideX > docWidth && ! forceRight) || forceLeft) {
				var x = this.currentXPosition - this.tooltipNode.offsetWidth;
				if(forceLeft){
					x-=16;
				}
				if(x < 0){
					x=0;
				}
				this.tooltipNode.style.left = x + "px";			// layer > left align
			} else {
				var x = this.currentXPosition;
				if(forceRight){
					x+=16;
				}
				this.tooltipNode.style.left = x + "px";			// layer > right align
			}

			// vertical position
			var docHeight = epages.Browser.engine == "WebKit" ? this._doc.body.clientHeight : this._doc.documentElement.clientHeight;
			var bottomSideX = this.tooltipNode.offsetHeight + this.currentYPosition + 16 + 3 - (this._doc.documentElement.scrollTop || this._doc.body.scrollTop);
			if((bottomSideX > docHeight && ! forceBottom) || forceTop) { // 16px = dist. from mouse ; 3px = shadow iframe
				var y = this.currentYPosition - this.tooltipNode.offsetHeight - 16;
				if(y < 0){
					y=0;
				}
				this.tooltipNode.style.top =  y + "px";														// layer > top align
			}else{
				this.tooltipNode.style.top = this.currentYPosition + 16 + "px";		// layer > bottom align
			}
			this.tooltipLayerFrame.style.width = this.tooltipNode.offsetWidth + 2 + "px";
			this.tooltipLayerFrame.style.height = this.tooltipNode.offsetHeight + 2 + "px";
		},

		show: function(/* int */ x, /* int */ y) {
			// summary: Set position & display the Tooltip
			// description:
			//		Update the tooltip position and triggers the display of the tooltip.
			this.currentXPosition = x;
			this.currentYPosition = y;
			this.showTooltip();
		},

		showTooltip: function() {
			// summary: Display the Tooltip
			// description:
			//		Hide the tooltip dom node before changing it. Then attach the layout classes and move the
			//		tooltip frame to front. Finally attach the tooltip node to the dom tree and display it.
			dojo.addClass(this.tooltipNode, "HideElement");
			if(!this.rendered){
				dojo.addClass(this.tooltipNode, "Tooltip");
				dojo.addClass(this.tooltipShadow, "TooltipShadow");
				dojo.addClass(this.tooltipLayerFrame, "LayerIframe");
				if(!this.tooltipIsInteractive) {
					this.tooltipLayerFrame.style.zIndex = "1";
					this.tooltipNode.style.MozUserSelect = 'none';
				}
				this.tooltipNode.appendChild(this.tooltipLayerFrame); // overlay
				this.tooltipNode.appendChild(this.tooltipShadow);
				this._doc.getElementsByTagName("body")[0].appendChild(this.tooltipNode);
				this.rendered = true;
			}

			var _this = this;

			if( this.fadeAction ) {
				this.fadeAction.stop();
			}

			this.fadeAction = dojo.fadeIn({
				node: this.tooltipNode,
				duration:200,
				beforeBegin: function() {
					_this.tooltipNode.style.display = "block";
					_this.setPosition();
					dojo.removeClass(_this.tooltipNode, "HideElement");
				}
			});
			this.fadeAction.play();
		},

		hide: function() {
			// summary: Hide the Tooltip
			// description:
			//		After a fade, hide the tooltip.
			var _this = this;
			if( this.fadeAction ) {
				this.fadeAction.stop();
			}

			this.fadeAction = dojo.fadeOut({
				node:this.tooltipNode,
				duration: 200,
				onEnd: function() {
					_this.tooltipNode.style.display = "none";
				}
			});
			this.fadeAction.play();
		},


		/**
		 * Event handlers
		 */
		onElementMove: function(mouseEvent) {
			if(!mouseEvent){
				var mouseEvent = window.event;
			}
			this.currentYPosition = mouseEvent.clientY + (this._doc.documentElement.scrollTop || this._doc.body.scrollTop);
			this.currentXPosition = mouseEvent.clientX + (this._doc.documentElement.scrollLeft || this._doc.body.scrollLeft);
		},
		onElementOver: function() {
			this.disabledBodyClickHide = true;
			this._resetTimeouts();
			if(!this.isActive()) {
				this.showDelay = this._delayExec(this.showTooltip, this.tooltipShowDelay);
			}
		},
		onElementOut: function() {
			this._resetTimeouts();
			this.fadeDelay = this._delayExec(this.hide, this.tooltipHideDelay);
			this.disabledBodyClickHide = false;
		},
		onElementClick: function() {
			this.disabledBodyClickHide = true;
			if(!this.isActive()) {
				this._resetTimeouts();
				this.showTooltip();
			}
		},
		onTooltipOver: function() {
			this.disabledBodyClickHide = true;
			this._resetTimeouts();
		},
		onTooltipOut: function() {
			this.disabledBodyClickHide = false;
			this.onElementOut();
		},
		onBodyClick: function() {
			if(!this.disabledBodyClickHide && this.isActive()) {
				this._resetTimeouts();
				this.hide();
			}
		},
		onKeypress: function(evt) {
			if(evt.keyCode == dojo.keys.ESCAPE) {
				this._resetTimeouts();
				this.hide();
			}
		},


		/**
		 * private methods
		 */
		_delayExec: function(task, delay) {
			return setTimeout(dojo.hitch(this, task), delay);
		},
		_resetTimeouts: function() {
			clearTimeout(this.hideDelay);
			clearTimeout(this.fadeDelay);
			clearTimeout(this.showDelay);
		}

	}
);