/* -------------------------------------------------------------------------- */
/** 
 *    @fileoverview
 *       visual effects and animations library.
 *
 *    @version rev004.2007-06-27
 *    @requires common.js
 */
/* -------------------------------------------------------------------------- */




/* -------------------- Constructor : BAEffect (abstract) inherits BAObservable -------------------- */

function BAEffect() {
	this.node           = null;
	this.callBackChains = {};
}

BAEffect.prototype = new BAObservable;



/* -------------------- Constructor : BAEffect_Resize inherits BAEffect -------------------- */

function BAEffect_Resize(node, step, interval, timeLimit) {
	this.node           = node;
	this.step           = (step      > 0) ? step      : 20;
	this.interval       = (interval  > 0) ? interval  : 10;
	this.timeLimit      = (timeLimit > 0) ? timeLimit :  0;
	this.animationTimer = null;
	this.elapsedTimer   = null;
	this.callBackChains = {};
	this.baseNodeCName  = 'BAEffectBase';
}

BAEffect_Resize.prototype = new BAEffect;

BAEffect_Resize.prototype.init = function() {
	if (!this.node || this.node.instanceOf != 'BAElement') {
		throw 'BAEffect_Resize.init: a BAElement node is required.';
	} else {
		this.prepareNode();
	}
}

BAEffect_Resize.prototype.prepareNode = function() {
	if (!this.node.__BAEffectBase__) {
		this.node.__BAEffectBase__ = true;
		this.node.appendClassNameBA(this.baseNodeCName);
	}
	return this.node;
}


BAEffect_Resize.prototype.resizeTo = function(height, timeLimit) {
	this.clearTimer();
	this.doCallBack('onStart', this);
	this.timeLimit = (timeLimit >= 0) ? timeLimit :  this.timeLimit;

	if (this.timeLimit == 0) {
		this.node.style.height = height + 'px';
	} else {
		this.elapsedTimer   = new BATimer;
		this.animationTimer = new BASetInterval(_resizeMain, this.interval, this);
		_resizeMain.call(this);
	}

	function _resizeMain() {
		var ebHeight = this.node.offsetHeight;
		var remainPx = Math.abs(height - ebHeight);
		var factor   = (height < ebHeight) ? -1 : 1;
		var leftTime = this.timeLimit - this.elapsedTimer.getTime();
		if (remainPx > 0) {
			var step = (this.timeLimit == 0) ?
			            	this.step :
			            	(leftTime > 0) ?
			            		remainPx / leftTime * this.interval :
			            		remainPx ;
			ebHeight += factor * Math.max(this.step, Math.round(step));
			ebHeight  = (factor > 0) ? Math.min(ebHeight, height) : Math.max(ebHeight, height);
			this.node.style.height = ebHeight + 'px';
		} else {
			this.postProcess();
		}
	}
}

BAEffect_Resize.prototype.postProcess = function() {
	this.clearTimer();
	this.doCallBack('onComplete', this);
}

BAEffect_Resize.prototype.clearTimer = function() {
	if (this.elapsedTimer) {
		this.elapsedTimer = null;
	}
	if (this.animationTimer) {
		this.animationTimer.clearTimer();
		this.animationTimer = null;
	}
}



/* -------------------- Constructor : BAEffect_Blind inherits BAEffect -------------------- */

function BAEffect_Blind(node, step, interval, timeLimit) {
	this.node           = null;
	this.radicalNode    = node;
	this.step           = (step      > 0) ? step      : 20;
	this.interval       = (interval  > 0) ? interval  : 10;
	this.timeLimit      = (timeLimit > 0) ? timeLimit :  0;
	this.animationTimer = null;
	this.elapsedTimer   = null;
	this.callBackChains = {};
	this.baseNodeCName  = 'BAEffectBase';
	this.curProcessName = '';
}

BAEffect_Blind.prototype = new BAEffect;

BAEffect_Blind.prototype.init = function() {
	if (!this.radicalNode || this.radicalNode.instanceOf != 'BAElement') {
		throw 'BAEffect_Blind.init: a BAElement node is required.';
	} else {
		this.node = this.radicalNode.parentNode;
		if (!this.node.__BAEffectBase__) {
			this.node = this.prepareNode(this.radicalNode);
		}
	}
}

BAEffect_Blind.prototype.prepareNode = function(rdNode) {
	var ebNode                      = document.createElementBA('ins');
	    ebNode.__BAEffectBase__     = true;
	    ebNode.style.position       = 'static';
//	    ebNode.style.float          = 'none';        // Safari causes error.
	    ebNode.style.display        = 'block';
	    ebNode.style.visibility     = 'visible';
	    ebNode.style.overflow       = 'hidden';
	    ebNode.style.border         = 'none';
	    ebNode.style.width          = 'auto';
	    ebNode.style.minWidth       = '0';
//	    ebNode.style.maxWidth       = 'auto';        // WinIE causes error.
	    ebNode.style.height         = 'auto';
	    ebNode.style.minHeight      = '0';
//	    ebNode.style.maxHeight      = 'auto';        // WinIE causes error.
	    ebNode.style.padding        = '0';
	    ebNode.style.margin         = '0';
	    ebNode.style.padding        = '0';
//	    ebNode.style.color          = 'inherit';     // WinIE causes error.
	    ebNode.style.background     = 'transparent';
	    ebNode.style.textDecoration = 'none';
	    ebNode.style.opacity        = '1.0';
	['marginTop', 'marginBottom', 'marginLeft', 'marginRight'].forEach(function(prop) {
	    ebNode.style[prop]          = rdNode.getCurrentStyleBA(prop);  // not work well on Safari.
	    rdNode.style[prop]          = '0';
	}, this);

	rdNode.parentNode.insertBefore(ebNode, rdNode.nextSibling);
	ebNode.appendChildBA(rdNode);
	if (BA.ua.isIE && BA.ua.isIE60) {
		// performance consideration for IE6 or before.
		new BASetTimeout(function() {
			ebNode.appendClassNameBA(this.baseNodeCName);
		}, 1, this);
	} else {
		ebNode.appendClassNameBA(this.baseNodeCName);
	}
	return ebNode;
}

BAEffect_Blind.prototype.open = function(noAnimate) {
	var threshold = this.radicalNode.offsetHeight
	              + this.radicalNode.getAbsoluteOffsetBA().Y - this.node.getAbsoluteOffsetBA().Y;

	if (this.curProcessName != 'open' && this.node.offsetHeight < threshold) {
		this.curProcessName = 'open';
		this.doCallBack('onStart', this.curProcessName, this);
		this.resizeTo(threshold, noAnimate);
	}
}

BAEffect_Blind.prototype.close = function(noAnimate) {
	var threshold = (BA.ua.isWinIEQM) ? 1 : 0;

	if (this.curProcessName != 'close' && this.node.offsetHeight > threshold) {
		this.curProcessName = 'close';
		this.doCallBack('onStart', this.curProcessName, this);
		this.resizeTo(threshold, noAnimate);
	}
}

BAEffect_Blind.prototype.resizeTo = function(height, noAnimate) {
	this.clearTimer();
	if (noAnimate == 'noAnimate') {
		this.node.style.height = height + 'px';
	} else {
		this.elapsedTimer   = new BATimer;
		this.animationTimer = new BASetInterval(_resizeMain, this.interval, this);
		_resizeMain.call(this);
	}

	function _resizeMain() {
		var ebHeight = this.node.offsetHeight;
		var remainPx = Math.abs(height - ebHeight);
		var factor   = (height < ebHeight) ? -1 : 1;
		var leftTime = this.timeLimit - this.elapsedTimer.getTime();
		if (remainPx > 0) {
			var step = (this.timeLimit == 0) ?
			            	this.step :
			            	(leftTime > 0) ?
			            		remainPx / leftTime * this.interval :
			            		remainPx ;
			ebHeight += factor * Math.max(this.step, Math.round(step));
			ebHeight  = (factor > 0) ? Math.min(ebHeight, height) : Math.max(ebHeight, height);
			this.node.style.height = ebHeight + 'px';
			this.doCallBack('onResizing', this.curProcessName, ebHeight, this);
		} else {
			this.postProcess();
		}
	}
}

BAEffect_Blind.prototype.postProcess = function() {
	this.clearTimer();
	this.doCallBack('onComplete', this.curProcessName, this);
	this.curProcessName = '';
}

BAEffect_Blind.prototype.clearTimer = function() {
	if (this.elapsedTimer) {
		this.elapsedTimer = null;
	}
	if (this.animationTimer) {
		this.animationTimer.clearTimer();
		this.animationTimer = null;
	}
}

