anim = function() {
	var autoIdInc = 1000,
		timeouts = {},
		timelines = [],
		stopInterval = false;
	
	return {
		add: function(sel,data) {
			timelines.push({ sel: sel, data: data });
		},
		
		start: function() {
			$.each(timelines,function(index,value) {
				var sel = value.sel, 
					el = $(sel).children().eq(0), 
					data = value.data,
					defaultConfig = data['_defaults'];
				
				el.children().data('animConfig',defaultConfig);
				
				$.each(data,function(index,value) {
					if (index.charAt(0) == '#' || index.charAt(0) == '.') {
						el.children(index).data('animConfig',$.extend({},defaultConfig,value));
					}
				});
				
				el.children().each(function(index,el) {
					el = $(el);
					
					if (!el.attr('id').length) {
						el.attr('id',anim.getAutoId());
					}
					
					el.data('elCopy',el.clone());
				});

				anim.initNavigation(el);
				anim.setScreen(el.children().eq(0));
			});
		},
		
		initNavigation: function(el) {
			var screenCount = el.children('li').length,
				prototype = el.siblings('ul.navigation').children('li:first');
			
			if (prototype.length) {
				for (var i=1; i<screenCount; i++) {
					prototype.after(prototype.clone());
				}
			}
			
			el.siblings('ul.navigation').children('li').click(function() {
				var activeScreen = $(this).parent().siblings('ul.screens').children('li.active'),
					activeScreenIndex = activeScreen.index(),
					newIndex = $(this).index();
				
				if (activeScreenIndex == newIndex) {
					return;
				}
				
				if (activeScreen.length) {
					anim.cancelScreen(activeScreen);
				}
				
				anim.setScreen($(this).parent().siblings('ul.screens').children().eq($(this).index()));
			});
		},
		
		cancelScreen: function(screen) {
			var id = screen.get(0).id;
			
			for (var to in timeouts[id]) {
				window.clearTimeout(timeouts[id][to]);
			}
			
			anim.timelineCallback(screen.get(0).id,'break');
		},
		
		setScreen: function(el,repeat) {
			if ($.type(el) === 'string') {
				el = $('#' + el);
			}
			
			var animConfig = el.data('animConfig'),
				newEl = el.data('elCopy'),
				id = newEl.get(0).id;

			if (!repeat) {
				el.siblings('li').removeClass('active');
				el.parent().siblings('ul.navigation').children('li').removeClass('active').eq(el.index()).addClass('active');
			
				el.replaceWith(newEl);
				newEl.addClass('active');
				newEl.data('animConfig',animConfig);
				newEl.data('elCopy',newEl.clone());
			
				anim.timelineCallback(id,'in');
			}

			if ($('body').hasClass('stopAnim')) {
				setTimeout('anim.setScreen("' + el.get(0).id + '",true)',1000);
				return;
			}
			
			timeouts[id] = [];
			for (var key in animConfig) {
				var i = parseInt(key);

				if (i) {
					i = i > 0 ? i : animConfig.duration - Math.abs(i);
					timeouts[id].push(window.setTimeout('anim.timelineCallback("' + id +  '","' + key + '")',i));
				} else if (key == 'out') {
					timeouts[id].push(window.setTimeout('anim.timelineCallback("' + id +  '","' + key + '")',animConfig.duration));
				}
			}
		},
		
		getConfigForEl: function(el) {
			var comment;
			
			try {
				if (el.is('ul')) {
					comment = el.prev('.animscript');
				} else {
					comment = el.children('.animscript');
				}

				if (comment.length) {
					return anim.readConfig(comment);
				} else {
					return {};
				}
			} catch (e) {
				return {};
			}
		},
		
		readConfig: function(el) {
			var lines,
				obj = {};
			
			// console.log(el);
			
			if ($.browser.msie) {
				lines = el.get(0).innerText.split("\n");
			} else {
				lines = el.text().split("\n");
			}
			
			// console.log('matches ' + lines.length);
			// console.log(lines);

			for (l in lines) {
				var idx = lines[l].indexOf(':'),
					key = $.trim(lines[l].substr(0,idx)),
					value = $.trim(lines[l].substr(idx + 1));
				
				if (idx !== false) {
					obj[key] = value;
				}
			}
			
			return obj;
		},
		
		getAutoId: function() {
			return 'auto' + autoIdInc++;
		},
		
		timelineCallback: function(screenId,step) {
			var screen = $('#' + screenId),
				config = screen.data('animConfig');
			
			function fadeIn(sel,dur) {
				sel = sel.length ? screen.find(sel) : screen;
				sel.fadeIn(dur);
			}
			
			function fadeOut(sel,dur) {
				sel = sel.length ? screen.find(sel) : screen;
				sel.fadeOut(dur);
			}
			
			function move(sel,xy,dur,easing) {
				var params = {},
					options = { duration: dur, queue: false };
				
				sel = sel.length ? screen.find(sel) : screen;
				xy = xy.split(',');
				
				if (xy[0].length) {
					params.left = xy[0] + 'px';
				}
				
				if (xy[1].length) {
					params.top = xy[1] + 'px';
				}
				
				if (easing) {
					options.easing = easing;
				}
				
				sel.animate(params,options);
			}
			
			function moveFrom(sel,xy,dur,easing) {
				var selNode = sel.length ? screen.find(sel) : screen,
					toPos = selNode.position(),
					fromPos = toPos;
				
				xy = xy.split(',');
				
				if (xy[0].length) {
					fromPos.left = xy[0];
				}
				
				if (xy[1].length) {
					fromPos.top = xy[1];
				}
				
				selNode.position(fromPos);
				move(sel,toPos.left + ',' + toPos.top,dur,easing);
			}
			
			function moveFromTo(sel,xyFrom,xyTo,dur,easing) {
				move(sel,xyFrom,0);
				move(sel,xyTo,dur,easing);
			}
			
			function size(sel,wh,dur,easing) {
				var params = {},
				options = { duration: dur, queue: false };
			
				sel = sel.length ? screen.find(sel) : screen;
				wh = wh.split(',');
				
				if (wh[0].length) {
					params.width = wh[0] + 'px';
				}
				
				if (wh[1].length) {
					params.height = wh[1] + 'px';
				}
				
				if (easing) {
					options.easing = easing;
				}
				
				sel.animate(params,options);
			}
			
			function show(sel,effect,dur,options) {
				sel = sel.length ? screen.find(sel) : screen;
				$(sel).show(effect,dur,options);
			}

			function hide(sel,effect,dur,options) {
				sel = sel.length ? screen.find(sel) : screen;
				$(sel).hide(effect,dur,options);
			}

			function nextScreen(repeat) {
				if (screen.next('li').length) {
					anim.setScreen(screen.next('li'));
				} else if (repeat) {
					anim.setScreen(screen.siblings('li:first'));
				}
			}

			if (config[step]) {
				eval(config[step] + ';');
			}
		}
	};
}();

