var ElementHint = {
	initialize: function () {
		Object.extend(this, TemplatedElement);
		this._buildFromTemplate('element_hint', false);
		this.observedElements = new Array();

		var elementsToAttachTo = document.getElementsByClassName ('elementHintStarter');
		for (var i = 0; i < elementsToAttachTo.length; i ++) {
			var elem = elementsToAttachTo[i];
			var text = elem.title;
			var ind = text.indexOf(';');
			var title = text.substring(0, ind);
			text = text.substring(ind+1);
			elem.title = '';
			text = text.replace(/&lt;/g, '<').replace(/&gt;/g, '>');
			this.observe (elem, title, text);
		}
	},
	observe: function (element, title, body, type) {
		this.observedElements.push({element:element, title:title, body:body, type:type});
		var tn = element.tagName.toLowerCase();
		if (tn == 'input' || tn == 'textarea' || tn == 'select') {
			Event.observe(element,"focus",this.onElementFocused.bindAsEventListener(this, this.observedElements.length - 1));
			Event.observe(element,"blur",this.onElementBlurred.bindAsEventListener(this, this.observedElements.length - 1));
			Event.observe(element,"focus", this.onInputFocused.bindAsEventListener(element) );
			Event.observe(element,"blur", this.onInputBlurred.bindAsEventListener(element) ); // notice the binding to the element!!!
		}
		Event.observe(element,"mouseover",this.onElementFocused.bindAsEventListener(this, this.observedElements.length - 1));
		Event.observe(element,"mouseout",this.onElementBlurred.bindAsEventListener(this, this.observedElements.length - 1));
	},

	onInputFocused: function () {
		this.focused = true;
	},
	onInputBlurred: function () {
		this.focused = false;
	},

	onElementFocused: function (event, id) {
		var details = this.observedElements[id];
		var pos = Position.cumulativeOffset(details.element);
		this.element.style.top = pos[1] + "px";
		this.element.style.left = pos[0] + details.element.offsetWidth + 3 + "px";
		this.title.innerHTML = details.title;
		Element.removeClassName(this.title, "error")
		Element.removeClassName(this.title, "info");
		Element.removeClassName(this.title, "alert");
		switch (details.type) {
			case "info": Element.addClassName(this.title, "info");break;
			case "alert": Element.addClassName(this.title, "alert");break;
			case "error": Element.addClassName(this.title, "error");break;
		}
		this.content.innerHTML = details.body;
		this.element.style.display = 'block';
		this.currentElementID = id;
	},
	onElementBlurred: function (event) {
		if (this.currentElementID === null)return;
		if (this.observedElements[this.currentElementID].element.focused) return;
		this.currentElementID = null;
		this.element.style.display = 'none';
	},
	forceHide: function () {
		this.currentElementID = null;
		this.element.style.display = 'none';
	}
}

var ElementHintFading = Class.create();
ElementHintFading.prototype = {
	initialize: function (options) {
		this.keepVisibleDelay = 4000;
		this.animationSteps = 20;
		this.animationInterval = 60;
		Object.extend(this, TemplatedElement);
		this._buildFromTemplate('element_hint_fading');
		Object.extend(this, options);
		if (this.upwards)
			Element.addClassName(this.element, 'upwards');
		this.element.style.display = 'none';
		this._onAnimationTimer = this.onAnimationTimer.bind(this);
	},
	show: function (text) {
		if (this.animating)
			this.cancelCurrentAnimationAndHide();
		this.animating = true;
		this.animation = 'show';
		this.animationStep = 0;
		this.contentElement.innerHTML = text;
		this.onAnimationTimer();
		this.element.style.display = 'block';
	},
	onAnimationTimer: function () {
		var o = this.animationStep / this.animationSteps;
		if (this.animation == 'hide') o = 1-o;
		this.element.style.mozOpacity = this.element.style.opacity = o;
		this.element.style.filter = 'alpha(opacity=' + (100 * o) + ')';
		this.animationStep ++;
		if (this.animationStep <= this.animationSteps) {
			this._currentTimer = setTimeout(this._onAnimationTimer, this.animationInterval);
		} else
			this.onAnimationEnd();
	},
	onAnimationEnd: function () {
		if (this.animation == 'show')
			this._currentTimer = setTimeout (this.hide.bind(this), this.keepVisibleDelay);
		else {
			this.animating = false; // all animation is over
			this.element.style.display = 'none';
		}
	},
	hide: function () {
		this.animation = 'hide';
		this.animationStep = 0;
		this.onAnimationTimer();
	},
	cancelCurrentAnimationAndHide: function () {
		if (this.animating) {
			clearTimeout(this._currentTimer);
			this.animating = false;
			this.element.style.mozOpacity = this.element.style.opacity = '0';
			this.element.style.filter = 'alpha(opacity=0)';
			this.element.style.display = 'block';
		}
	}
};
