/**---------------------------------------------*\
 * A hint that fades in and out automatically	*
 * @author Wang Jianchun						*
 * @version 1.0									*
\*----------------------------------------------*/
var SmartHint = Class.create();
SmartHint.prototype = {
	message:		"",
	container:		null,// where the hint is to put
	
	hintSpan:		null,
	hintStyle:		{border:"1px solid #FC0", backgroundColor:"#FFC", fontSize:"13px", color:"#259", position:"absolute"},
	
	theTimer:		null,// remembers the setTimeout
	timeInterval:	100,// ms, inc/dec opacity every 100 ms
	retainTime:		50,// ms, time for retain full opacity
	incTimes:		10,// how many times inc to full opacity
	decTimes:		20,// how many times dec to zero opacity
	
	offsetL:		0,// adjust the left position
	offsetT:		0,// adjust the top position
	
	currentOpacity:	0,
	
	initialize: function(msg, con) {
		this.hintSpan = document.createElement("span");
		
		this.setMessage(msg);
		this.setContainer(con);
		this.setHintStyle(this.hintStyle);
		
		this.setOpacity(this.currentOpacity);
	},
	/**
	 * setters
	 */
	setMessage: function(msg) {
		this.message = msg ? msg.trim() : "";
	},
	setContainer: function(con) {
		this.container = (con && $(con)) ? $(con) : document.body;
	},
	setHintStyle: function(s) {
		Element.setStyle(this.hintSpan, s);
	},
	setTimeInterval: function(interval) {
		this.timeInterval = Math.floor(interval) || 100;
	},
	setRetainTime: function(time) {
		this.retainTime = time ? (time * 1000) : 1000;
	},
	setIncTimes: function(incTimes) {
		this.incTimes = Math.floor(incTimes) || 10;
	},
	setDecTimes: function(decTimes) {
		this.decTimes = Math.floor(decTimes) || 10;
	},
	setOffsetLT: function(offsetL, offsetT) {
		this.setOffsetL(offsetL);
		this.setOffsetT(offsetT);
	},
	setOffsetL: function(offsetL) {
		this.offsetL = Math.floor(offsetL) || 0;
	},
	setOffsetT: function(offsetT) {
		this.offsetT = Math.floor(offsetT) || 0;
	},
	setOpacity: function(op) {
		if(op <= 0) {
			op = 0;
		} else if(op >= 1) {
			op = 1;
		}
		if(document.all) {// IE
			this.setHintStyle({filter: "alpha(opacity=" + (op * 100) + ")"});
		} else {
			this.setHintStyle({opacity: op});
		}
	},
	/**
	 * The only interface for user
	 */
	show: function() {
		var ltOffsets = Position.cumulativeOffset(this.container);// left-top offsets
		
		this.hintSpan.innerHTML = this.message;
		this.setHintStyle({left: (ltOffsets[0] + this.offsetL) + "px", top: (ltOffsets[1] + this.offsetT) + "px"});
		
		document.body.appendChild(this.hintSpan);
		this.hintFadeIn();
	},
	/**
	 * Display the hintspan in a fade-in way
	 * @private
	 */
	hintFadeIn: function() {
		if(this.currentOpacity >= 1) {
			this.theTimer = null;
			this.theTimer = setTimeout(this.hintFadeOut.bind(this), this.retainTime);
		} else {
			this.currentOpacity += 1/this.incTimes;
			this.setOpacity(this.currentOpacity);
			
			this.theTimer = setTimeout(this.hintFadeIn.bind(this), this.timeInterval);
		}
	},
	/**
	 * Remove the hintspan in a fade-out way
	 * @private
	 */
	hintFadeOut: function() {
		if(this.currentOpacity <= 0) {
			this.theTimer = null;
			if(this.hintSpan && this.hintSpan.parentNode) {
				this.hintSpan.parentNode.removeChild(this.hintSpan);
			}
		} else {
			this.currentOpacity -= 1/this.decTimes;
			this.setOpacity(this.currentOpacity);
			
			this.theTimer = setTimeout(this.hintFadeOut.bind(this), this.timeInterval);
		}
	}
};