(function($) {

	/*---------------------------------------------------------------------
	 * CONSTANTS
	 *--------------------------------------------------------------------*/

	$.daniel = $.daniel || {};
	$.daniel.sitemanager = {};

	/*---------------------------------------------------------------------
	 * END OF CONSTANTS
	 *--------------------------------------------------------------------*/

	/*---------------------------------------------------------------------
	 * CLASSES
	 *--------------------------------------------------------------------*/

	/**
	 * Component used to manage the Daniel Photography Site, providing simple
	 * tools for organizing the menu tree as well as general public API to help
	 * around the site's interaction with the user.
	 * 
	 * <p>
	 * There must be is no in-line JavaScript within any of the web site pages
	 * besides the startup command.
	 * </p>
	 * 
	 * @class
	 * @name SiteManager
	 */
	function SiteManager(instance, conf) {

		var self = this;

		var instance = instance;

		var conf = conf;

		/*---------------------------------------------------------------------
		 * UTILITY METHODS
		 *--------------------------------------------------------------------*/

		var init = function() {

			conf.viewers = instance.find(".multi-viewer");
			conf.viewers.each(function() {
				var viewer = $(this);
				if (viewer.width() > 0) {
					viewer.data("loaded", true);
				}
			});
			conf.photoIndices = instance.find(".photo-index");
			conf.viewer = instance.find(".viewer");
			conf.previewer = instance.find(".previewer");
			conf.imageWrapper = instance.find(".image-wrapper");
			conf.controlsWrapper = instance.find(".controls-wrapper");
			conf.caption = instance.find("#caption p");
			conf.left = conf.controlsWrapper.find(".left");
			conf.right = conf.controlsWrapper.find(".right");

			conf.prevArrow = instance.find(".leftarrow");
			conf.nextArrow = instance.find(".rightarrow");

			conf.left.trackMouseDown();
			conf.right.trackMouseDown();

			if (!conf.prevArrow.parent().is("a")) {
				conf.prevArrow.wrap("<a />");
			}
			if (!conf.nextArrow.parent().is("a")) {
				conf.nextArrow.wrap("<a />");
			}

			if (conf.photos) {

				var photos = getPhotos();

				// start loading them
				photos.show();
				photos.hide();

				var photo = getPhoto(window.location.hash.substring(1), "slug");

				if (photo) {

					showPhoto(photo, false);

				} else {

					showPhoto(getPhoto(), false);
				}

			} else {

				conf.viewer.fadeTo(1000, 1);
			}

			initHandlers();

			postInit();
		};

		var postInit = function() {

			instance.find(".player .video").each(function() {

				var video = $(this);

				video.flowplayer(false, true);
			});

			conf.submenus = instance.find(".menu .sub-menu");
			conf.selected = conf.submenus.find(".selected");

			conf.animate = conf.selected.length == 0;

			conf.submenus.each(function() {

				var sub = $(this);
				var link = sub.prev();

				link.click(function() {

					if (sub.is(":visible")) {

						sub.slideUp();

					} else {

						if (conf.animate) {

							conf.submenus.slideUp();
							sub.slideDown();

						} else {

							conf.submenus.hide();
							sub.show();
						}
					}

					conf.animate = true;
				});
			});

			/*
			 * open selected item
			 */
			conf.selected.parent().prev().click();
		};

		var initHandlers = function() {

			conf.prevArrow.parent().click(prevPhotoClickHandler);
			conf.nextArrow.parent().click(nextPhotoClickHandler);

			conf.left.click(leftClickHandler);
			conf.right.click(rightClickHandler);

			if (conf.photos) {
				conf.photoIndices.click(photoIndexClickHandler);
			}

			conf.viewers.click(viewersClickHandler);
			conf.viewers.load(viewersLoadHandler);

			// var previewables = instance.find(".preview-enabled[data-url]");
			//
			// previewables.mouseover(previewEnabledMouseOverHandler);
			// previewables.mouseout(previewEnabledMouseOutHandler);
		};

		var getPhoto = function(url, field) {

			if (typeof url == "undefined") {
				url = getSelectedPhoto().attr("src");
			}

			if (url) {

				url = url.replace(conf.mediaUrl, "");
				field = field || "url";

				for ( var i = 0; i < conf.photos.length; i++) {

					var photo = conf.photos[i];

					if (url == photo[field]) {

						return photo;
					}
				}
			}

			return null;
		};

		var getPhotos = function() {

			return conf.imageWrapper.find("img");
		};

		var getSelectedPhoto = function() {

			return conf.imageWrapper.find("img.selected");
		};

		var renderControls = function() {

			var photo = getSelectedPhoto();

			conf.controlsWrapper.height(photo.height());
			conf.controlsWrapper.width(photo.width());

			conf.controlsWrapper.center(true, false);
		};

		var showPhoto = function(photo, fade) {

			if (photo instanceof jQuery) {

				if (!conf.previousPhoto
						|| photo.height() != conf.previousPhoto.height()) {

					conf.imageWrapper.height(photo.height());
				}

				photo.center(true, false);

				// photo.show();
				photo.fadeIn(1000, function() {

					photo.center(true, false);

					renderControls();
				});

				return;
			}

			if (!photo) {
				return;
			}

			var url = conf.mediaUrl + photo.url;
			var index = conf.photos.indexOf(photo);
			var position = $.daniel.utils.pad(index + 1);
			var last = conf.photos.length == (index + 1);

			var photos = getPhotos();

			var current = getSelectedPhoto();
			var next = photos.filter("[src=" + url + "]");
			var photoIndex = conf.photoIndices.filter("[data-url=" + url + "]");

			if (current.get(0) != next.get(0)) {

				/*
				 * move next photo before the current one so we can show the
				 * correct fading effect
				 */
				if (current.length == 1) {
					next.insertBefore(current);
				}

				current.removeClass("selected");
				current.fadeOut(1000);

				conf.previousPhoto = current;
			}

			conf.photoIndices.removeClass("selected");
			photoIndex.addClass("selected");
			next.addClass("selected");

			if (next.data("loaded")) {

				showPhoto(next);
			}

			// conf.viewer.attr("src", url);
			// conf.viewer.attr("title", photo.description);
			// conf.viewer.attr("alt", photo.tags);
			conf.caption.html(photo.title);
			// conf.prevArrow.html(position);

			window.location.hash = photo.slug;

			conf.prevArrow.toggleClass("enabled", index > 0);
			conf.nextArrow.toggleClass("enabled", conf.photos.length > 1
					&& !last);
		};

		// --------------------
		// handlers
		// --------------------

		var prevPhotoClickHandler = function() {

			var link = $(this);

			if (conf.photos) {

				self.previousPhoto();

			} else if (link.attr("href")) {

				conf.viewer.fadeTo(1000, 0, function() {

					window.location.href = link.attr("href");
				});
			}

			return false;
		};

		var nextPhotoClickHandler = function() {

			var link = $(this);

			if (conf.photos) {

				self.nextPhoto();

			} else if (link.attr("href")) {

				conf.viewer.fadeTo(1000, 0, function() {

					window.location.href = link.attr("href");
				});
			}

			return false;
		};

		var leftClickHandler = function() {

			self.previousPhoto();
		};

		var rightClickHandler = function() {

			self.nextPhoto();
		};

		var photoIndexClickHandler = function() {

			var link = $(this);
			var index = parseInt(link.attr("data-index")) - 1;
			var photo = conf.photos[index];

			showPhoto(photo);

			return false;
		};

		var viewersClickHandler = function() {

			if (conf.photos) {

				self.nextPhoto();

				return false;
			}
		};

		var viewersLoadHandler = function() {

			var viewer = $(this);

			// mark as loaded
			viewer.data("loaded", true);

			if (viewer.is(".selected")) {

				showPhoto(viewer);
			}
		};

		var previewEnabledMouseOverHandler = function() {

			var link = $(this);

			var url = link.attr("data-url");

			self.openPreview(url);
		};

		var previewEnabledMouseOutHandler = function() {

			self.cancelPreview();
		};

		/*---------------------------------------------------------------------
		 * END OF UTILITY METHODS
		 *--------------------------------------------------------------------*/

		/*---------------------------------------------------------------------
		 * METHODS
		 *--------------------------------------------------------------------*/

		var methods = /** @lends SiteManager.prototype */
		{

			isMenuOpened : function() {

				return conf.selected.is(":visible");
			},
			nextPhoto : function() {

				if (!self.isMenuOpened()) {
					return;
				}

				var current = getPhoto();
				var index = conf.photos.indexOf(current) + 1;

				if (index < conf.photos.length) {

					showPhoto(conf.photos[index]);
				}
			},

			previousPhoto : function() {

				if (!self.isMenuOpened()) {
					return;
				}

				var current = getPhoto();
				var index = conf.photos.indexOf(current) - 1;

				if (index >= 0) {

					showPhoto(conf.photos[index]);
				}
			},

			openPreview : function(url) {

				conf.previewer.attr("src", url);
				conf.previewer.show();

				getSelectedPhoto().hide();
			},

			cancelPreview : function() {

				var selectedPhoto = getSelectedPhoto();

				conf.previewer.hide();

				selectedPhoto.show();

				conf.imageWrapper.height(selectedPhoto.height());
			}

		};

		/*
		 * publish public methods to the class scope
		 */
		$.extend(this, methods);

		/*---------------------------------------------------------------------
		 * END OF METHODS
		 *--------------------------------------------------------------------*/

		init();
	}

	/*---------------------------------------------------------------------
	 * END OF CLASSES
	 *--------------------------------------------------------------------*/

	/*---------------------------------------------------------------------
	 * JQUERY PLUGINS
	 *--------------------------------------------------------------------*/

	/**
	 * jQuery plugin that exposes the SiteManager class to a jQuery object
	 * 
	 * @param conf
	 *            the initial configuration object used to create the
	 *            sitemanager
	 */
	$.fn.sitemanager = function(conf) {

		this.each(function() {

			var instance = $(this);

			var sitemanager = instance.data("sitemanager");

			if (!sitemanager) {

				var data = $.extend({}, $.daniel.sitemanager, conf || {});

				sitemanager = new SiteManager(instance, data);

				instance.data("sitemanager", sitemanager);
			}
		});

		var index = typeof conf == "number" ? conf : 0;

		return this.eq(index).data("sitemanager");
	};

	/*---------------------------------------------------------------------
	 * END OF JQUERY PLUGINS
	 *--------------------------------------------------------------------*/

})(jQuery);

