/**
 * Absztrakt tooltip megjelenítő osztály.
 */
function TipAbstractView(helper) {
	this.helper = helper;
}

TipAbstractView.prototype.getParamsValidator = function() {
	return false;
}

TipAbstractView.prototype.show = function(x, y, immediate) {
}

TipAbstractView.prototype.hide = function(immediate) {
}

TipAbstractView.prototype.move = function(x, y) {
}

/**
 * Alapértelmezett tooltip
 */
function TipDefaultView(helper) {
	TipAbstractView.call(this, helper);

	var _this = this;

	this.twTip = new HTTween(function(x, mode) { _this.tipFadeAnim(x, mode); }, 'sinoidal', 300).init(0);
	this.animTimer = false;
	this.fade = 0;
	this.x = 0;
	this.y = 0;
	this.x1 = 0;
	this.y1 = 0;
	this.xd = 0;
	this.yd = 0;
}

jgtc.__extends(TipDefaultView, TipAbstractView);

TipDefaultView.prototype.getParamsValidator = function() {
	return [
		[ 'tweenIn', 'number', 200 ],
		[ 'tweenOut', 'number', 100 ],
		[ 'skin', 'object', [ "div", { 'class': 'tooltip', 'style': 'position: absolute;', 'tip:content': "html" } ] ],
		[ 'skinHead', 'object', false ],
		[ 'dx', 'number', -10 ],
		[ 'dy', 'number', 26 ],
		[ 'spring', 'number', .2],
		[ 'friction', 'number', .75 ],
		[ 'head', 'string', false ]
	];
}

TipDefaultView.prototype.tipFadeAnim = function(x, mode) {
	if(is.ie) this.element.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=" + (x * 100) + ")";
	else this.element.style.opacity = x;

	if(x == 0 && mode == HTTween.T_END) {
		this.destroy();
		this.helper.dispose();
	} else if(x == 1 && mode == HTTween.T_END) {
		if(is.ie) this.element.style.filter = '';
		else this.element.style.opacity = '';
	}
}

TipDefaultView.prototype.create = function() {
	var _this = this;

	function _tip_attr(element, prefix, attrName, attrValue, jsonml) {
		if(attrName == 'content') {
			if(String(attrValue).toLowerCase() == 'html') {
				element.innerHTML = _this.helper.getParam('tip');
			} else {
				console.error("Ismeretlen tip:content érték a skin descriptorban: %s", attrValue);
			}
		} else if(attrName == 'headContent') {
			if(String(attrValue).toLowerCase() == 'html') {
				element.innerHTML = _this.helper.getParam('head');
			} else {
				console.error("Ismeretlen tip:headContent érték a skin descriptorban: %s", attrValue);
			}
		}
	}

	function _tip_tag(element, tagName, jsonml) {
		if(tagName == 'head') {
			var sHead = _this.helper.getParam('skinHead');
			var head = _this.helper.getParam('head');
			if(sHead !== false && head !== false) {
				return jsonHelper.build(sHead);
			}
		}
		return null;
	}

	var jsonHelper = jgtc.jsonML().addUserAttribute('tip', _tip_attr).addUserTag('tip', _tip_tag);
	this.element = jsonHelper.build(this.helper.getParam('skin'));

	document.body.appendChild(this.element);

	this.updatePosition();
	this.helper.enableMove();

	if(this.helper.getParam('spring') > 0 && this.helper.getParam('friction') > 0) {
		this.animTimer = setInterval(function() { _this.animate(); }, 30);
	}
}

TipDefaultView.prototype.destroy = function() {
	if(this.animTimer !== false) {
		clearInterval(this.animTimer);
		this.animTimer = false;
	}

	this.helper.disableMove();

	document.body.removeChild(this.element);
	this.element = null;
}

TipDefaultView.prototype.show = function(x, y, immediate) {
//	console.trace();
//	console.log("TipDefaultView.prototype.show(%d, %d, %s)", x, y, immediate);

	if(this.twTip.isRunning()) {
		this.twTip.cancel();
	}

	this.x = this.x0 = x;
	this.y = this.y0 = y;
	this.xd = this.yd = 0;
	this.create();

	if(!immediate) {
		var tt = this.helper.getParam('tweenIn');
		if(tt > 0) {
			this.twTip.start(0, 1, tt);
		}
	}
}

TipDefaultView.prototype.hide = function(immediate) {
//	console.trace();
//	console.log("TipDefaultView.prototype.hide(%s)", immediate);

	var tt = this.helper.getParam('tweenOut');
	if(tt > 0 && !immediate) {
		this.twTip.start(1, 0, tt);
		return true;
	} else {
		if(this.twTip.isRunning()) {
			this.twTip.kill();
		}

		this.destroy();
		return false;
	}
}

TipDefaultView.prototype.animate = function() {
	var s = this.helper.getParam('spring');
	var f = this.helper.getParam('friction');
	this.xd = (this.xd + (this.x0 - this.x) * s) * f;
	this.yd = (this.yd + (this.y0 - this.y) * s) * f;

	this.x += this.xd;
	this.y += this.yd;

	this.updatePosition();
}

TipDefaultView.prototype.updatePosition = function() {
	var x = Math.round(this.x) + this.helper.getParam('dx');
	var y = Math.round(this.y) + this.helper.getParam('dy');

	var de = document.documentElement;
	if(x + this.element.offsetWidth > de.scrollLeft + de.clientWidth) x = de.scrollLeft + de.clientWidth - this.element.offsetWidth;
	else if(x < de.scrollLeft) x = de.scrollLeft;
	if(y + this.element.offsetHeight > de.scrollTop + de.clientHeight) y -= this.element.offsetHeight + 45;

	with(this.element.style) {
		left = x + "px";
		top = y + "px";
	}
}

TipDefaultView.prototype.move = function(x, y) {
	if(this.animTimer !== false) {
		this.x0 = x;
		this.y0 = y;
	} else {
		this.x = x;
		this.y = y;
		this.updatePosition();
	}
}


/*
function DefaultTipView(e, descriptor) {
	this._init(e, descriptor);
	this._initTip(tip);
}

DefaultTipView.prototype.getValidator = function() {
	return [
		[ 'timeIn', 'number', 400 ],
		[ 'timeOut', 'number', 40 ],
		[ 'tweenIn', 'number', 200 ],
		[ 'tweenOut', 'number', 100 ],
		[ 'tipFace', 'string', false ],
		[ 'tipFaceHead', 'string', '' ],
		[ 'dx', 'number', -10 ],
		[ 'dy', 'number', 12 ],
		[ 'spring', 'number', .2],
		[ 'friction', 'number', .75 ],
		[ 'head', 'string', false ]
	];
}

DefaultTipView.prototype._init = function(e, tip, tipDescr, _valid) {
	this.descr = new Object();
	if(typeof tipDescr != '')
	for(var i = 0; i < _valid.length; i++) {
		var v = _valid[i];
		if(v[1] === true) {
			if(typeof tipDescr[v[0]] == 'undefined') this.descr[v[0]] = v[2];
			else this.descr[v[0]] = tipDescr[v[0]];
		} else if(typeof tipDescr[v[0]] != v[1]) {
			this.descr[v[0]] = v[2];
		} else {
			this.descr[v[0]] = tipDescr[v[0]];
		}
	}
	_valid = null;
	tipDescr = null;

	this.tipJSON = null;
	this.tip = null;

	if(this.descr.tweenIn > 0 || this.descr.tweenOut > 0) {
		var _this = this;

		this.tw = new HTTween(function(x, mode) {
			if(x == 0 && mode == 2) {
				document.body.removeChild(_this.tip);
				_this.tip = null;
			} else {
				if(is.ie) _this.tip.style.filter = "progid:DXImageTransform.Microsoft.Alpha(opacity=" + (x * 100) + ")";
				else _this.tip.style.opacity = x;
			}
		});
	}

	var element = typeof e == 'string' ? element = document.getElementById(e) : e;
	if(element == null) {
		console.warn("Invalid tip anchor, skipping.");
		console.dir(e);
		console.dir(tipDescr);
		return;
	}

	htTipEngine.attachManager(element, this);

	this.toString = function() {
		return "DefaultTipView: " + element;
	}
}

DefaultTipView.prototype._initTip = function(tip) {
	function _json(s) {
		return s.replace(/\\/g, '\\\\').replace(/\"/g, '\\"').replace(/\n/g, '\\n').replace(/\r/g, '\\r').replace(/\t/g, '\\t').replace(/\f/g, '\\f');
	}

	if(this.descr.tipFace !== false) {
		var head = '';
		if(this.descr.head !== false) {
			head = this.descr.tipFaceHead.replace(/#html#/i, "'innerHTML': \"" + _json(this.descr.head) + '"');
		}

		var j = this.descr.tipFace.replace(/#html#/i, "'innerHTML': \"" + _json(tip) + '"').replace(/#head#/, head).replace(/, *,/, ',');
		eval('this.tipJSON=' + j);

		delete this.descr.tipFace;
		delete this.descr.tipFaceHead;
		delete this.descr.head;
	} else {
		this.tipJSON = [ "DIV", { 'class': 'tooltip', 'style': 'position: absolute;', 'innerHTML': tip } ];
	}
}

DefaultTipView.prototype.over = function(x, y, forced) {
	var _this = this;
	var xd = 0;
	var yd = 0;

	function _rugo() {
		if(_this.tip != null) {
			xd = (xd + (_this.x0 - x) * _this.descr.spring) * _this.descr.friction;
			yd = (yd + (_this.y0 - y) * _this.descr.spring) * _this.descr.friction;

			x += xd;
			y += yd;

			_this.setPosition(Math.round(x), Math.round(y));

			setTimeout(_rugo, 40);
		}
	}

	if(this.tip == null) {
		this.createTip();
		document.body.appendChild(this.tip);
		if(this.descr.spring > 0) {
			setTimeout(_rugo, 40);
		}
	}

	if(this.descr.spring > 0) {
		this.setPosition(x, y);
	}

	if(this.descr.tweenIn > 0) {
		this.tw.start(0, 1, this.descr.tweenIn);
		if(forced) {
			this.tw.cancel();
		}
	}

	this.move(x, y);
}

DefaultTipView.prototype.out = function(x, y, forced) {
	if(this.tip) {
		if(!forced && this.descr.tweenOut > 0) {
			this.tw.start(1, 0, this.descr.tweenOut);
		} else {
			document.body.removeChild(this.tip);
			this.tip = null;
		}
	} else {
		console.warn('Tip, double hide: %s', this);
	}
}

DefaultTipView.prototype.setPosition = function(x, y) {
	x -= this.descr.dx;
	y += this.descr.dy;

	var de = document.documentElement;
	if(x + this.tip.offsetWidth > de.scrollLeft + de.clientWidth) x = de.scrollLeft + de.clientWidth - this.tip.offsetWidth;
	else if(x < de.scrollLeft) x = de.scrollLeft;
	if(y + this.tip.offsetHeight > de.scrollTop + de.clientHeight) y -= this.tip.offsetHeight + 25;

	with(this.tip.style) {
		top = y + "px";
		left = x + "px";
	}
}

DefaultTipView.prototype.move = function(x, y) {
	if(this.tip) {
		if(this.descr.spring > 0) {
			this.x0 = x;
			this.y0 = y;
		} else {
			this.setPosition(x, y);
		}
	} else {
		console.warn('Tip, hidden move: %s', this);
		console.dir(htTipEngine);
	}
}

DefaultTipView.prototype.invisibleMove = function(x, y) {
	if(this.descr.spring > 0) {
		this.x0 = x;
		this.y0 = y;
	}
}

DefaultTipView.prototype.createTip = function() {
	this.tip = jsonML(this.tipJSON);
}
*/

var HTTip = {
	uid: 0,
	over: null,
	showing: null,

	__init: function() {
		function walk(e, d) {
			for(var e1 = e.firstChild; e1 != null; e1 = e1.nextSibling) {
				if(e1.nodeType == 1) {
					try {
						var d1 = d;
						var tf = e1.getAttribute('ht:tipFace');
						var tfh = e1.getAttribute('ht:tipFaceHead');
						var td = e1.getAttribute('ht:tipDescriptor');
						var tvc = e1.getAttribute('ht:tipView');
						if(tf || tfh || td || tvc) {
							d1 = jgtc.clone(d1);

							if(tf) {
								try {
									eval("tf = " + tf + ";");
									d1.skin = tf;
								} catch(err) {
									console.error("Invalid tooltip face: %s (%s)", tf, err);
								}
							}
							if(tfh) {
								try {
									eval("tfh = " + tfh + ";");
									d1.skinHead = tfh;
								} catch(err) {
									console.error("Invalid tooltip faceHead: %s", tfh);
								}
							}
							if(tvc) d1.view = tvc;
							if(td) {
								var d2;
								eval('d2 = {' + td + '}');
								for(var d2i in d2) {
									d1[d2i] = d2[d2i];
								}
							}
						}

						var t = e1.getAttribute('ht:tip');
						if(t) {
							var d2 = jgtc.clone(d1);
							d2.tip = t;
							var fh = e1.getAttribute('ht:tipHead');
							if(fh) {
								d2.head = fh;
							}

//							eval("new " + d2._tipViewClass + "(e1, t, d2)");
							HTTip.create(e1, d2);
						} else {
							walk(e1, d1);
						}
					} catch(err) {
						console.warn("tip error:" + err);
						console.dir(err);
						walk(e1, d);
					}
				}
			}
		}

		walk(document.documentElement, { });
		console.log("Tip engine inited...");
	},

	create: function(element, descriptor) {
		var view;
		var actor;
		var move = false;
		var opened = false;
		var timerIn = false;
		var timerOut = false;
		var x, y;

		var helper = {
			getParam: function(name) {
				return descriptor[name];
			},

			enableMove: function() {
				if(!opened) {
					console.warn("HTTip, enableMove: nincs megjelenítve tip.");
				}

				if(!move) {
					jgtc.captureEvent(document.body, "mousemove", _mmv, false);
					move = true;
				} else {
					console.warn("HTTip, enableMove: dupla enable");
				}
			},

			disableMove: function() {
				if(move) {
					jgtc.releaseEvent(document.body, "mousemove", _mmv, false);
					move = false;
				} else {
					console.warn("HTTip, enableMove: dupla disable");
				}
			},

			dispose: function() {
				if(opened) {
					console.warn("HTTip, dispose: megnyitott tip dispose-olása.");
				}

				HTTip.showing = null;
			},

			isOpened: function() {
				return opened;
			}
		};

		function _mmv(e) {
			if(!e) e = window.event;

			x = e.clientX;
			y = e.clientY;

			with(document.documentElement) { // ff és ie
				x += scrollLeft;
				y += scrollTop;
			}
			with(document.body) { // webkit
				x += scrollLeft;
				y += scrollTop;
			}

			if(move) {
				view.move(x, y);
			}
		}

		function _startTIn() {
			timerIn = setTimeout(_show, descriptor.timeIn);
			jgtc.captureEvent(document.body, "mousemove", _mmv, false);
		}

		function _stopTIn() {
			clearTimeout(timerIn);
			timerIn = false;
			jgtc.releaseEvent(document.body, "mousemove", _mmv, false);
		}

		function _startTOut() {
			timerOut = setTimeout(_hide, descriptor.timeOut);
		}

		function _stopTOut() {
			clearTimeout(timerOut);
			timerOut = false;
		}

		function _over(e) {
			if(HTTip.over != null) {
				console.warn("HTTip: dupla onmouseover. (%o <=> %o)", HTTip.over, actor);
			}

			HTTip.over = actor;

			if(timerOut !== false) {
				_stopTOut();
			}

			if(!opened && timerIn === false) {
				_mmv(e);

				if(HTTip.showing != null) {
					opened = true;
					if(HTTip.showing.uid != actor.uid) {
						HTTip.showing.close();
						HTTip.showing = actor;
						view.show(x, y, true);
					} else {
						view.show(x, y, false);
					}
				} else {
					_startTIn();
				}
			}
		}

		function _out(e) {
			if(HTTip.over == null || HTTip.over.uid != actor.uid) {
				console.warn("HTTip: dupla onmouseout. (%o <=> %o)", HTTip.over, actor);
			} else {
				HTTip.over = null;
			}

			if(timerIn !== false) {
				_stopTIn()
			}

			if(opened && timerOut === false) {
				_startTOut();
			}
		}

		function _click(e) {
			if(timerIn !== false) {
				_stopTIn()
			}

			if(opened) {
				opened = false;
				if(!view.hide(true)) {
					helper.dispose();
				} else if(HTTip.showing != null) {
					console.error("HTTip: invalid státusz, azonnali bezárás dispose() nélkül.");
					HTTip.showing = null;
				}
			}
		}

		function _show() {
			jgtc.releaseEvent(document.body, "mousemove", _mmv, false);
			timerIn = false;

			if(opened) {
				console.warn("HTTip: show, látszó tipen.");
				return;
			}

			if(HTTip.over == null) {
				console.warn("HTTip: show, és nincs mouseover.");
				return;
			} else if(HTTip.over.uid != actor.uid) {
				return;
			}

			if(HTTip.showing != null) {
				if(HTTip.showing.uid != actor.uid) {
					HTTip.showing.close();
				}
			}

			HTTip.showing = actor;
			opened = true;
			view.show(x, y, false);
		}

		function _hide() {
			timerOut = false;

			if(!opened) {
				console.warn("HTTip: hide, nem látszó tipen.");
				return;
			}

			opened = false;
			if(!view.hide(false)) {
				helper.dispose();
			}
		}

		actor = {
			uid: this.uid++,

			close: function() {
				if(timerOut !== false) {
					_stopTOut();
				}
				if(timerIn !== false) {
					console.warn("HTTip: invalid státusz, close() alatt van timerIn");
				}

				opened = false;
				if(!view.hide(true)) {
					helper.dispose();
				} else if(HTTip.showing != null) {
					console.error("HTTip: invalid státusz, azonnali bezárás dispose() nélkül.");
					HTTip.showing = null;
				}
			}
		};

		descriptor = jgtc.validateObject(descriptor, [
			[ 'view', 'function', TipDefaultView ],
			[ 'tip', 'string', "" ],
			[ 'timeIn', 'number', 400 ],
			[ 'timeOut', 'number', 40 ]
		], false);

		(function() {
			view = new descriptor.view(helper);
			var dv = view.getParamsValidator();
			if(dv) {
				descriptor = jgtc.validateObject(descriptor, dv, false);
			}
		})();

		jgtc.captureEvent(element, "mouseover", _over, false);
		jgtc.captureEvent(element, "mouseout", _out, false);
		jgtc.captureEvent(element, "click", _click, false);
	}
}

jgtc.captureEvent(window, "load", function() {
	HTTip.__init();
}, true);

