/*
 Copyright (c) 2008, Bubbling Library Team. All rights reserved.
 Portions Copyright (c) 2008, Yahoo!, Inc. All rights reserved.
 Code licensed under the BSD License:
 http://www.bubbling-library.com/eng/licence
 version: 2.0
 */
(function() {
	var $B = YAHOO.Bubbling, $L = YAHOO.lang, $E = YAHOO.util.Event, $C = YAHOO.util.Connect;
	var $D = YAHOO.util.Dom, $ = YAHOO.util.Dom.get;
	
	/**
	 * @class Tips
	 * Tooltips manager object...
	 * @constructor
	 */
	YAHOO.widget.Tooltip = function() {
		var DEBUG_MODE = false; // enable/disable defining onmouseout event to elements (usable for testing purposes)
		
		var obj = {};
		var _areas = {};
		var _handle = 'yui-cms-snap';
		var _className = 'yui-cms-tt';
		var _loadingClass = 'loading';
		var _status = false;
		var _ready = false;
		var _timer = null;
		var _delayTimer = null;
		var _pos = [0, 0];
		var _posPage = [0, 0];
		var _defConf = {}; // store local conf for currently displayed tooltip
		
		var _staticConf = {
			zIndex: 1000,
			opacity: 0.98,
			preventoverlap: false,
			constraintoviewport: true,
			showdelay: 250,
			effect: {
				effect: YAHOO.widget.ContainerEffect.FADE,
				duration: 0.1
			},
			autodismissdelay: 30000,
			text: '',
			underlay: "shadow",
			width: null,
			height: 'auto',
			close: false
		};
		
		var _staticConfAjaxOverlay = {
			text: 'Loading...',
			close: false
		};
		
		
		// private stuff
		// pasive behavior...
		var actionControl = function(layer, args) {
			var el = obj.finder(args[1].target) || args[1].anchor;
			if ($L.isObject(el)) {
				// discard forbbiden areas
				for (var i = 0; i < obj.forbbiden.length; i++) {
					if ($L.isObject($B.getOwnerByClassName(el, obj.forbbiden[i]))) {
						return;
					}
				}
				// the tooltip will be showed... and the event continue...
				obj.check(args[0], el);
			}
		};
		var _save = function() {
			obj.backup = {
				title: obj.element.getAttribute('title')
			};
			obj.element.setAttribute('title', '');
			
			// decode json and store in element for future usage
			if (!$L.isObject(obj.element.previewData)) {
				obj.element.previewData = $L.JSON.parse(obj.element.getAttribute('rel'));
			}
			
			obj.previewData = obj.element.previewData;
		};
		
		// public vars
		obj.handleOverlay = null;
		obj.element = null;
		obj.body = '';
		obj.header = null;
		obj.footer = null;
		obj.onCompile = null;
		obj.onRender = null;
		obj.destructible = true;
		obj.backup = {};
		obj.forbbiden = ['yuimenu', 'yuimenubar', 'yui-nav', 'notips'];
		// public methods
		obj.config = function(userConfig) {
			c = userConfig || {};
			_defConf.constraintoviewport = ($L.isBoolean(c.constraintoviewport) ? c.constraintoviewport : _staticConf.constraintoviewport);
			_defConf.zIndex = ($L.isNumber(c.zIndex) ? c.zIndex : _staticConf.zIndex);
			_defConf.underlay = ($L.isString(c.underlay) ? c.underlay : _staticConf.underlay);
			_defConf.preventoverlap = ($L.isBoolean(c.preventoverlap) ? c.preventoverlap : _staticConf.preventoverlap);
			_defConf.width = ($L.isNumber(c.width) || $L.isString(c.width) ? (isNaN(c.width) ? c.width : c.width + 'px') : _staticConf.width);
			_defConf.height = ($L.isNumber(c.height) || $L.isString(c.height) ? (isNaN(c.height) ? c.height : c.heigh + 'px') : _staticConf.height);
			_defConf.close = ($L.isBoolean(c.close) ? c.close : _staticConf.close);
			_defConf.effect = ($L.isObject(c.effect) ? c.effect : _staticConf.effect);
			_defConf.opacity = ($L.isNumber(c.opacity) ? c.opacity : _staticConf.opacity);
			_defConf.showdelay = ($L.isNumber(c.showdelay) ? c.showdelay : _staticConf.showdelay);
			_defConf.className = c.className || '';
		};
		obj.configForCurrentElement = function() {
			this.config(this.element.previewData.xhrUrl ? _staticConfAjaxOverlay : _staticConf);
			
			if (this.element.previewData && $L.isObject(this.element.previewData.config)) {
				this.config(this.element.previewData.config);
			}
		};
		obj.init = function() {
			if (!_ready) {
				_ready = true;
				$B.on('rollover', actionControl);
			}
		};
		obj.check = function(e, el) {
			this.init();
			// Remove any existing mouseover/mouseout listeners from the old element and restoring the values
			if (this.element) {
				$E.removeListener(this.element, "mouseout", obj.hide);
			}
			this.element = el;
			_save(); // saving values...
			_pos = $E.getXY(e); // computing the mouse position...
			// set config
			this.configForCurrentElement();
			
			
			// Add mouseover/mouseout listeners to context elements
			if (!DEBUG_MODE) $E.addListener(obj.element, "mouseout", obj.dismiss, obj, true);
			
			// reseting the current values
			this.body = '';
			this.header = null;
			this.footer = null;
			if (!$L.isFunction(this.onCompile) || !(this.onCompile.apply(obj, [this.element]))) {
				this.compileBody(el);
			}
			// verifing if we really have text to display in the tooltip
			if (($L.isString(this.body) && (this.body !== '')) || $L.isString(this.header) || $L.isString(this.footer)) {
				// Eliminando todos los ATL de las imagenes que estan dentro del Anchor - for IE
				try {
					var childs = el.getElementsByTagName("img");
					if (childs && (childs.length > 0)) {
						for (var i = 0; i < childs.length; i++) {
							childs[i].alt = '';
						}
					}
				} 
				catch (e1) {
				}
				
				// applying delay before show
				obj.delay();
			}
		};
		obj.render = function() {
			if ($L.isObject(this.handleOverlay) && (this.destructible)) {
				this.handleOverlay.destroy();
			}
			this.destructible = true;
			if (!$L.isFunction(YAHOO.widget.Panel)) {
				return false;
			}
			
			// Build overlay based on markup
			this.handleOverlay = new YAHOO.widget.Panel(_handle, {
				visible: false,
				draggable: false,
				constraintoviewport: _defConf.constraintoviewport,
				zIndex: _defConf.zIndex,
				underlay: _defConf.underlay,
				preventoverlap: _defConf.preventoverlap,
				width: _defConf.width,
				close: _defConf.close,
				context: this.element,
				xy: [_pos[0] + 10, _pos[1] + 10]
			});
			// add standard/default class to recognize tooltip
			$D.addClass(this.handleOverlay.element, _className);
			// add user defined class to personalize tooltip for given element
			$D.addClass(this.handleOverlay.element, _defConf.className);
			
			if (this.body) {
				this.handleOverlay.setBody(this.body);
			}
			if (this.footer) {
				this.handleOverlay.setFooter(this.footer);
			}
			if ($D.inDocument(_handle)) { // is the panel is already in the DOM
				this.handleOverlay.render();
			}
			else {
				this.handleOverlay.render(document.body);
			}
			if (_defConf.effect) {
				this.handleOverlay.cfg.setProperty('effect', _defConf.effect);
			}
			
			
			this.handleOverlay.showEvent.subscribe(function() {
				obj.destructible = true;
				// applying the correct opacity...
				if (!$E.isIE || $B.force2alfa) {
					$D.setStyle(obj.handleOverlay.element, 'opacity', _defConf.opacity);
				}
			}, obj, true);
			this.handleOverlay.hideEvent.subscribe(function() {
				obj.destructible = true;
			}, obj, true);
			if ($L.isFunction(this.onRender)) {
				this.onRender.apply(obj, [this.element, this.handleOverlay]);
			}
			
			// flip horizontal if the Panel exceeds viewport's constrains
			var _localXY = this.handleOverlay.getConstrainedXY(_pos[0], _pos[1]);
			if (_pos[0] > _localXY[0] && _pos[1] > _localXY[1]) {
				var _region = $D.getRegion(this.handleOverlay.element);
				this.handleOverlay.moveTo(_pos[0] - (_region.right - _region.left) - 10, _pos[1]);
			}
			
			
			// setup AJAX if needed
			if (this.previewData.xhrUrl) {
				if (!$L.isFunction(this.onCompileAjax) || !(this.onCompileAjax.apply(obj, [this.element, this.previewData.xhrUrl]))) {
					this.compileAjax(this.element, this.previewData.xhrUrl);
				}
			}
			
			obj.show();
		};
		obj.dismiss = function() {
			$E.removeListener(obj.element, "mouseout", obj.dismiss);
			window.clearTimeout(_timer);
			window.clearTimeout(_delayTimer);
			if (!_defConf.close) { // if don't have close button
				obj.hide();
			}
		};
		obj.delay = function() {
			// applying the delay before show the tooltip...
			window.clearTimeout(_timer);
			window.clearTimeout(_delayTimer);
			if (!this.destructible) {
				if ($L.isObject(this.handleOverlay)) {
					this.handleOverlay.hideEvent.subscribe(obj.delay, obj, true);
					this.handleOverlay.showEvent.subscribe(obj.delay, obj, true);
				}
			}
			else {
				_delayTimer = window.setTimeout(function() {
					obj.render();
				}, _defConf.showdelay);
			}
		};
		obj.show = function() {
			if (this.handleOverlay && this.element && this.previewData) {
				this.destructible = false;
				this.handleOverlay.show();
				// setting the autodismis timer...
				if ($L.isNumber(_defConf.autodismissdelay) && (_defConf.autodismissdelay > 0)) {
					window.clearTimeout(_timer);
					_timer = window.setTimeout(function() {
						obj.dismiss();
					}, Math.abs(_defConf.autodismissdelay));
				}
			}
		};
		
		obj.hide = function() {
			if ((this.handleOverlay) && (this.element)) {
				this.handleOverlay.hide();
			}
		};
		
		obj.compileBody = function(el) {
			this.body = this.previewData.body || '&nbsp;';
			this.footer = this.previewData.footer || '';
		};
		
		obj.compileAjax = function(el, uri) {
			if ($L.isObject(this.handle)) $C.abort(this.handle);
			
			var callback = {
				success: function(o) {
					this.body = o.responseText;
					obj.handleOverlay.setBody(this.body);
				},
				failure: function(o) {
					throw new Error('YAHOO.widget.Tooltip: ajax failure...');
				},
				timeout: 5000
			};
			if (this.handle = $C.asyncRequest('GET', uri, callback)) {
				this.body = '<div class="loading-indicator"></div>';
				obj.handleOverlay.setBody(this.body);
				return true;
			}
		};
		
		obj.finder = function(el) {
			return !$B.getOwnerByClassName(el, 'yui-preview');
		};
		
		$E.onDOMReady(obj.init, obj, true);
		return obj;
	}();
})();
YAHOO.register("Tooltip", YAHOO.widget.Tooltip, {
	version: "0.2",
	build: "1"
});
