/***************
 Object: Focuser
 ***************/
function Focuser(elem, item_class, more_alters)
{
///PROPERTIES
	var self = this;
	this.elemSizes = $e.elemSizes(elem);
	this.items = [];

	var _actEdge = 0.05;
	var _actGrow = 1.20;
	var _actGrowStep = 17;
	var _curNum = undefined;

///METHODS
	this.resize = function()
	{
		self.elemSizes = $e.elemSizes(elem);
	}

	this.init = function()
	{
		var itemsElems = $e.elemsByClass(item_class, elem);
		for (var i=0; i < itemsElems.length; i++)
		{
			var itemStyle = $e.getStyle(itemsElems[i]);
			var width = parseInt(itemStyle.width);
			var height = parseInt(itemStyle.height);
			var ratio = height / width;
			var alters = more_alters;
			alters.push(
				{prop:'height', units:'px', initial:height, focused:Math.floor(height * _actGrow), step:_actGrowStep}
			);
			alters.push(
				{prop:'width', units:'px', initial:width, focused:Math.floor(width * _actGrow), step:_actGrowStep / ratio}
			);

			this.items.push({
				elem: itemsElems[i],
				pos: parseFloat(itemStyle.left),
				width: width,
				height: height,
				ratio: ratio,
				altering: new Altering(itemsElems[i], alters)
			});
		}

		elem.onmousemove = this.onMouseMove;
		elem.onmouseout = this.onMouseOut;
	}

	/**
	 * Mouse move handler
	 */
	this.onMouseMove = function(e)
	{
		e = $e.event(e);
		// calculate offset
		var boundX = self.elemSizes.left;
		var boundWidth = self.elemSizes.width;

		var pos = (e.x - boundX) / boundWidth;
		var num = Math.floor( (pos - _actEdge) / (1 - 2*_actEdge) * self.items.length);
		if (num < 0 || num >= self.items.length ) num = undefined;
		if (num !== _curNum) {
			_curNum = num;
			for (var i=0; i < self.items.length; i++) {
				if (i === num) self.items[i].altering.focus(); else self.items[i].altering.unfocus();
			}
		}

		return false;
	}

	/**
	 * Mouse out handler
	 */
	this.onMouseOut = function(e)
	{
		e = $e.event(e);
		if ($e.elemIsOf(e.target, elem) && !$e.elemIsOf(e.related, elem)) {
			_curNum = undefined;
			for (var i=0; i < self.items.length; i++) self.items[i].altering.unfocus();
		}
	}

	this.init();
};



/****************
 Object: Altering
 ****************/
function Altering(elem, alters)
{
	var self = this;
	var _alters = [];
	var _currents = [];
	var _intFocus = undefined;
	var _intUnfocus = undefined;

	var _frametime = 30;

	this.init = function()
	{
		for (var i=0; i<alters.length; i++) {
			// alter must be changing
			if (alters[i].initial == alters[i].focused) continue;

			// retrieve element or subelements for alter
			var subs = undefined;
			if (alters[i].subclass) {
				subs = $e.elemsByClass(alters[i].subclass, elem);
				//alert(subs.length);
				//alert(subs[0]);

				if (subs.length < 1) continue;
			}

			_alters.push({
				elem: elem,
				subs: subs,
				prop: alters[i].prop,
				units: alters[i].units,
				initial: alters[i].initial,
				focused: alters[i].focused,
				step: (alters[i].initial < alters[i].focused)? Math.abs(alters[i].step) : -Math.abs(alters[i].step)
			});
			// store alter current
			_currents.push(alters[i].initial);
		}

		this.applyCurrents();

		// Discard Motions
		_intFocus = clearInterval(_intFocus);
		_intUnfocus = clearInterval(_intUnfocus);
	}

	/**
	 * Applies currents alters
	 */
	this.applyCurrents = function()
	{
		for (var i=0; i<_alters.length; i++) {
			var alter = _alters[i];
			//alert(alter.subs);
			if (alter.subs) {
				for (var j=0; j<alter.subs.length; j++) {
					alter.subs[j].style[alter.prop] = '' + _currents[i] + alter.units;
				}
			} else {
				alter.elem.style[alter.prop] = '' + _currents[i] + alter.units;
			}
		}
	}


	/**
	 * Focuses the altering
	 */
	this.focus = function()
	{
		_intUnfocus = clearInterval(_intUnfocus);
		if (_intFocus === undefined) {
			_intFocus = setInterval(function(){
				var alters_num = _alters.length;
				// recalculate
				for (var i=0; i<alters_num; i++) {
					var alter = _alters[i];
					var done = 0;
					_currents[i] += alter.step;
					if (
						(alter.step > 0 && _currents[i] >= alter.focused) ||
						(alter.step < 0 && _currents[i] <= alter.focused)
					) {
						_currents[i] = alter.focused;
						done++;
					}
				}
				// repaint
				self.applyCurrents();
				// done?
				if (done == alters_num) _intFocus = clearInterval(_intFocus);
			}, _frametime);
		}

	}

	/**
	 * Unfocuses the altering
	 */
	this.unfocus = function()
	{
		_intFocus = clearInterval(_intFocus);
		if (_intUnfocus === undefined) {
			_intUnfocus = setInterval(function(){
				var alters_num = _alters.length;
				// recalculate
				for (var i=0; i<alters_num; i++) {
					var alter = _alters[i];
					var done = 0;
					_currents[i] -= alter.step;
					if (
						(alter.step > 0 && _currents[i] <= alter.initial) ||
						(alter.step < 0 && _currents[i] >= alter.initial)
					) {
						_currents[i] = alter.initial;
						done++;
					}
				}
				self.applyCurrents();
				// done?
				if (done === alters_num) _intUnfocus = clearInterval(_intUnfocus);
			}, _frametime);
		}
	}

	this.init();
}


