var hovertipMouseX;
var hovertipMouseY;
var dw_Tooltip = {
	offX: 12,
	offY: 12,
	maxLoops: 2, // for actuator check(linked image, etc.)
	init: function(areaId) {
		dw_Tooltip.tip = $('#' + areaId);
		var _this = dw_Tooltip;
		if(!_this.tip || !_this.tip.html()) {
			return;
		}
		_this.setDefaults();
		dw_Viewport.getAll();
	},
	setDefaults: function() { // called when props changed(resetFlag set)
		if(!this.defaultProps) {
			this.defaultProps = {
			};
		}
		var list = [['jumpAbove', 'boolean', true], ['jumpLeft', 'boolean', true],
			['Left', 'boolean', false], ['Above', 'boolean', false],
			['positionFn', 'function', this.positionRelEvent], 
			['wrapFn', 'function', function(str) {return str;}]];
		for(var i=0; list[i]; i++) {
			this[list[i][0]] = typeof(this.defaultProps[list[i][0]]) == list[i][1] ? this.defaultProps[list[i][0]] : list[i][2];
		}
	},
	positionRelEvent: function(e, tgt) {
		var _this = dw_Tooltip; 
		if(typeof e == 'object') { // event 
			if(e.type == 'mouseover' || e.type == 'mousemove') {
				_this.evX = _this.getMouseEventX(e);
				_this.evY = _this.getMouseEventY(e);
			} else { // focus
				var pos = dw_getPageOffsets(tgt);
				_this.evX = pos.x;
				_this.evY = pos.y;
			}
		}
		return _this.calcPosCoords(e, tgt);
	},
	calcPosCoords: function(e, tgt) {
		var x = this.evX; var y = this.evY; var xXd, yXd;
		var maxX = this.getMaxX(); var maxY = this.getMaxY(); // tip width/height too
		var tx = x + this.offX;
		var altx = x - (this.width + this.offX);
		var spL = x - dw_Viewport.scrollX > dw_Viewport.width / 2;
		if(typeof e == 'object' && e.type &&(e.type == 'focus' || e.type == 'focusin')) {
			var tgtWidth = tgt.width();
			if(tx + tgtWidth < maxX) {
				x = this.evX = x + tgtWidth;
				tx += tgtWidth; 
			} else if(tx + 20 < maxX) {
				x = this.evX = x + 20;
				tx += 20
			}
			y = this.evY = y + 10;
		}
		var ty = y + this.offY;
		var alty = y - (this.height + this.offY);
		var spA = y - dw_Viewport.scrollY > dw_Viewport.height / 2;
		if(!this.Left && tx < maxX) {
			x = tx;
		} else if((this.Left && altx >= dw_Viewport.scrollX) || (this.jumpLeft && tx >= maxX && altx >= dw_Viewport.scrollX)) {
			x = altx;
		} else if((this.Left && altx < dw_Viewport.scrollX) || (!this.Left && this.jumpLeft && altx < dw_Viewport.scrollX && spL)) {
			x = dw_Viewport.scrollX; // place at left edge
			xXd = 'Left'; // check later whether yXd too
		} else if(!this.Left && tx >= maxX &&(!this.jumpLeft || (this.jumpLeft && altx < dw_Viewport.scrollX && !spL))) {
			x = maxX; 
			xXd = 'Right';
		}
		if(!this.Above && ty < maxY) {
			y = ty;
		} else if((this.Above && alty >= dw_Viewport.scrollY) || (this.jumpAbove && ty >= maxY && alty >= dw_Viewport.scrollY)) {
			y = alty;
		} else if((this.Above && alty < dw_Viewport.scrollY) || (!this.Above && this.jumpAbove && alty < dw_Viewport.scrollY && spA) ) {
			y = dw_Viewport.scrollY; // place at top
			yXd = 'Above';
		} else if(!this.Above && ty >= maxY &&(!this.jumpAbove || (this.jumpAbove && alty < dw_Viewport.scrollY && !spA))) {
			y = maxY; yXd = 'Below';
		}
		if(xXd && yXd) { // over link(will flicker) calc least distance to uncover
			var dx = (xXd == 'Left')? dw_Viewport.scrollX - altx : tx - maxX;
			var dy = (yXd == 'Above')? dw_Viewport.scrollY - alty : ty - maxY;
			if(dx <= dy) {
				x = (xXd == 'Left')? altx : tx;
			} else {
				y = (yXd == 'Above')? alty : ty;
			}
		}
		//alert('(' + x + ', ' + y + ')');
		return {
			x: x, 
			y: y 
		}
	},
	getWidth: function() { 
		return this.width = this.tip.width(); 
	},
	getHeight: function() { 
		return this.height = this.tip.height(); 
	},
	getMaxX: function() { 
		return dw_Viewport.width + dw_Viewport.scrollX - this.getWidth() - 1; 
	},
	getMaxY: function() { 
		return dw_Viewport.height + dw_Viewport.scrollY - this.getHeight() - 1; 
	},
	getMouseEventX: function(e) { 
		return e.pageX ? e.pageX : e.clientX + dw_Viewport.scrollX; 
	},
	getMouseEventY: function(e) { 
		return e.pageY ? e.pageY : e.clientY + dw_Viewport.scrollY; 
	}
}
targetSelectByTargetAttribute = function(el, config) {
	target_list = el.getAttribute('target');
	if(target_list) {
		target_ids = target_list.split(' ');
		var selector = '#' + target_ids.join(',#');
		return $(selector);
	}
};
hovertipPrepare = function(o, config) {
	return o.
		hover(
			function() {
				hovertipHideCancel(this);
			}, 
			function() {
				hovertipHideScheduled(this);
			}
		).
		css('position', 'absolute').
		each(hovertipPosition);
};
hovertipPosition = function(i) {
	document.body.appendChild(this);
}
hovertipIsVisible = function(el) {
	return(jQuery.css(el, 'display') != 'none');
}
hovertipShowUnderMouse = function(el) {
	hovertipHideCancel(el);
	if(!hovertipIsVisible(el)) {
		dw_Event.add(document, 'keydown', function(e) {
		    e = e ? e: window.event;  
		    if(27 == e.keyCode) {
		    	hovertipHideScheduled(el, 0/*immediately*/);
		    }
		},  true);
		el.ht.showing = // keep reference to timer
		window.setTimeout(function() {
			el.ht.tip.css({
				'position': 'absolute',
				'top': hovertipMouseY + 'px',
				'left': hovertipMouseX + 'px'
			}).show();
		}, el.ht.config.showDelay);
	}
};
hovertipHideCancel = function(el) {
	if(el.ht.hiding) {
		window.clearTimeout(el.ht.hiding);
		el.ht.hiding = null;
	}
};
hovertipHideScheduled = function(el, delay) {
	if(el.ht.showing) {
		window.clearTimeout(el.ht.showing);
		el.ht.showing = null;
	}
	if(el.ht.hiding) {
		window.clearTimeout(el.ht.hiding);
		el.ht.hiding = null;
	}
	el.ht.hiding = window.setTimeout(function() {
		if(el.ht.hiding) {
			el.ht.tip.hide();
		}
	}, undefined == delay ? el.ht.config.hideDelay : delay);
};
hovertipTargetPrepare = function(o, el, config) {
	return o.addClass(config.attribute + '_target').hover(
		function() {
			hovertipShowUnderMouse(el);
		},
		function() {
			hovertipHideScheduled(el);
		}
	);
};
jQuery.fn.hovertipActivate = function(config, targetSelect, tipPrepare, targetPrepare, parentObjectId) {
	return this.css('display', 'block').hide().each(function() {
		if(parentObjectId == $(this).attr('parentObjectId')) {
			if(!this.ht) {
				this.ht = new Object();
			}
			this.ht.config = config;
			var targets = targetSelect(this, config), tipsThis = this;
			if(targets && targets.size()) {
				if(!this.ht.targets) {
					this.ht.targets = targetPrepare(targets, this, config);
				} else {
					this.ht.targets.add(targetPrepare(targets, this, config));
				}
				if(!this.ht.tip) {
					this.ht.tip = tipPrepare($(this), config);
				}
				targets.mousemove(
					function hovertipMouseUpdate(e) {
						dw_Tooltip.init('target_' + parentObjectId + '_' + tipsThis.ht.tip.attr('target'));
						var computeTipCoordinates = dw_Tooltip.positionRelEvent(e, dw_Event.getTarget(e));
						hovertipMouseX = computeTipCoordinates.x;
						hovertipMouseY = computeTipCoordinates.y;
					}
				);
			}
		}
	});
};
function hovertipInit(parentObjectId) {
var hovertipConfig = {'showDelay': 300, 'hideDelay': 700, 'attribute': 'hovertip'};
	$('div[parentObjectId=' + parentObjectId + ']').css('display', 'block').addClass('hovertip_wrap3').wrap('<div class="hovertip_wrap0"><div class="hovertip_wrap1"><div class="hovertip_wrap2"></div></div></div>').each(function() {
	var tooltip = this.parentNode.parentNode.parentNode;
		if(this.getAttribute('target')) {
			tooltip.setAttribute('target', this.getAttribute('target'));
		}
		if(this.getAttribute('id')) {
		var id = this.getAttribute('id');
			this.removeAttribute('id');
			tooltip.setAttribute('id', id);
			tooltip.setAttribute('parentObjectId', this.getAttribute('parentObjectId'));
		}
	});
	$('div.hovertip_wrap0').hovertipActivate(hovertipConfig, targetSelectByTargetAttribute, hovertipPrepare, hovertipTargetPrepare, parentObjectId);
}