﻿/// <reference path="jquery-1.3.2.js" />
$.factory.create({

	stageLoader: function(url, puppets, callback) {
		var 
		MIN_INTERVAL = 200,
		MAX_INTERVAL = 450,
		ROLL_SPEED = 450
		;

		var 
		self = this,
		$ = window.$,
		_queue = [],
		_suspended = false,
		_agenda,
		_performed = 0,

		load = function(puppet) {
			$('<img />')
				.attr('src', puppet.source)
				.load(function() {
					enqueue(puppet);
				})
				;
		},

		suspend = function(interval) {
			if (typeof interval === 'undefined' || interval < MIN_INTERVAL || interval > MAX_INTERVAL)
				interval = Math.random() * (MAX_INTERVAL - MIN_INTERVAL) + MIN_INTERVAL;

			_suspended = true;

			setTimeout(function() {
				_suspended = false;
				_queue.length && dequeue();
			}, interval);
		},

		enqueue = function(puppet) {
			_queue.push(puppet);
			dequeue();
		},

		dequeue = function() {
			if (_queue.length === 0 || _suspended)
				return;

			debut(_queue.shift());
			
			_agenda === ++_performed
				? ($.isFunction(callback) && callback(puppets))
				: suspend()
				;
		},

		debut = function(puppet) {
			var styles = {
				backgroundImage: 'url(' + puppet.source + ')',
				opacity: 0,
				display: 'block',
				left: (puppet.position - puppet.dispersal * puppet.direction) + '%'
			};

			if ($.browser.msie && +$.browser.version === 7)
				delete styles.opacity;

			puppet.css(styles);
			$.fn.fixpng && puppet.fixpng();

			var animation = { left: puppet.position + '%', opacity: 1 };

			if ($.browser.msie && +$.browser.version === 7)
				delete animation.opacity;

			puppet.animate(animation, ROLL_SPEED);
		}

		;

		// ctor
		_agenda = puppets.length;

		for (var i = _agenda; i--; ) {
			var puppet = puppets[i];
			var id = puppet.id;
			
			puppet.source = url.replace('{id}', id);
			load(puppet);
		};

		suspend();
		return self;
	},

	puppeteer: function(puppets, scenes, triggers) {
		var 
		FADE = .3,
		ROLL_SPEED = 450,
		STAGE_DELAY = 900
		;

		var
		self = this,
		$ = window.$,
		_puppets = {},
		_hero,
		_timeout,

		attach = function(trigger, scene, hero) {
			trigger.mouseover(function() {
				_hero === hero ? clear() : stage(scene, _hero = hero);
			});

			trigger.mouseout(revert);
		},

		stage = function(scene, hero) {
			clear();

			for (var puppetID in scene) {
				var puppet = _puppets[puppetID],
					attitude = scene[puppetID];

				if (typeof puppet === 'undefined')
					continue;

				var animation = {
					left: attitude.position + '%',
					opacity: typeof hero === 'undefined' || hero === puppetID ? 1 : FADE
				};

				if ($.browser.msie && +$.browser.version === 7)
					delete animation.opacity;
				
				puppet.stop().animate(animation, ROLL_SPEED);
			}
		},

		revert = function() {
			clear();

			_timeout = setTimeout(function() {
				stage(_puppets); /* initial scene */
				_hero = 0;
			}, STAGE_DELAY);
		},

		clear = function() {
			_timeout && (_timeout = clearTimeout(_timeout));
		}

		;

		// ctor
		for (var i = puppets.length; i--; ) {
			var puppet = puppets[i];
			_puppets[puppet.id] = puppet;
		}

		for (var id in scenes)
			triggers[id] && attach(triggers[id], scenes[id], id);

		return self;
	}

});
