/**
 * The Explorer class
 * 
 * @author Karl Shea	kshea@matharts.com
 */
Explorer = function(args) {
	var defaults = {
		roomsId: '#explore-rooms-nav',
		
		containerId: '#explore-dynamic-container',
		wrapperId: '#explore-dynamic-wrapper',
		contentWrapperId: '#explore-content-wrapper',
		dynamicId: '#explore-dynamic',
		navId: '#explore-nav',
		contentId: '#explore-content',
		toggleId: '#explore-content-toggle',
		
		loadedContentId: '#content',
		
		fadeSpeed: 700,
		slideSpeed: 450,
		sectionWaitSpeed: 2000,
		dynamicMinHeight: 226,
		contentPadding: 43,
		toggleClosedSize: 68
	};
	
	$.extend(defaults, args);
	
	//
	//	Constants
	//
	
	this._LINKS = null;
	this._CONFIG = defaults;
	
	this._TOGGLE_IMG_OPEN = '/images/common/open.png';
	this._TOGGLE_IMG_CLOSE = '/images/common/close.png';
	
	this._HANDLER_KEY = 'explorer';
}

$.extend(Explorer.prototype, {
	
	/**
	 * Initializes the explorer. Should be called on the window.load event.
	 * 
	 * @param {HashQuery} hashQuery	The HashQuery object to register the change event listener with
	 */
	init: function(hashQuery) {
		// Initialize navigation array and links
		this._initExplorerData();
		
		// Handle the content change event
		$(this._CONFIG.contentId).bind('contentChanged', { explorer: this }, this._contentChanged);
		
		// Handle all events fired on the #gallery-image-caption id
		$('#gallery-image-caption').bind('contentChanged', { explorer: this }, this._contentChanged);
		
		// Register the change event handler with the passed HashQuery object
		var me = this;
		hashQuery.registerEventHandler(this._HANDLER_KEY, function(newVal, oldVal) {
			me._handleChangeEvent(newVal, oldVal, hashQuery);
		});
		
		// Show the current hash's content
		this._handleChangeEvent(HashQuery.valueFor(this._HANDLER_KEY), '', hashQuery);
	},
	
	/**
	 * Toggle content
	 * 
	 * @param {Bool} animate
	 */
	toggleContent: function(animate){
		var containerDiv = $(this._CONFIG.containerId);
		var contentDiv = $(this._CONFIG.contentId);
		var navDiv = $(this._CONFIG.navId + ' ul');
		var toggleImage = $('img', $(this._CONFIG.toggleId))[0];
		var closedContainerHeight = this._CONFIG.toggleClosedSize;
		
		if (containerDiv.height() == closedContainerHeight) {
			// Open container
			toggleImage.src = this._TOGGLE_IMG_CLOSE;
			
			var newHeight = $(this._CONFIG.contentId).height() + this._CONFIG.contentPadding;
			var animateHeight = newHeight > this._CONFIG.dynamicMinHeight ? newHeight : this._CONFIG.dynamicMinHeight;
			
			if(animate) {
				contentDiv.find("*").stop();
				containerDiv.stop();
				navDiv.stop();
				
				contentDiv.css("opacity", 1);
				
				contentDiv.find("*").animate({ opacity: 1 }, {
					duration: this._CONFIG.fadeSpeed,
					queue: false
				});
				containerDiv.animate({ height: animateHeight }, {
					duration: this._CONFIG.fadeSpeed,
					queue: false
				});
				navDiv.animate({ opacity: 1 }, {
					duration: this._CONFIG.fadeSpeed,
					queue: false
				});
			}
			else {
				contentDiv.find("*").css('opacity', 1);
				containerDiv.height(animateHeight);
				navDiv.css('opacity', 1);
			}
			
			// Set the first link back to its hash
			var sectionIndexAnchor = $('a:first', this._CONFIG.navId);
			sectionIndexAnchor.attr('href', '#' + this._HANDLER_KEY + '=' + sectionIndexAnchor.attr('name'));
		}
		else {
			// Close container
			toggleImage.src = this._TOGGLE_IMG_OPEN;
			
			if(animate) {
				contentDiv.find("*").stop();
				containerDiv.stop();
				navDiv.stop();
				
				contentDiv.find("*").animate({ opacity: 0 }, {
					duration: this._CONFIG.fadeSpeed,
					queue: false
				});
				containerDiv.animate({ height: closedContainerHeight }, {
					duration: this._CONFIG.fadeSpeed,
					queue: false
				});
				navDiv.animate({ opacity: 0 }, {
					duration: this._CONFIG.fadeSpeed,
					queue: false
				});
			}
			else {
				contentDiv.find("*").css('opacity', 0);
				containerDiv.height(closedContainerHeight);
				navDiv.css('opacity', 0);
			}
			
			// Override the first link with toggleContent()
			$('a:first', this._CONFIG.navId).attr('href', $('a', this._CONFIG.toggleId).attr('href'));
		}
	},
	
	/**
	 * Handle the hash change event
	 * 
	 * @param {String} currentHash
	 * @param {String} previousHash
	 * @param {HashQuery} hashQuery
	 */
	_handleChangeEvent: function(currentHash, previousHash, hashQuery) {
		// Hide the container if there is no room specified
		var container = $(this._CONFIG.containerId);
		var content = $(this._CONFIG.contentId);
		
		if(!currentHash || currentHash == '') {
			var me = this;
			
			container.stop();
			container.animate({ opacity: 0 }, {
				duration: me._CONFIG.fadeSpeed,
				queue: false,
				complete: function() {
					container.hide();
					container.css('height', '1px');
				}
			});
			content.html('');
		}
		
		if(currentHash == previousHash || !currentHash) return;
		
		var newHashSplit = currentHash.split('/');
		var oldHashSplit = previousHash ? previousHash.split('/') : '';
		
		var newMain = newHashSplit[0] != null ? newHashSplit[0] : '';
		var newSub = newHashSplit[1] != null ? newHashSplit[1] : '';
		var oldMain = oldHashSplit[0] != null ? oldHashSplit[0] : '';
		var oldSub = oldHashSplit[1] != null ? oldHashSplit[1] : '';
		
		// Load the navigation if the main section changed
		if(newMain != oldMain) {
			this._handleNavLoad(newMain);
		}
	
		// Remove event handlers for any gallery objects
		hashQuery.unregisterEvents('gallery');
	
		// Handle section change
		var section = newMain + (newSub == '' ? '' : '/' + newSub);
		this._handleSectionChange(section, newMain != oldMain && newSub == '');
	},
	
	/**
	 * Initialize the explorer navigation array and links
	 */
	_initExplorerData: function() {
		this._LINKS = new Array();
		
		var me = this;
		
		// Save all link paths in an array, and set the link href to the anchor name
		$('a', $(this._CONFIG.roomsId)).each(function(i) {
			me._LINKS[$(this).attr('name')] = $(this).attr('href');
		});
	},
	
	/**
	 * Handles loading navigation
	 * 
	 * @param {String} section
	 */
	_handleNavLoad: function(section) {
		// Fetch the hidden room content and insert it for navigation	

		var roomNav = $('#room-' + section).html();
		var dynamicNav = $(this._CONFIG.navId);
		dynamicNav.html(roomNav);
		
		var me = this;
		
		// Init links
		$('a', dynamicNav).each(function(i) {
			$(this).attr('href', '#' + me._HANDLER_KEY + '=' + $(this).attr('name'));
		});
		
		// Override the first link with toggleContent()
		$('a:first', dynamicNav).attr('href', $('a', this._CONFIG.toggleId).attr('href'));
	},
	
	/**
	 * Handles the main section change
	 * 
	 * @param {String} section
	 * @param {Bool} newMainSection
	 */
	_handleSectionChange: function(section, newMainSection) {
		var me = this;
		
		// Load the section data
		$.get(this._LINKS[section], function(data) {
				me._handleData(data, newMainSection); 
			});
		
		// Highlight current link
		$('ul a', $(this._CONFIG.navId)).each(function(i) {
			if($(this).attr('name') == section) {
				$(this).addClass('active')
			} else {
				$(this).removeClass('active');
			}
		});
	},
	
	/**
	 * Handles sub data changes
	 * 
	 * @param {String} data
	 * @param {Bool} newMainSection
	 */
	_handleData: function(data, newMainSection) {
		var parsedData = $(data);
		var containerDiv = $(this._CONFIG.containerId);
		var contentDiv = $(this._CONFIG.contentId);
		var me = this;
		
		contentDiv.stop();
		contentDiv.animate({ opacity: 0 }, {
			duration: this._CONFIG.fadeSpeed,
			queue: false,
			complete: function() {
				contentDiv.html(parsedData.filter(me._CONFIG.loadedContentId));
				
				if(!newMainSection) {
					contentDiv.animate({
						opacity: 1
					}, {
						duration: me._CONFIG.fadeSpeed,
						queue: false
					});
				}
				else {
					containerDiv.stop();
					containerDiv.show();
					
					setTimeout(function() {
						containerDiv.animate({ opacity: 1 }, {
							duration: me._CONFIG.fadeSpeed,
							queue: false
						});
					}, me._CONFIG.sectionWaitSpeed);
				}
				
				// Trigger content div changed event to resize container
				contentDiv.trigger('contentChanged', newMainSection);
			}
		});
	},
	
	/**
	 * Handle the content changing and resize the container
	 * 
	 * @param {Event} event
	 */
	_contentChanged: function(event, newMainSection) {
		// Pull explorer instance out of event data object
		var me = event.data.explorer;
		
		var containerDiv = $(me._CONFIG.containerId);
		var contentDiv = $(me._CONFIG.contentId);
		
		var currHeight = containerDiv.height();
		
		if(newMainSection) {
			// Close the container box if the main section changed
			explorer.toggleContent(false);
		}
		else {
			// Animate the container box to fit the content any other time
			var newHeight = contentDiv.height() + me._CONFIG.contentPadding;
			var animateHeight = newHeight > me._CONFIG.dynamicMinHeight ? newHeight : me._CONFIG.dynamicMinHeight;
			
			containerDiv.stop();
			
			containerDiv.animate({
				height: animateHeight
			}, {
//				duration: me._CONFIG.fadeSpeed,
				duration: 0,
				queue: false
			});
		}
	}

});
