/***********************************************************

	Castwide FX Library

	Author: Fred Snyder
	Company: Castwide Technologies
	URL: http://castwide.com
	Date Created: Nov 16, 2006
	Date Modified: Jan 12, 2007

	Required files:
	* prototype.js (http://prototype.conio.net)

	1-12-2007	Added distance function

***********************************************************/

/*
The CFX library provides base functions and constructors
for visual effects.  In application code, these features
should normally be accessed through the extended methods
that the $CFX function adds to HTML elements (see below).
*/

var CFX = new function() {
	return {

		// Browser-independent methods to retrieve the
		// absolute X and Y positions of elements

		getPosX: function(obj) {
			var curleft = 0;
			if (obj.offsetParent)
			{
				while (obj.offsetParent)
				{
					curleft += obj.offsetLeft
					obj = obj.offsetParent;
				}
			}
			else if (obj.x)
				curleft += obj.x;
			return curleft;
		},

		getPosY: function(obj) {
			var curtop = 0;
			if (obj.offsetParent)
			{
				while (obj.offsetParent)
				{
					curtop += obj.offsetTop
					obj = obj.offsetParent;
				}
			}
			else if (obj.y)
				curtop += obj.y;
			return curtop;
		},

		distance: function(x1, y1, x2, y2) {
			return Math.sqrt( Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2) );
		},

		// Mover constructor to move elements around the
		// screen

		Mover: function(el, startX, startY, endX, endY, millisec) {
			var posX = startX;
			var posY = startY;
			var offX = (endX - startX) / (millisec / 50);
			var offY = (endY - startY) / (millisec / 50);

			// Prepare the element for motion.  Elements
			// must be set to absolute position in order
			// to be movable.
			el.style.position = 'absolute';
			el.style.left = startX + 'px';
			el.style.top = startY + 'px';

			this.move = function() {
				posX += offX;
				posY += offY;
				el.style.left = Math.floor(posX) + 'px';
				el.style.top = Math.floor(posY) + 'px';
			}

			this.last = function() {
				el.style.left = (endX*1.5) + 'px';
				el.style.top = endY + 'px';
			}

			for (var i = 0; i < (millisec / 50) - 1; i++) {
				setTimeout(this.move, i * 50);
			}
			setTimeout(this.last, i * 50);
		},

		// Fader constructor to change the opacity of elements

		Fader: function(el, startOpac, endOpac, millisec) {
			var speed = Math.round(millisec / 100);
			var timer = 0;
			var curOpac = startOpac;
			var offOpac = (endOpac - startOpac) / (millisec / 100);

			this.fade = function() {
				curOpac += offOpac;
				el.opacity.set(curOpac);
			}

			this.last = function() {
				el.opacity.set(endOpac);
			}

			for (var i = 0; i < (millisec / 100) - 1; i++) {
				setTimeout(this.fade, i * 100);
			}
			setTimeout(this.last, i * 100);
		},

		// Animator constructor to perform generic style
		// transitions (essentially any numeric property)

		Animator: function(el, prop, unit, startVal, endVal, millisec) {
			var curVal = startVal;
			var offVal = (endVal - startVal) / (millisec / 50);

			this.animate = function() {
				curVal += offVal;
				el.style[prop] = curVal + unit;
			}

			this.last = function() {
				el.style[prop] = endVal + unit;
			}

			for (var i = 0; i < (millisec / 50) - 1; i++) {
				setTimeout(this.animate, i * 50);
			}
			setTimeout(this.last, i * 50);
		}

	};
}

/*
The $CFX function extends elements with methods for
visual effects.  In order to use any of the effects, the
element or its ID must be passed to the $CFX function at
least once.

A simple example:

	$CFX('element-id').opacity.fade(100, 0, 1000);

A longer example:

	var ref = $CFX('element-id');
	ref.opacity.fade(100, 0, 1000);
	// Later...
	var ref2 = document.getElementById('element-id');
	ref2.opacity.fade(0, 100, 1000);

When the element is referenced via the ref2 variable in
the above example, it is not necessary to call the $CFX
function a second time.  Conversely, multiple passes to
the $CFX function will not hurt the element, either.  The
function checks to see if the extended methods exist
before adding them.)

The following methods are implemented:

	POSITION METHODS
	element.position.getX();
	element.position.getY();
	element.position.set(x, y);
	element.position.move(startx, starty, endx, endy, milliseconds);
	element.position.moveTo(x, y, millisec);

	OPACITY METHODS
	element.opacity.set(opacity);
	element.opacity.face(start, end, milliseconds);

	ANIMATE METHOD
	element.animate(property, unit, start, end, milliseconds);
*/

function $CFX(i) {
	// Get element by ID or assume argument is element
	if (!i.tagName) {
		var element = document.getElementById(i);
	} else {
		var element = i;
	}

	if (!element.opacity) element.opacity = {
		set: function(opac) {
			element.style.opacity = (opac / 100);
			element.style.MozOpacity = (opac / 100);
			element.style.KhtmlOpacity = (opac / 100);
			element.style.filter = "alpha(opacity=" + opac + ")";
		},

		fade: function(startOpac, endOpac, millisec) {
			new CFX.Fader(element, startOpac, endOpac, millisec);
		}
	};

	if (!element.position) element.position = {
		set: function(x, y) {
			element.style.position = 'absolute';
			element.style.left = x  + 'px';
			element.style.top = y + 'px';
		},

		getX: function() {
			return CFX.getPosX(element);
		},

		getY: function() {
			return CFX.getPosY(element);
		},

		move: function(sX, sY, eX, eY, millisec) {
			new CFX.Mover(element, sX, sY, eX, eY, millisec);
		},

		moveTo: function(x, y, millisec) {
			new CFX.Mover(element, element.position.getX(), element.position.getY(), x, y, millisec);
		}
	};

	if (!element.animate) element.animate = function(prop, unit, startVal, endVal, millisec) {
		new CFX.Animator(element, prop, unit, startVal, endVal, millisec);
	}

	return element;
}

