/**
 * The RH object handles general page functionality, in particular the registration of, and events on, page content.
 * 
 * @author Cam Morrow
 */
var RH = (function() {

	var content							= {};
	var elements						= {};
	var original_elements				= {};

	/******************************************************
	 * DOM methods
	 *****************************************************/
	
	/**
	 * @private cacheOriginalElements() creates clones of the original core elements so they can be rolled back.
	 * 
	 * @author Cam Morrow
	 */
	var cacheOriginalElements			= function() {
		for (var i in elements) {
			original_elements[i] = elements[i].cloneNode(true);
		}
	};
	
	/**
	 * @private rollbackOriginalElements() replaces (a subset of) the core elements with clones of their original values.
	 * 
	 * @author Cam Morrow
	 * 
	 * @param string	1-n		Arguments are the IDs of the core elements to roll back.
	 */
	var rollbackOriginalElements		= function() {
		$A(arguments).each(function(target_id) {
			if (Object.isElement(elements[target_id])) {
				if (Object.isElement(original_elements[target_id])) {
					
					// Clone a new original
					var clone = original_elements[target_id].cloneNode(true);
					
					// Replace in DOM
					elements[target_id].replace(clone);
					
					// Replace reference
					elements[target_id] = clone;
				} else {
					throw new Exception("Original `" + target_id + "` is not an element.");
				}
			} else {
				throw new Exception("Target `" + target_id + "` is not an element.");
			}
		});
	};
	
	/**
	 * @private selectContent() selects a content element for the page to show, updating the DOM as appropriate, and replacing the 'rollback' original content with this content.
	 *  
	 * @author Cam Morrow
	 * 
	 * @param RH.Content	content_instance	The content instance to show.
	 */
	var selectContent					= function(content_instance) {
		
		// Update the DOM
		updateElements(content_instance, false);
		
		// Set content the new standard
		cacheOriginalElements();
		
		// Update the subnavigation
		$$("#subnav li").each(function(element) {
			element.removeClassName("active");
		});
		
		$("subnav" + content_instance.getID()).addClassName("active");
		
		// Update the title
		document.title = content_instance.getTitle() + " : Robert Humphreys";
	}
	
	/**
	 * @private updateElements() updates the DOM elements for a content instance.
	 * 
	 * @author Cam Morrow
	 * 
	 * @param RH.Content	content_instance	The content instance to show.
	 * @param boolean		is_hover			If true, let the content instance know to only return elements to update as a hover state.
	 */
	var updateElements					= function(content_instance, is_hover) {
		
		// Collect new values from the content object
		var values = content_instance.getUpdates(is_hover);
		
		// Apply values
		for (var i in values) {
			
			if (Object.isElement(elements[i])) {
				elements[i].update(values[i]);
			}
		}
	};
	
	/******************************************************
	 * Event methods
	 *****************************************************/
	
	/**
	 * @private onMouseOver is fired when the user rolls over a content item sub-navigation link.
	 * It shows a preview of the item if applicable.
	 * 
	 * @author Cam Morrow
	 * 
	 * @param Event			e					The fired Event.
	 * @param RH.Content	content_instance	The associated content.
	 */
	var onMouseOver						= function(e, content_instance) {
		e.stop();
		
		// Update the DOM, in hover mode
		updateElements(content_instance, true);
	};
	
	/**
	 * @private onMouseOver is fired when the user rolls off a content item sub-navigation link.
	 * It rolls back the content that was updated during the rollover.
	 * 
	 * @author Cam Morrow
	 * 
	 * @param Event			e					The fired Event.
	 * @param RH.Content	content_instance	The associated content.
	 */
	var onMouseOut						= function(e, content_instance) {
		e.stop();
		
		// Replace original elements
		rollbackOriginalElements("title", "right");
	};
	
	/**
	 * @private onClick is fired when the user clicks on a content item sub-navigation link.
	 * It shows the content on the page.
	 * 
	 * @author Cam Morrow
	 * 
	 * @param Event			e					The fired Event.
	 * @param RH.Content	content_instance	The associated content.
	 */
	var onClick							= function(e, content_instance) {
		try {
			selectContent(content_instance);
		} catch (e) {
			// .. oh dear
		}
	};
	
	return {
		
		/**
		 * @public init() initialises the object, registering events and caching the original DOM state.
		 * 
		 * @author Cam Morrow
		 */
		init:								function() {
			try {
				
				// Store elements
				elements.title		= $("title");
				elements.content	= $("content");
				elements.right		= $("subcontentrightdetail");
				
				// Cache original content for rollback
				cacheOriginalElements();
				
				// Register events
				var target;
				for (var i in content) {
					target = $("subnav" + i);
					if (Object.isElement(target)) {
						target.observe("mouseover", onMouseOver.bindAsEventListener(this, content[i]));
						target.observe("mouseout", onMouseOut.bindAsEventListener(this, content[i]));
						target.observe("click", onClick.bindAsEventListener(this, content[i]));
					} else {
						throw new Exception("Target for `" + i + "` does not exist.");
					}
				}
				
				// Check if an item has already been selected
				if (window.location.hash && window.location.hash.length > 1) {
					var hash_value = parseInt(window.location.hash.substr(1));
					if (hash_value && content[hash_value]) {
						selectContent(content[hash_value]);
					}
				}
			} catch (e) {
				// Oh well, we tried
			}
		},
		
		/**
		 * @public registerContent() stores a Content element from the passed parameters, to be acted on when the page has loaded.
		 * 
		 * @author Cam Morrow
		 * 
		 * @param string	id			The backend ID of the content.
		 * @param string	title		The content title.
		 * @param string	type		The content type.
		 * @param object	properties	Property values for the content.
		 */
		registerContent:					function(id, title, type, properties) {
			content[id] = new RH.Content(id, title, type, properties);
		},
		
		/**
		 * @public The Content class represents a piece of backend content.
		 * 
		 * @author Cam Morrow
		 * 
		 * @param string	id			The backend ID of the content.
		 * @param string	title		The content title.
		 * @param string	type		The content type.
		 * @param object	properties	Property values for the content.
		 */
		Content:							function(id, title, type, properties) {
			
			// Decode the title
			title = unescape(title);
			
			/**
			 * @public getUpdates() returns the elements to update when this content is selected.
			 * 
			 * @author Cam Morrow
			 * 
			 * @param boolean	is_hover	If true, return elements for the hover state of this element, otherwise return for the 'active' state.
			 * 
			 * @return object				An object with identifiers for the elements to update.
			 */
			this.getUpdates						= function(is_hover) {
				
				var updates = {};
				
				if (!is_hover || type == "VideoContent") {
					updates.title	= this.getTitle();
					updates.right	= getRight();
				}
				
				if (!is_hover) {
					updates.content = getContent();
				}
				
				
				return updates;
			};
			
			/**
			 * @public getID() returns the ID.
			 * 
			 * @author Cam Morrow
			 * 
			 * @return string
			 */
			this.getID							= function() {
				return id;
			};
			
			/**
			 * @public getTitle() gets the title of the object.
			 * 
			 * @author Cam Morrow
			 * 
			 * @return string
			 */
			this.getTitle						= function() {
				return title;
			};
			
			var embedVideo						= function(video) {
				try {
					
					VideoJS.setupAllWhenReady();
				} catch (e) {
					
				}
			};
			
			/**
			 * @private getContent() gets the main content for this element.
			 * 
			 * @author Cam Morrow
			 * 
			 * @return string|Element	The content.
			 */
			var getContent						= function() {
				if (type == "VideoContent") {
					
					var width	= 640; //468;
					var height	= 360; //287;
					var src		= properties.video.absolute_path;
					var swf		= "../site/assets/swfs/video_player.swf";
					
					var flash_vars = {
						path:	src
					};
					
					// Defer embedding
					embedVideo.curry(properties.video).defer();
					
					var video_js = "" +
						"<div class=\"video-js-box\" id=\"mainvideo_flashholder\">" +
							"<video id=\"mainvideo\" class=\"video-js\" width=\"" + width + "\" height=\"" + height + "\" poster=\"../site/assets/images/video_placeholder_blanc.jpg\" controls=\"controls\">" +
								"<source src=\"" + src + "\" type=\"video/mp4\" />" +
								"<object id=\"mainvideo_flashfallback\" class=\"vjs-flash-fallback\" data=\"" + swf + "\" width=\"" + width + "\" height=\"" + height + "\" type=\"application/x-shockwave-flash\" allowScriptAccess=\"true\" allowFullScreen=\"true\">" +
									"<param name=\"flashvars\" value=\"path=" + src + "\" />" +
									"<param name=\"movie\" value=\"" + swf + "\" />" +
									"<param name=\"allowScriptAccess\" value=\"true=\" />" +
									"<param name=\"allowFullScreen\" value=\"true\" />" +
									"<img src=\"../site/assets/images/video_placeholder_blanc.jpg\" width=\"" + width + "\" height=\"" + height + "\" alt=\"Poster Image\" title=\"No video playback capabilities.\" />" +
								"</object>" +
								
							"</video>" +
							"<p class=\"vjs-no-video\">No video playback is available in your browser. Please try installing the <a href=\"http://get.adobe.com/flashplayer\">Adobe Flash Player</a>.</p>" + 
						"</div>";
					
					return "<div id=\"videowrapper\" class=\"roflcopter\">" + video_js + "</div>";
				} else {
					return "";
				}
			};
			
			/**
			 * @private getRight() gets the right content of the object.
			 * 
			 * @author Cam Morrow
			 * 
			 * @return string
			 */
			var getRight						= function() {
				var right = "";
				
				if (properties.line_1.length > 0) {
					right += "<b>" + properties.line_1 + "</b><br />";
				}
				
				if (properties.line_2.length > 0) {
					right += properties.line_2.split("\n").join("<br />");
				}
				
				return right;
			};
		}
	};
})();

var flash = {
	videosize:							function(width, height) {
		
		// Update wrapper
		$("videowrapper").setStyle({
			width:		width + "px",
			height:		height + "px"
		});
		
		$("mainvideo_flashfallback").setStyle({
			outline:	"none"
		});
		$("mainvideo_flashfallback").setAttribute("width", width);
		$("mainvideo_flashfallback").setAttribute("height", height);
	}
}
