xAddEventListener(window, 'load', btnInit, false);
xAddEventListener(window, 'load', trgInit, false);
xAddEventListener(window, 'resize', animBoxesResize, false);

function btnInit()
{
	var i, a = xGetElementsByClassName('jsButton');
	for (i = 0; i < a.length; ++i) { 
		a[i].onclick = btnOnClick; 
	}
}

function trgInit()
{
	var i, a = xGetElementsByClassName('jsTrigger');
	for (i = 0; i < a.length; ++i) { 
		a[i].onmouseover = trgOnOver;
		a[i].onmouseout = trgOnOut;
	}
	a = xGetElementsByClassName('jsContainer');
	for (i = 0; i < a.length; ++i) {
		a[i].onmouseover = trgOnOver;
		a[i].onmouseout = trgOnOut;
	}
}

function btnOnClick()
{
	var i, xa = animBox.instances;
	for (i = 0; i < xa.length; ++i)
	{
		if ('btn_' + xa[i].eid == this.id) {
			if (xa[i].st == 1) {
				xa[i].expand();
			}
			else if (xa[i].st == 2) {
				xa[i].collapse();
			}
			else xa[i].animate();
		}
	}
}

function trgOnOver()
{
	var i, xa = animBox.instances;
	for (i = 0; i < xa.length; ++i)
	{
		if ('btn_' + xa[i].eid == this.id || xa[i].eid == this.id) {
			if (xa[i].out_tmr) {
				clearTimeout(xa[i].out_tmr);
				xa[i].out_tmr = null;
			}
			if (xa[i].st == 1) {
				xa[i].expand(); xa[i].act = 1;
			}
			else {
				xa[i].act = 1;
			}
		}
	}
}

function trgOnOut()
{
	var i, xa = animBox.instances;
	for (i = 0; i < xa.length; ++i)
	{
		if ('btn_' + xa[i].eid == this.id || xa[i].eid == this.id) {
			xa[i].act = 0;
			if (!xa[i].out_tmr) xa[i].out_tmr = setTimeout('trgOnTimer(' + xa[i].idx + ')', 400);
		}
	}
}

function trgOnTimer(idx)
{
	var xa = animBox.instances;
	xa[idx].out_tmr = null;
	if (xa[idx].act == 0) {
		xa[idx].collapse();
	}
}

function animBoxesResize()
{
	var i, a = animBox.instances;
	for (i = 0; i < a.length; ++i)
	{
		if (a[i].pe) {
			a[i].reposition();
		}
	}
}

function animBox(e, st, at, qc, tt, orf, otf, oed, oea, oef) // Object Prototype
{
	this.init(e, st, at, qc, tt, orf, otf, oed, oea, oef);
	var a = animBox.instances;
	var i;
	for (i = 0; i < a.length; ++i) {
		if (!a[i]) break;
	} // find an empty slot
	a[i] = this;
	this.idx = i;
	return this;
}

animBox.instances = []; // static property

animBox.prototype.init = function(e, st, at, qc, tt, orf, otf, oed, oea, oef)
{
	this.e = xGetElementById(e); // e is object ref or id str
	this.pe = 'bababah'; // pe is button or triger object ref or id str
	this.xs = null; // relative x shift: '-', null, '+'
	this.ys = null; // relative y shift: '-', null, '+'
	this.eid = e; // e is object ref or id str
	this.act = 0; // mouse status: 0=out, 1=over
	this.st = st || 2; // status: 1=collapsed, 2=expanded
	this.at = at || 2; // acceleration type: 1=linear, 2=sine, 3=cosine
	this.qc = qc || 1; // acceleration quarter-cycles
	this.tt = tt || 2000; // total time
	this.orf = orf; // onRun function
	this.otf = otf; // onTarget function
	this.oed = oed; // delay before calling onEnd
	this.oea = oea; // onEnd argument
	this.oef = oef; // onEnd function
	this.to = 20; // timer timeout
	this.as = false; // auto-start

	this.x = xPageX(this.e);
	this.y = xPageY(this.e);
	this.w = xWidth(this.e);
	this.h = xHeight(this.e);
	if (st == 1) // collapsed
	{
		xHide(this.e);
		xResizeTo(e, this.w, 2); // setting (…,1) seemed to cause problems? (perhaps because this ele has a border)
	}
	return this;
};

animBox.prototype.reposition = function(e, xs, ys)
{
	var x, y, a = animBox.instances[this.idx];
	if (!e)
	{
		e = a.pe;
		xs = a.xs;
		ys = a.ys
	}
	if (!xGetElementById(e)) return;
	var px = xPageX(e);
	var py = xPageY(e);
	var pw = xWidth(e);
	var ph = xHeight(e);
	a.pe = e;
	a.xs = xs;
	a.ys = ys;
	if (xs == '+') { x = px + pw; }
	else if (xs == '-') { x = px - a.w + pw; }
	else { x = px; }
	if (ys == '+') { y = py + ph; }
	else if (ys == '-') { y = py - a.h; }
	else { y = py; }
	xMoveTo(a.eid, x, y);
}

animBox.prototype.animate = function()
{
	var a = animBox.instances[this.idx];
	if (a.st == 1) { alert('expanding'); a.expand(); }
	else if (a.st == 2) { alert('collapsing'); a.collapse(); }
	else return;
}

animBox.prototype.expand = function()
{
	var a = animBox.instances[this.idx];
	a.x1 = xWidth(a.e); // start size
	a.y1 = xHeight(a.e);
	a.x2 = a.w; // end size
	a.y2 = a.h;
	a.orf = onRun;
	a.otf = onTarget;
	a.oea = 0;
	a.oef = onEnd;

	xShow(a.e);
	a.start();

	function onRun(o) { xResizeTo(o.e, Math.round(o.x), Math.round(o.y)); }
	function onTarget(o) { }
	function onEnd(o) { xResizeTo(o.e, o.w, o.h); o.st = 2; }
}

animBox.prototype.collapse = function()
{
	var a = animBox.instances[this.idx];
	a.x1 = xWidth(a.e); // start size
	a.y1 = xHeight(a.e);
	a.x2 = a.w; // end size
	a.y2 = 2;
	a.orf = onRun;
	a.otf = onTarget;
	a.oea = 0;
	a.oef = onEnd;

	a.start();
	return a;

	function onRun(o) { xResizeTo(o.e, Math.round(o.x), Math.round(o.y)); }
	function onTarget(o) { }
	function onEnd(o) { xHide(o.e); xResizeTo(o.e, o.w, 2); o.st = 1; }
}

animBox.prototype.start = function()
{
	var a = this;
	if (a.at == 1) { a.ap = 1 / a.tt; } // linear acceleration
	else { a.ap = a.qc * (Math.PI / (2 * a.tt)); } // sine and cosine acceleration
	// magnitudes
	if (xDef(a.x1)) { a.xm = a.x2 - a.x1; }
	if (xDef(a.y1)) { a.ym = a.y2 - a.y1; }
	// end point if even number of cyles
	if (!(a.qc % 2)) {
		if (xDef(a.x1)) a.x2 = a.x1;
		if (xDef(a.y1)) a.y2 = a.y1;
	}
	if (!a.tmr) { // if not already running
		var d = new Date();
		a.t1 = d.getTime(); // start time
		a.tmr = setTimeout('animBox.run(' + a.idx + ')', 1);
	}
};

animBox.run = function(i) // static method
{
	var a = animBox.instances[i];
	if (!a) return;
	var d = new Date();
	a.et = d.getTime() - a.t1; // elapsed time
	if (a.et < a.tt)
	{
		a.tmr = setTimeout('animBox.run(' + i + ')', a.to);
		a.af = a.ap * a.et;  // linear acceleration
		if (a.at == 2) { a.af = Math.abs(Math.sin(a.af)); } // sine acceleration
		else if (a.at == 3) { a.af = 1 - Math.abs(Math.cos(a.af)); } // cosine acceleration
		// instantaneous point
		if (xDef(a.x1)) a.x = a.xm * a.af + a.x1;
		if (xDef(a.y1)) a.y = a.ym * a.af + a.y1;
		a.orf(a); // onRun
	}
	else
	{
		var rep = false; // repeat
		if (xDef(a.x2)) a.x = a.x2;
		if (xDef(a.y2)) a.y = a.y2;
		a.tmr = null;
		a.otf(a); // onTarget
		if (xDef(a.oef)) { // onEnd
			if (a.oed) setTimeout(a.oef, a.oed); // no args passed to oef if oed or oef is str
			else if (xStr(a.oef)) { rep = eval(a.oef); }
			else { rep = a.oef(a, a.oea); }
		}
		if (rep) { a.resume(true); } // there may be a problem here if the anim is paused and oef returns true
  }
};

animBox.prototype.kill = function()
{
	animBox.instances[this.idx] = null;
};

