/**********************************************************************************************************

DESCRIPTION:
Xpander turns any block element into an expandable box. 
It does this by wrapping the given block element in two 
divs: a container and a clipper. Both divs are given class names 
and you can style them if you wish.  See the Xpander.html example.

ARGUMENTS:
elm: the base element. Can be a string ID or HTMLELement object
clip: The height in pixels where the base element should be clipped
duration (optional, default is 500): the length of time in milliseconds that it will take to complete the effect
expImgSrc (optional): path to an expand image
expImgSrc (optional): path to a collapse image

USAGE:

To unobtrusively call it onload, put the following inside the <head>: 
<script type="text/javascript">
	Xpander.Utils.addEvent(window,'load', function() {
		new Xpander('divName', 100, 800, 'images/global/icon_collapse.gif', 'images/global/icon_expand.gif');
	});
</script>
	
If you wish call it from within the body, be sure to call it AFTER the element has already been loaded:
<div id="foo">Bar</div>
<script type="text/javascript">
	new Xpander('foo', 100, 800, 'images/global/icon_collapse.gif', 'images/global/icon_expand.gif');
</script>
	
*************************************************************************************************************/

var Xpander = function(elm, clip, duration, expImgSrc, colImgSrc) {

	if(!document.getElementById) return;

	// Get the element
	if(typeof elm == "string") this.elm = document.getElementById(elm);

	// Set the height at which we should clip
	this.clip = parseInt(clip);
	
	// Set the original height
	this.originalHeight = this.elm.offsetHeight;
	
	// Set the speed of the effect
	this.duration = (duration) ? Number(duration) : 800;

	// Create IMG elements for expand/collapse buttons (optional)
	if(expImgSrc && colImgSrc) {
		this.colImgSrc = colImgSrc;
		this.colImg = document.createElement('img');
		this.colImg.src = colImgSrc;
		this.colImg.alt = '';
		this.colImg.className = 'XpanderToggleImg';

		this.expImgSrc = expImgSrc;		
		this.expImg = document.createElement('img');
		this.expImg.src = expImgSrc;
		this.expImg.alt = '';
		this.expImg.className = 'XpanderToggleImg';
	}

	// Detect IE 5 Mac because it doesn't support setInterval like we want it to
//	this.isIE5Mac = document.all && document.getElementById &&  !document.mimeType && !window.opera;
	
	// Intialize 
	this._init();
};

Xpander.prototype = {
	
	/* Public Methods */
	
	toggle: function() {
		if(this.timer) return false;
		(!this.xpanded) ? this._expand() : this._collapse();
	},
	

	/* Private Methods */
	
	_init: function() {
		// Set the default state 
		this.xpanded = false;
		
		// Create clipping div
		this.clipDiv = this.elm.parentNode.insertBefore(document.createElement('div'), this.elm);
		this.clipDiv.appendChild(this.elm);
		this.clipDiv.className = 'XpanderClip';
		this.clipDiv.style.overflow = 'hidden';

		
		// Create container div 
		this.containerDiv = this.clipDiv.parentNode.insertBefore(document.createElement('div'), this.clipDiv);
		this.containerDiv.className = 'XpanderContainer'
		this.containerDiv.appendChild(this.clipDiv);
		
		// Append toggle button
		if(this.colImg && this.expImg) this.containerDiv.appendChild(this.colImg);
		
		// Attach events to buttons
		var me = this;
		if(this.colImg) Xpander.Utils.addEvent(this.colImg,'click', function() { me.toggle(); })
		if(this.expImg) Xpander.Utils.addEvent(this.expImg,'click', function() { me.toggle(); })
	
		
		// recalulate clipping height (accounts for padding and any images)
		this.clip = this.clip - (this.containerDiv.offsetHeight - this.clipDiv.offsetHeight);
		this.clipDiv.style.height = this.clip + "px";

	
	},

	_setToggleImg: function() {
		if(this.xpanded) {
			this.colImg.parentNode.replaceChild(this.expImg,this.colImg);
		} else {
			this.expImg.parentNode.replaceChild(this.colImg,this.expImg);
		}
	},
	
	_expand: function() {
		if(this.isIE5Mac) {
			this.colImg.src = this.expImgSrc;
		 	this.clipDiv.style.height = this.originalHeight+'px';
		} else {
			this._start(this.clipDiv.style.height, this.originalHeight);
		}
		this.xpanded = true;
	},
	
	_collapse: function() {
		if(this.isIE5Mac) {
			this.colImg.src = this.colImgSrc;
			this.clipDiv.style.height = this.clip+'px';
		} else {
			this._start(this.clipDiv.style.height, this.clip);
		}
		this.xpanded = false;
	
	},
	
	_start: function(from, to) {
		if (this.timer != null) return;
		this.from = parseInt(from);
		this.to = parseInt(to);
		this.startTime = (new Date).getTime();

		// Fix scope for interval
		var me = this;
		this.timer = setInterval (function() { me._step() }, 13);
	},
	
	_step: function() {
		
	 	var time  = (new Date).getTime();
			if (time >= this.duration + this.startTime) {
				this.now = this.to;
				clearInterval (this.timer);
				this.timer = null;
				this._setToggleImg();
			} else {
				var pos = (time - this.startTime) / (this.duration);
				this.now = this._sine(pos) * (this.to-this.from) + this.from;
			}
		this.clipDiv.style.height = this.now+'px';
	},
	
	_sine: function(pos){
		return ((-Math.cos(pos*Math.PI)/2) + 0.5);
	}
};

Xpander.Utils = {
	// Cross browser addEvent
	addEvent: function( obj, type, fn ) {
		if (obj.addEventListener) {
			obj.addEventListener( type, fn, false );
		}
		else if (obj.attachEvent) {
	
			obj["e"+type+fn] = fn;
			obj[type+fn] = function() { obj["e"+type+fn]( window.event ); }
			obj.attachEvent( "on"+type, obj[type+fn] );
		}
		else {	
			oldFn = obj["on"+type];
			obj["on"+type] = function() {
				fn();
				oldFn();
			}
		}
	}
}
