//
//
//
(function($) {

	//
	//
	//
	$.fn.fatbox = function(options, callback)
	{
		//
		//
		//
		var $caller = null;

		//
		//
		//
		var groups = {};

		//
		//
		//
		var settings = jQuery.extend(true, {}, $.fn.fatbox.defaultSettings, options);

		//
		//
		//
		function __initialize(event)
		{
			event.preventDefault();
			event.stopPropagation();

			var $target = $(event.target);
			$caller = ($target.get(0).nodeName.toLowerCase() == 'a')
				? $target
				: $target.parents('a');

			FatBox.initialize($caller);
			return false;
		};

		//
		//
		//
		var FatBox = {

			//
			//
			//
			initialize: function($caller)
			{
				FatboxEvent.processEvent(
					'initialize',
					{
						fatbox: this,
						caller: $caller
					},
					this.performInitialization
				);
			},

			//
			//
			//
			performInitialization: function(parameter)
			{
				FatboxEvent.processEvent('initialized', parameter, parameter.fatbox.open);
			},

			//
			//
			//
			open: function(parameter)
			{
				FatboxEvent.processEvent('open', parameter, parameter.fatbox.performOpening);
			},

			//
			//
			//
			performOpening: function(parameter)
			{
				FatboxEvent.processEvent('opened', parameter, parameter.fatbox.load);
			},

			//
			//
			//
			load: function(parameter)
			{
				FatboxEvent.processEvent('load', parameter, parameter.fatbox.performLoading);
			},

			//
			//
			//
			performLoading: function(parameter)
			{
				settings.media.loader['image'](
					'image',
					parameter.caller,
					parameter.fatbox.loadingPerformed,
					parameter
				);
			},

			//
			//
			//
			loadingPerformed: function(parameter)
			{
				FatboxEvent.processEvent('loaded', parameter, parameter.fatbox.animate);
			},

			//
			//
			//
			animate: function(parameter)
			{
				var dimension = {
					width: (parameter.width || 200) + $.fn.fatbox.globals.stage.padding * 2,
					height: (parameter.height || 200) + $.fn.fatbox.globals.stage.padding * 2
				};

				jQuery.extend(
					parameter,
					dimension,
					$.fn.fatbox.utils.getCenteredPosition(dimension),
					{
						animationTargets: []
					}
				);

				FatboxEvent.processEvent('animate', parameter, parameter.fatbox.performAnimation);
			},

			//
			//
			//
			performAnimation: function(parameter)
			{
				$.fn.fatbox.animation.processAnimationTargets(
					parameter.animationTargets,
					parameter.fatbox.animationPerformed,
					{
						caller: parameter.caller,
						fatbox: parameter.fatbox
					}
				);
			},

			//
			//
			//
			animationPerformed: function(parameter)
			{
				FatboxEvent.processEvent('animated', parameter);
			},

			//
			//
			//
			close: function(parameter)
			{
				FatboxEvent.processEvent('close', parameter, parameter.fatbox.performClosing);
			},

			//
			//
			//
			performClosing: function(parameter)
			{
				FatboxEvent.processEvent('closed', parameter);
			}
		};

		//
		//
		//
		var FatboxEvent = {

			//
			//
			//
			events: {
				initialize: null,
				initialized: null,
				open: null,
				opened: null,
				load: null,
				loaded: null,
				animate: null,
				animated: null,
				close: null,
				closed: null
			},

			//
			//
			//
			registerHook: function(event, hook)
			{
				if ('object' != typeof(this.events[event]))
				{
					$.fn.fatbox.utils.log('Unknown event "' +event+ '"');
					return;
				};
				try
				{
					this.events[event].hooks.push(hook);
				}
				catch (exc)
				{
					this.events[event] = {
						hooks: [hook]
					};
				};
				$.fn.fatbox.utils.log('Hook registered for event "' +event+ '"');
			},

			//
			//
			//
			processEvent: function(event, parameter, callback)
			{
				$.fn.fatbox.utils.log('Processing event "' +event+ '"');
				if (this.events[event] == null)
				{
					$.fn.fatbox.utils.log('No hooks registered for event "' +event+ '"');
					$.fn.fatbox.utils.log('Finished processing event "' +event+ '"');
					if (callback != undefined)
					{
						callback(parameter);
					};
					return;
				}

				this.events[event] = jQuery.extend(
					this.events[event],
					{
						callback: callback,
						parameter: parameter
					}
				);
				this.processEventHook(event, 0);
			},

			//
			//
			//
			processEventHook: function(event, index)
			{
				$.fn.fatbox.utils.log(
					'Processing hook #' +index+ ' for event "' +event+ '"'
				);
				this.events[event].index = index;
				this.events[event].hooks[index](
					this.events[event].parameter,
					event,
					this.processEventHookResponse
				);
			},

			//
			//
			//
			processEventHookResponse: function(event, parameter)
			{
				var index = FatboxEvent.events[event].index;
				$.fn.fatbox.utils.log(
					'Processing hook #' +index+ ' response for event "' +event+ '"'
				);
				index++;
				if (index < FatboxEvent.events[event].hooks.length)
				{
					FatboxEvent.processEventHook(event, index);
				}
				else if (FatboxEvent.events[event].callback != undefined)
				{
					FatboxEvent.events[event].callback(FatboxEvent.events[event].parameter);
				};
			}
		};

		//
		//
		//
		$.fn.fatbox.utils.log('Register custom event hooks');
		for (var event in callback)
		{
			for (var i=0 ; i<callback[event].length ; i++)
			{
				FatboxEvent.registerHook(event, callback[event][i]);
			};
		};

		//
		//
		//
		$.fn.fatbox.utils.log('Register default event hooks');
		FatboxEvent.registerHook('initialize', $.fn.fatbox.veil.build);
		FatboxEvent.registerHook('initialize', $.fn.fatbox.stage.build);
		FatboxEvent.registerHook('initialize', $.fn.fatbox.shadow.build);
		FatboxEvent.registerHook('initialize', $.fn.fatbox.control.build);

		FatboxEvent.registerHook('open', $.fn.fatbox.veil.show);
		FatboxEvent.registerHook('open', $.fn.fatbox.stage.show);
		FatboxEvent.registerHook('open', $.fn.fatbox.shadow.show);

		FatboxEvent.registerHook('animate', $.fn.fatbox.stage.addAnimationTarget);
		FatboxEvent.registerHook('animate', $.fn.fatbox.shadow.addAnimationTarget);

		FatboxEvent.registerHook('animated', $.fn.fatbox.control.showClose);
		FatboxEvent.registerHook('animated', $.fn.fatbox.shadow.fixBackground);
		FatboxEvent.registerHook('animated', $.fn.fatbox.stage.showContent);

		FatboxEvent.registerHook('close', $.fn.fatbox.control.hide);
		FatboxEvent.registerHook('close', $.fn.fatbox.shadow.hideBackground);
		FatboxEvent.registerHook('close', $.fn.fatbox.shadow.hide);
		FatboxEvent.registerHook('close', $.fn.fatbox.stage.hide);
		FatboxEvent.registerHook('close', $.fn.fatbox.veil.hide);

		FatboxEvent.registerHook('closed', $.fn.fatbox.stage.hideContent);

		//
		//
		//
		$.fn.fatbox.utils.log('Initialize items');
		return this.each(
			function(index)
			{
				$(this).bind('click', __initialize);
			}
		);
	};



	//
	//
	//
	$.fn.fatbox.stage = {

		//
		//
		//
		element: null,

		//
		//
		//
		build: function(parameter, event, notify)
		{
			if ($.fn.fatbox.stage.element == null)
			{
				$('body').append(
					'<div id="fatbox-stage">' +
						'<div id="fatbox-content"></div>' +
					'</div>'
				);
				$.fn.fatbox.stage.element = $('#fatbox-stage');
				$.fn.fatbox.stage.element.hide();
				$.fn.fatbox.utils.log('Stage built');
			};
			notify(event, parameter);
		},

		//
		//
		//
		reset: function()
		{
			var dimension = {
				width: $.fn.fatbox.globals.stage.width,
				height: $.fn.fatbox.globals.stage.height
			};
			$.fn.fatbox.stage.element
				.show()
				.css(
					jQuery.extend(
						dimension,
						$.fn.fatbox.utils.getCenteredPosition(dimension),
						{
							opacity: 0
						}
					)
				);
			$.fn.fatbox.utils.log('Stage reset');
		},

		//
		//
		//
		show: function(parameter, event, notify)
		{
			$.fn.fatbox.stage.reset();
			var dimension = {
				width: $.fn.fatbox.globals.stage.width,
				height: $.fn.fatbox.globals.stage.height
			};
			$.fn.fatbox.stage.element
				.fadeTo(
					$.fn.fatbox.globals.animation.speed,
					1,
					function()
					{
						$.fn.fatbox.utils.log('Stage visible');
						notify(event, parameter);
					}
				);
		},

		//
		//
		//
		addAnimationTarget: function(parameter, event, notify)
		{
			parameter.animationTargets.push(
				{
					element: $.fn.fatbox.stage.element,
					settings: jQuery.extend(
						{},
						parameter,
						{
							top: parameter.top,
							left: parameter.left,
							width: parameter.width,
							height: parameter.height,
							animations: [
								$.fn.fatbox.animation.horizontal,
								$.fn.fatbox.animation.vertical
							]
						}
					)
				}
			);
			notify(event, parameter);
		},

		//
		//
		//
		hide: function(parameter, event, notify)
		{
			
			$.fn.fatbox.stage.element.fadeTo(
				$.fn.fatbox.globals.animation.speed,
				0,
				function()
				{
					$.fn.fatbox.stage.element.hide();
					$.fn.fatbox.utils.log('Stage hidden');
					notify(event, parameter);
				}
			);
		},

		//
		//
		//
		showContent: function(parameter, event, notify)
		{
			var width = $.fn.fatbox.stage.element.width() - $.fn.fatbox.globals.stage.padding * 2,
				height = $.fn.fatbox.stage.element.height() - $.fn.fatbox.globals.stage.padding * 2;

			$('#fatbox-content')
				.hide()
				.css(
					{
						top: $.fn.fatbox.globals.stage.padding,
						left: $.fn.fatbox.globals.stage.padding,
						width: width,
						height: height,
						visibility: 'visible'
					}
				)
				.fadeIn(
					$.fn.fatbox.globals.animation.speed,
					function()
					{
						$.fn.fatbox.utils.log('Stage content visible');
						notify(event, parameter);
					}
				);
		},

		//
		//
		//
		hideContent: function(parameter, event, notify)
		{
			$('#fatbox-content').fadeOut(
				1,
				function()
				{
					$('#fatbox-image').hide();
					$(this)
						.css(
							{
								visibility: 'hidden'
							}
						)
						.show();
					$.fn.fatbox.utils.log('Stage content hidden');
					notify(event, parameter);
				}
			);
		}
	};

	//
	//
	//
	$.fn.fatbox.shadow = {

		//
		//
		//
		element: null,

		//
		//
		//
		build: function(parameter, event, notify)
		{
			if ($.fn.fatbox.shadow.element == null)
			{
				$('body').append(
					'<div id="fatbox-shadow">' +
						'<div id="fatbox-shadow-background"></div>' +
					'</div>'
				);
				$.fn.fatbox.shadow.element = $('#fatbox-shadow');
				$.fn.fatbox.shadow.element.hide();

				var i,
					edges = ['n','e','s','w'],
					corners = ['ne','se','sw','nw'];

				for (i=0 ; i<edges.length ; i++)
				{
					$.fn.fatbox.shadow.element.append(
						'<div class="fatbox-shadow-' +edges[i]+ '">' +
							'<img src="' +$.fn.fatbox.globals.path.gfx+ '/shadow-' +edges[i]+ '.png" />' +
						'</div>'
					);
				}
				for (i=0 ; i<corners.length ; i++)
				{
					$.fn.fatbox.shadow.element.append(
						'<img' +
							' class="fatbox-shadow-' +corners[i]+ '"' +
							' src="' +$.fn.fatbox.globals.path.gfx+ '/shadow-' +corners[i]+ '.png" />'
					);
				}
				$.fn.fatbox.shadow.element.find('img').ifixpng();
				$.fn.fatbox.utils.log('Shadow built');
			};
			notify(event, parameter);
		},

		//
		//
		//
		reset: function()
		{
			var dimension = {
				width: $.fn.fatbox.globals.stage.width,
				height: $.fn.fatbox.globals.stage.height
			};
			var properties = jQuery.extend(
				dimension,
				$.fn.fatbox.utils.getCenteredPosition(dimension)
			);
			$.fn.fatbox.shadow.element.css(properties);
			$.fn.fatbox.utils.log('Shadow reset');
		},

		//
		//
		//
		fixBackground: function(parameter, event, notify)
		{
			var properties = {
				top: $.fn.fatbox.globals.stage.padding,
				left: $.fn.fatbox.globals.stage.padding,
				width: $.fn.fatbox.stage.element.width(),
				height: $.fn.fatbox.stage.element.height()
			}
			$('#fatbox-shadow-background')
				.css(properties)
				.show();
			notify(event, parameter);
		},

		//
		//
		//
		prepareAnimation: function(parameter, event, notify)
		{
			notify(event, parameter);
		},
		
		//
		//
		//
		show: function(parameter, event, notify)
		{
			$.fn.fatbox.shadow.reset();
			var dimension = {
				width: $.fn.fatbox.globals.stage.width + $.fn.fatbox.globals.stage.padding * 2,
				height: $.fn.fatbox.globals.stage.height + $.fn.fatbox.globals.stage.padding * 2
			};
			var properties = jQuery.extend(
				dimension,
				$.fn.fatbox.utils.getCenteredPosition(dimension)
			);			
			$.fn.fatbox.shadow.element
				.show()
				.animate(
					properties,
					$.fn.fatbox.globals.animation.speed,
					function()
					{
						$.fn.fatbox.utils.log('Shadow visible');
						notify(event, parameter);
					}
				);
		},

		//
		//
		//
		addAnimationTarget: function(parameter, event, notify)
		{
			parameter.animationTargets.push(
				{
					element: $.fn.fatbox.shadow.element,
					settings: jQuery.extend(
						{},
						parameter,
						{
							top: parameter.top - $.fn.fatbox.globals.stage.padding,
							left: parameter.left - $.fn.fatbox.globals.stage.padding,
							width: parameter.width + $.fn.fatbox.globals.stage.padding * 2,
							height: parameter.height + $.fn.fatbox.globals.stage.padding * 2,
							animations: [
								$.fn.fatbox.animation.horizontal,
								$.fn.fatbox.animation.vertical
							]
						}
					)
				}
			);
			notify(event, parameter);
		},

		//
		//
		//
		hide: function(parameter, event, notify)
		{
			var dimension = {
				width: $.fn.fatbox.shadow.element.width()-20,
				height: $.fn.fatbox.shadow.element.height()-20
			};

			$.fn.fatbox.shadow.element.animate(
				jQuery.extend(
					dimension,
					$.fn.fatbox.utils.getCenteredPosition(dimension)
				),
				$.fn.fatbox.globals.animation.speed,
				function()
				{
					$.fn.fatbox.shadow.element.hide();
					$.fn.fatbox.utils.log('Shadow hidden');
					notify(event, parameter);
				}
			);
		},

		//
		//
		//
		hideBackground: function(parameter, event, notify)
		{
			var dimension = {
				width: $.fn.fatbox.shadow.element.width()-40,
				height: $.fn.fatbox.shadow.element.height()-40
			};

			$('#fatbox-shadow-background').animate(
				dimension,
				100,
				function()
				{
					$('#fatbox-shadow-background').hide();
					notify(event, parameter);
				}
			);

		}
	};

	//
	//
	//
	$.fn.fatbox.veil = {

		//
		//
		//
		element: null,

		//
		//
		//
		build: function(parameter, event, notify)
		{
			if ($.fn.fatbox.veil.element == null)
			{
				$('body').append('<div id="fatbox-veil"></div>');
				$.fn.fatbox.veil.element = $('#fatbox-veil');
				$.fn.fatbox.veil.element.hide();
				$.fn.fatbox.utils.log('Veil built.');
			};
			notify(event, parameter);
		},

		//
		//
		//
		reset: function()
		{
			$.fn.fatbox.veil.element
				.css(
					{
						width: $(document).width(),
						height: $(document).height(),
						opacity: 0
					}
				)
				.show();
			$.fn.fatbox.utils.log('Veil reset');
		},

		//
		//
		//
		show: function(parameter, event, notify)
		{
			$('embed,object').css('visibility', 'hidden');
			$.fn.fatbox.veil.reset();
			$.fn.fatbox.veil.element
				.fadeTo(
					$.fn.fatbox.globals.animation.speed,
					$.fn.fatbox.globals.veil.opacity,
					function()
					{
						$.fn.fatbox.veil.element.one(
							'click',
							function(event)
							{
								parameter.fatbox.close(parameter);
							}
						);
						$.fn.fatbox.utils.log('Veil visible');
						notify(event, parameter);
					}
				);
		},

		//
		//
		//
		hide: function(parameter, event, notify)
		{
			$.fn.fatbox.veil.element.fadeTo(
				$.fn.fatbox.globals.animation.speed,
				0,
				function()
				{
					$.fn.fatbox.veil.element.hide();
					$('embed,object').css('visibility', 'visible');
					$.fn.fatbox.utils.log('Veil hidden');
				}
			);
			notify(event, parameter);
		}
	};

	//
	//
	//
	$.fn.fatbox.media = {

		//
		//
		//
		loadImage: function(imageSource, callback, parameter)
		{
			var image = new Image();
			image.onload = function()
			{
				if ($('#fatbox-image').length == 0)
				{
					$('#fatbox-content').append('<img src="" id="fatbox-image"/>');
				}
				var $image = $('#fatbox-image').show();
				$image.attr('src', imageSource);

				parameter = jQuery.extend(
					parameter,
					{
						width: $image.width(),
						height: $image.height()
					}
				);
				callback(parameter);
			};
			image.src = imageSource;
		},

		//
		//
		//
		loadMediaContent: function(mediaType, $caller, callback, parameter)
		{
			$.fn.fatbox.media.loadImage($caller.attr('href'), callback, parameter);
		}
	};

	//
	//
	//
	$.fn.fatbox.animation = {

		//
		//
		//
		moveTo: function($element, settings, targets, callback, parameter)
		{
			$element.animate(
				{
					top: settings.top,
					left: settings.left
				},
				$.fn.fatbox.globals.animation.speed,
				function()
				{
					$.fn.fatbox.animation.processAnimation(
						$element,
						settings,
						targets,
						callback,
						parameter
					);
				}
			);
		},

		//
		//
		//
		resize: function($element, settings, targets, callback, parameter)
		{
			$element.animate(
				{
					width: settings.width,
					height: settings.height
				},
				$.fn.fatbox.globals.animation.speed,
				function()
				{
					$.fn.fatbox.animation.processAnimation(
						$element,
						settings,
						targets,
						callback,
						parameter
					);
				}
			);
		},

		//
		//
		//
		horizontal: function($element, settings, targets, callback, parameter)
		{
			$element.animate(
				{
					left: settings.left,
					width: settings.width
				},
				$.fn.fatbox.globals.animation.speed,
				function()
				{
					$.fn.fatbox.animation.processAnimation(
						$element,
						settings,
						targets,
						callback,
						parameter
					);
				}
			);
		},

		//
		//
		//
		vertical: function($element, settings, targets, callback, parameter)
		{
			$element.animate(
				{
					top: settings.top,
					height: settings.height
				},
				$.fn.fatbox.globals.animation.speed,
				function()
				{
					$.fn.fatbox.animation.processAnimation(
						$element,
						settings,
						targets,
						callback,
						parameter
					);
				}
			);
		},
		
		//
		//
		//
		processAnimation: function($element, settings, targets, callback, parameter)
		{
			if (settings.animations.length > 0)
			{
				var animation = settings.animations.shift();
				animation($element, settings, targets, callback, parameter);
			}
			else if (callback != undefined)
			{
				$.fn.fatbox.animation.finishedForElement(targets, callback, parameter);
			};
		},

		//
		//
		//
		finishedForElement: function(targets, callback, parameter)
		{
			if (targets.finished != undefined)
			{
				return;
			};
			for (var i=0 ; i<targets.length ; i++)
			{
				if (targets[i].settings.animations.length > 0)
				{
					return;
				}
			};
			targets.finished = true;
			callback(parameter);
		},

		//
		//
		//
		processAnimationTargets: function(targets, callback, parameter)
		{
			for (var i=0 ; i<targets.length ; i++)
			{
				$.fn.fatbox.animation.processAnimation(
					targets[i].element,
					targets[i].settings,
					targets,
					callback,
					parameter
				);
			};
		}
	};

	//
	//
	//
	$.fn.fatbox.control = {

		//
		//
		//
		elements: {},
	
		//
		//
		//
		build: function(parameter, event, notify)
		{
			if ($('#fatbox-close').length == 0)
			{
				$('body').append(
					'<img src="' +$.fn.fatbox.globals.path.gfx+ '/close.png" id="fatbox-close"/>'
				);
				$.fn.fatbox.control.elements.close = $('#fatbox-close');
				$.fn.fatbox.control.elements.close
					.ifixpng()
					.bind(
						'click',
						function(event)
						{
							parameter.fatbox.close(parameter);
						}
					);
				$.fn.fatbox.utils.log('Control "close" built');
			};
			notify(event, parameter);
		},
	
		//
		//
		//
		showClose: function(parameter, event, notify)
		{
			var top = parseInt($.fn.fatbox.stage.element.css('top')),
				left = parseInt($.fn.fatbox.stage.element.css('left')),
				width = $.fn.fatbox.stage.element.width();
	
			$.fn.fatbox.control.elements.close
				.css(
					{
						top: top,
						left: left + width - 22 - $.fn.fatbox.globals.stage.padding
					}
				)
				.show()
				.animate(
					{
						top: top - 18
					},
					$.fn.fatbox.globals.animation.speed,
					function()
					{
						$.fn.fatbox.utils.log('Control "close" visible');
						notify(event, parameter);
					}
				);
		},
	
		//
		//
		//
		hide: function(parameter, event, notify)
		{
			for (var control in $.fn.fatbox.control.elements)
			{
				$.fn.fatbox.control.elements[control].fadeOut($.fn.fatbox.globals.animation.speed);
			}
			notify(event, parameter);
		}
	};


	//
	//
	//
	$.fn.fatbox.globals = {
		debug: {
			verbose: false,
			prefix: 'Fatbox log: '
		},
		path: {
			app: '',
			gfx: '/resources/gfx/fatbox'
		},
		stage: {
			width: 100,
			height: 100,
			padding: 10
		},
		veil: {
			opacity: 0.66
		},
		animation: {
			speed: 400
		}
	};

	//
	//
	//
	$.fn.fatbox.defaultSettings = {
		media: {
			loader: {
				image: $.fn.fatbox.media.loadMediaContent
			}
		}
	};

	//
	//
	//
	$.fn.fatbox.utils = {

		//
		//
		//
		getViewPort: function()
		{
			if ($.browser.opera)
			{
				var width = window.innerWidth,
					height = window.innerHeight;		
			}
			else
			{
				var width = $(window).width(),
					height = $(window).height();
			};
			return {
				width: width,
				height: height,
				offset: this.getScrollingOffset()
			};
		},

		//
		//
		//
		getScrollingOffset: function()
		{
			if (self.pageYOffset)
			{
				var top = self.pageYOffset,
					left = self.pageXOffset;
			}
			else if (document.documentElement && document.documentElement.scrollTop)
			{
				var top = document.documentElement.scrollTop,
					left = document.documentElement.scrollLeft;
			}
			else if (document.body)
			{
				var top = document.body.scrollTop,
					left = document.body.scrollLeft;	
			};
			return {
				top: top,
				left: left
			};
		},

		//
		//
		//
		getCenteredPosition: function(dimension, $element)
		{
			if ($element != undefined)
			{
				var top = $element.css('top'),
					left = $element.css('left'), 
					related = {
						width: $element.width(),
						height: $element.height(),
						offset: {
							top: (top == 'auto' ? 0 : parseInt(top)),
							left: (left == 'auto' ? 0 : parseInt(left))
						}
					};
			}
			else
			{
				var related = $.fn.fatbox.utils.getViewPort();
			};
			return {
				top: related.offset.top + Math.ceil((related.height - dimension.height)/2),
				left: related.offset.left + Math.ceil((related.width - dimension.width)/2)
			};
		},

		//
		//
		//
		log: function(message)
		{
			if ($.fn.fatbox.globals.debug.verbose)
			{
				message = $.fn.fatbox.globals.debug.prefix + message;
				if (window.console && window.console.log)
				{
					window.console.log(message);
				}
				else if (window.status)
				{
					window.status = message;
				};
			}
		}
	};
//
// End of closure
//
})(jQuery);
