//--- Javascript framework base ---

// Setup global variables

// RHG Root namespace
if (!RHG) {
	var RHG = {};
}

// All functionality based on the RHG.Class object
if (!RHG.Classes) {
	RHG.Classes = {}
}

// Additional functionality that behaves differently to RHG.Class
if (!RHG.Utilities) {
	RHG.Utilities = {}
}

// Any variables used by multiple classes/utilites
if (!RHG.Variables) {
	RHG.Variables = {}
}

// --- Global Variables ---
// Used for all AJAX loading
RHG.Variables.loadSpinnerHtml = "<p class='load-spinner'><em>Loading</em></p>";



// Add a class of javascript-active to the body as soon as possible
/**
(function(){
	if (window.document.body) {
		window.document.body.className += " javascript-active"
	} else {
		setTimeout(arguments.callee, 10)		
	}
})()
*/


// CSS3 PIE
RHG.Utilities.PIEAttach = function(elem) {
	if (typeof PIE === 'object') {
		//PIE.attach(elem);		
	}
}
RHG.Utilities.PIEDetach = function(elem) {
	if (typeof PIE === 'object') {
		//PIE.detach(elem);
	}
}	
RHG.Utilities.doPIE = function() {
	if (typeof PIE === 'object') {
		jQuery('img,'
		+ '.account-boxed,'
		+ '.account-login-details .fake-form dd,'
		+ '.account-feature-box,'
		+ '.atoz li a,'
		+ '.atoz li strong,'
		+ '.author-thumb .author-image,'
		+ '.blog-entry .comment,'
		+ '.blog-entry .comment-form,'
		+ '.book-of-month,'
		+ '.button a,'
		+ '.button span,'
		+ 'blockquote.bubble,'
		+ '.carousel .carousel-previous a,'
		+ '.carousel .carousel-previous strong,'
		+ '.carousel .carousel-next a,'
		+ '.carousel .carousel-next strong,'
		+ '.date-badge,'
		+ '.date-badge span,'
		+ '.featured-title,'
		+ '.featured-title .description,'
		+ '.footer-page-curl,'
		+ '#left-col nav h3 a,'
		+ '#left-col nav h3 span,'
		+ '.leftmenu h3 a'
		+ '.popup-box,'
		+ '.product-details .otherformat-selector ul,'
		+ '.share-links li,'
		+ '.sidebar-feature-box,'
		+ 'ul.tabset-tabs li.current,'
		+ 'ul.tabset-tabs li a,'
		+ 'ul.tabset-tabs li strong,'
		+ '#left-col nav h3,'
		+ '#footer .list-carousel,'
		+ '.row-submit input,'
		+ '.intro-textX').each(function(){
			//PIE.attach(this);
		})	
	}
}
jQuery(document).ready(function(){
	RHG.Utilities.doPIE();	
});

// SoundManager2 setup
SM2_DEFER = true

RHG.Utilities.ControlButton = function(labelText, className, actionFunction, containerString) {
	var ControlButtonPub = {}
	var containerString = (typeof(containerString) == "string") ? containerString : "p";
	
	var enabledElemJq = jQuery("<"+containerString+" href='#' class='"+className+"'><a href='#'>"+labelText+"</a></"+containerString+">");
	var disabledElemJq = jQuery("<"+containerString+" class='"+className+" disabled'><span>"+labelText+"</span></"+containerString+">");
	ControlButtonPub.elemJq;
	var enabled;		

	var actionFunctionWrapper = function(evt) {
		actionFunction(evt);
		return false;
	}

	ControlButtonPub.enable = function() {
		
		if (enabled == false) { 
			disabledElemJq.replaceWith(enabledElemJq);
			ControlButtonPub.elemJq = enabledElemJq;									
			enabled = true;
		}
		
	    enabledElemJq.unbind('click', actionFunctionWrapper);
	    enabledElemJq.bind('click', actionFunctionWrapper);
	}

	ControlButtonPub.disable = function() {
		if (enabled == true) { 
			enabledElemJq.replaceWith(disabledElemJq);
			ControlButtonPub.elemJq = disabledElemJq;
			enabled = false;
		}
	}

	ControlButtonPub.setLabelText = function(newLabelText) {
		if (newLabelText) {
			enabledElemJq.text(newLabelText);
			disabledElemJq.text(newLabelText);
		} else {
			enabledElemJq.text(labelText);
			disabledElemJq.text(labelText);
		}
	}

	ControlButtonPub.setActionFunction = function(newActionFunction) {
		actionFunction = newActionFunction;
	}

	ControlButtonPub.elemJq = disabledElemJq;
	enabled = false;
	
	return ControlButtonPub;
}

RHG.Utilities.ToggleButton = function(ControlButtonArray) {
	var ToggleButtonPub = {}
	ToggleButtonPub.currentControlButton;
	
	ToggleButtonPub.setState = function(indexOrControlButton) {
		var newControlButton;
		if (typeof(indexOrControlButton) == "number") {
			newControlButton = ControlButtonArray[indexOrControlButton]
		} else {
			// Should really check type, but I can't figure that out right now
			newControlButton = indexOrControlButton
		}

		if (newControlButton !== ToggleButtonPub.currentControlButton) {
			ToggleButtonPub.currentControlButton.elemJq.replaceWith(newControlButton.elemJq);
			newControlButton.enable();
			ToggleButtonPub.currentControlButton = newControlButton;
		}
	}
	
	ToggleButtonPub.toggleState = function() {
		var index = jQuery.inArray(ToggleButtonPub.currentControlButton, ControlButtonArray);
		if (index == ControlButtonArray.length-1) {
			ToggleButtonPub.setState(0)
		} else {
			ToggleButtonPub.setState(index + 1)
		}
	}

	ToggleButtonPub.currentControlButton = ControlButtonArray[0];
	
	return ToggleButtonPub;
}




// --- Base Class ---

// This helps maintain a standard pattern for scripts used on RHG
// 
// Scripts can be initialised by calling it's init function with an object describing the configuration
// var referenceObject = RHG.Classes.ClassName.init({
// 		"uniqueTargetNodeOrSelector": "#example-selector",
// 		"exampleConfigOption": "example"
// 	})
// 
// (If you examine the implementations, configuration options are found as properties of the configObject passed into classFunction)

RHG.Class = function(){
	
	this.classFunction = function(configObject) {} // Dummy reference to the main class function (Constructor)

	this.selectors = {} // Dummy reference to CSS Selectors that might get changed in the future that are used for functionality in the class
    
	this.classObjectNodeMap = []; // Storage of all instances of the class implementation that are used in the page

	this.getState = function(classFunctionInstance) {
		return {};		
	}

	// Tool for retreiving a reference to the initiated class object from a DOM node (if it exists)
	// Mostly used to make sure elements do not get modified twice
	this.getMapItemFromNode = function(targetNodeOrSelector) {
		var thisClass = this;
		
		var returnElem = false;
		if (targetNodeOrSelector !== undefined) {
			jQuery.each(this.classObjectNodeMap, function(i) {
				var mapItem = thisClass.classObjectNodeMap[i];
				if (mapItem.uniqueTargetNodeOrSelector == targetNodeOrSelector) {
					returnElem = mapItem;
				}
			});
		}
		
		if (returnElem !== false) {
			return returnElem;
		} else {
			return null;
		}
	}

	// Creates an instance of the main classFunction
	this.makeInstance = function(configObjectObj) {	
	    var thisClass = this; // Shortcut to capture the scope of this, refering to the above properites
		var tempReturn = null;

			var previousMapItem = thisClass.getMapItemFromNode(configObjectObj.uniqueTargetNodeOrSelector);
			if (previousMapItem != null) {
				// If it's already been instantiated on this element, persist state
				var stateObject = thisClass.getState(previousMapItem.classObject);
				for (i in stateObject) {
					configObjectObj[i] = stateObject[i];
				}
			}
			
			// Initialise with the configuration
			var tempNodeMap = {
				"uniqueTargetNodeOrSelector": configObjectObj.uniqueTargetNodeOrSelector,
				"classObject": new thisClass.classFunction(configObjectObj) // Instantiate the main classFunction
			}

			if (previousMapItem != null) {
				thisClass.classObjectNodeMap[jQuery.inArray(previousMapItem, thisClass.classObjectNodeMap)] = tempNodeMap;
			} else {
				thisClass.classObjectNodeMap.push(tempNodeMap);
			}
			
			// Check if we've flagged this object to load immediately
			if(configObjectObj.loadImmediate) {
				// Load this objects init immediately - don't wait for the rest of the page to load
				tempNodeMap.classObject.init();
			}
			else {
				jQuery(document).ready(function(){
					// Make things happen on DOM Ready, this avoids having to include elsewhere in the implementations
					tempNodeMap.classObject.init()
				});
			}
			
			tempReturn = tempNodeMap.classObject
		//}

		return tempReturn;
	}

	// Our main interface
	this.init = function(customConfigObject) {
		var thisClass = this; // Shortcut to capture the scope of this, refering to the above properites
		
		// Return a reference to the created instance, so it can be worked with elsewhere
		return (thisClass.makeInstance(customConfigObject));
	}
}

