/**
 * ISkySpotter Personal Tracker
 */
com_pagasg_www_fx_transition = new es_lang.Package(true,
	/*Title*/   'Testing Package',
	/*Docs */   '-- none --',
	/*Package*/ function() {
		// Imports
		var LANG = es_lang;
		var StringBuilder = LANG.StringBuilder;
		var LOG = es_util_logging;
		var WU = com_pagasg_www_util;

		// Constructor imports
		var Class = es_lang.Class;
		var Enum = es_lang.Enum;
		var StringBuilder = LANG.StringBuilder;
		var Objects = WU.Objects;
		var Cycle = WU.Cycle;
		var UserAgent = WU.UserAgent;

		// Function imports
		var extend = Class.extend;
		var implement = Class.implement;
		var enumerate = Enum.enumerate;

		// ****** Range ******
		var Range = function(start, end) {
			this.start = start;
			this.end = end;
			this.diff = end - start;

			this.toString = function() {
				return '[' + start + ',' + end + ']';
			}
		}

		// ****** Transition ******
		var Transition = implement({
				compute: function(/*int | int[]*/ percentageCompletion) {}
			},
			function(/*Range | Range[]*/ range) {
				this.compute = function(pct) {
					var results;
					var num;

					if (range.constructor == Array) {
						results = [];
						for (var i = 0; i < range.length; i++) {
							num = (pct.constructor == Array) ? pct[i] : pct;
							results.push(range[i].start + (range[i].diff * num));
						}
						return results;
					} else {
						return range.start + range.diff * pct;
					}
				}
			}
		);
		// ****** Enum Transition ******
		var EnumTransition = extend(Transition,
			function(/*Enum*/ enumeration) {
				var _items = enumeration.items;
				this.compute = function(pct) {
					var pos = parseInt(pct * _items.length);

					for (var i = pos; i >= 0; i--) {
						if (_items[i] && _items[i].name) {
							return _items[i].name;
						}
					}

					return undefined;
				}
			}
		);
		// ****** Color Transition ******
		var ColorTransition = extend(Transition,
			function(startColor, endColor) {
				var _ranges = [];
				var _super = {};

				for (var i = 0; i < 3; i++) {
					_ranges.push(getRange(i));
				}

				Transition.call(this, _ranges);
				_super.compute = this.compute;

				function getRange(index) {
					var start = getColor(startColor, index);
					var end = getColor(endColor, index);
					return new Range(start, end);
				}
				function getColor(color, index) {
					var hexStr;
					var pos = color.indexOf('#') + 1;

					// TODO: handle rgb() and int[] color definitions
					if (color.length - pos == 6) {
						pos = pos + index * 2;
						hexStr = color.substring(pos, pos + 2);
					} else {
						pos = pos + index;
						hexStr = color.substring(pos, pos + 1);
						hexStr += hexStr;
					}

					return parseInt(hexStr, 16);
				}

				this.compute = function(pct) {
					var parts = _super.compute(pct);
					var color = '#';

					for (var i = 0; i < parts.length; i++) {
						part = Math.round(parts[i]).toString(16);
						color += (part.length == 2) ? part : '0' + part;
					}
					return color.toLowerCase();
				}
			}
		);

		// ****** Moderator ******
		// Crops the value between 0 and 1
		var Moderator = function(/*int = 10^3*/ prec) {
			this.prec = prec || 10000;
			this.transform = function(/*int | int[]*/ num) {
				return Math.round(Math.max(Math.min(num, 1), 0) * this.prec) / this.prec;
			}
		};
		// ****** Sine Moderator ******
		var CosModerator = extend(Moderator,
			function(/*degrees = 0*/ start, /*degrees = 360*/ period, /*int=1*/ pow, /*float = 1/2*/ alpha, /*lift = 1*/ lift) {
				var _start = Math.PI * (parseFloat(start) || 0) / 180
				var _diff = Math.PI * (parseFloat(period) || 360) / 180
				var _pow = (pow || 1);
				var _alpha = (parseFloat(alpha) || 1/2);
				var _lift = (parseFloat(lift) || 1);
				var _super = {};

				Moderator.call(_super);
				
				this.transform = function(num) {
					var val = Math.cos(_start + num * _diff);
					if (_pow && _pow != 1) {
						if (val > 0) {
							val = Math.pow(val, _pow);
						} else {
							val = -1 * Math.pow((-1 * val), _pow);
						}
					}
					return _super.transform(_alpha * (val + _lift));
				}
			}
		);
		// ****** Theta Moderator ******
		var ThetaModerator = extend(Moderator,
			function(/*0<=int<=1=1*/ transition, /*bool*/ initiallyOn) {
				var _transition = (transition != 0 && !transition) ? 1 : transition;

				Moderator.call(this);
				this.transform = function(num) {
					if (num >= _transition) {
						return (initiallyOn) ? 0 : 1;
					} else {
						return (initiallyOn) ? 1 : 0;
					}
				}
			}
		);

		// ****** Style Updater ******
		var Updater = implement({
				update: function(/*0<=int,=1*/ pct) {}
			},
			function() { }
		);
		var StyleUpdater = extend(Updater,
			function(/*Element | Element[]*/ elms, /*String*/ styleName, /*Transition*/ transition, /*Moderator*/ moderator) {
				var _styleName = fixStyleName(new String(styleName));

				// private
				function fixStyleName(name) {
					var pos;
					var fixedName;

					if ((pos = styleName.indexOf('-')) > 0) {
						fixedName = name.substring(0, pos);
						fixedName += styleName.substring(pos + 1, pos + 2).toUpperCase();
						fixedName += styleName.substring(pos + 2);
						return fixedName;
					} else {
						return name;
					}
				}

				this.elms = elms;
				this.transition = transition;
				this.moderator = moderator || new Moderator();
				this.update = function(pct) {
					var val = this.transition.compute(this.moderator.transform(pct));

					if (elms.constructor == Array) {
						for (var i = 0; i < elms.length; i++) {
							elms[i].style[_styleName] = val;
						}
					} else {
						elms.style[_styleName] = val;
					}

					return _styleName + ':' + val + ';';
				}
			}
		);
		var OpacityUpdater = extend(Updater,
			function(elms, transition, moderator, /*UserAgent*/ agent) {
				var _agent = agent || new UserAgent();
				var _browser = agent.browser;

				function setOpacity(elm, opacity) {
					if (opacity >= .05) {
						elm.style.visibility = 'visible';
						if (_browser == 'MSIE') {
							elm.style.filter = 'alpha(opacity=' + Math.round(100 * opacity) + ')';
						} else {
							elm.style.opacity = opacity;
						}
					} else {
						elm.style.visibility = 'hidden';
					}
				}

				// Public
				this.elms = elms;
				this.transition = transition;
				this.moderator = moderator || new Moderator();
				this.update = function(pct) {
					var elm;
					var opacity = this.transition.compute(this.moderator.transform(pct));

					if (elms.constructor == Array) {
						for (var i = 0; i < elms.length; i++) {
							setOpacity(elms[i], opacity);
						}
					} else {
						setOpacity(elms, opacity);
					}

					return opacity;
				}
			}
		);

		// ****** Animation ******
		var Animation = extend(Cycle,
			function(/*Updater ...*/ updaters) {
				var _super = {};
				var _updaters = Objects.argsOrArray2Array(arguments);

				Cycle.call(this,
					function(cycle) {
						//alert(this.constructor);
						var pct = cycle.counter / cycle.count;

						for (var i = 0; i < _updaters.length; i++) {
							_updaters[i].update(pct);
						}
					}
				)

				_super.start = this.start;
				this.start = function(/*millis*/ period, /*int=0*/ count, /*int=1*/ repeat, /*millis=0*/ wait, /*millis=0*/ timeout) {
					_super.start.call(this, period, count + 1, repeat, wait, timeout);
				}
			}
		);

		// === PACKAGE PUBLIC ===
		this.Range = Range;
		this.Transition = Transition;
		this.ColorTransition = ColorTransition;
		this.EnumTransition = EnumTransition;
		this.Moderator = Moderator;
		this.ThetaModerator = ThetaModerator;
		this.CosModerator = CosModerator;
		this.StyleUpdater = StyleUpdater;
		this.OpacityUpdater = OpacityUpdater;
		this.Animation = Animation;
		// === PACKAGE PUBLIC ===
	}
);










