/// <reference path="../../../../jQuery/1.3.2/jquery-1.3.2-vsdoc.js" />

// ********************************************************************
// 
// Manheim Retail Services Marketing
// ********************************************************************
// Copyright © 2010 Manheim Retail Services Marketing.
//
//  Summary
// ******************************
//
// File History Information
// ************************				
// Original Author:					Liam Prescott
//
// ********************************************************************


///////// CLASSES ARE CREATED 'INSIDE' NAMESPACES

///////// THEREFORE : To create class : 
										// a. createNamespace / check for existance 
										// b. Create class definition within namespace

/**
 *
 * CORE LIBRARY FUCTIONALITY
 *
 */

	/**
	 * CLASS EXTENSION FUNCTIONALITY
	 *	
	 * Self initialising utility that extends the javascript 'Object' class with the addition of a 
	 * new CLASS LEVEL method '.subClass()' that facilitates creating OOP orientated class structures
	 *
	 * The first level class of ANY HEIRACHY should extend Object:
	 *
	 ****************************************************************************************************
	 EXAMPLE :
	 
			CLASS DEFINITIONS:
			
			var a = Object.subClass(
				{
					init	: function () {}, //// This is the class constructor method
					method1 : function (a) {}, //// Class prototype methods
					method2 : function () {}
				}
			);
			
			var b = a.subClass(
				{
					init		: function () {},
					method1		: function (a,b) { this._super(a) }, //// Override method calling superclasses version of same method
					newMethod1	: function () {}
				}
			);
			
			
			CLASS USAGE:
			
			var instance_a = new a();
			var instance_b = new b();
			
		
			CLASS METHODS: 
			Class methods can be added either after creation or during constructor method

	 ****************************************************************************************************
	 * 
	 * NOTE : This does NOT affect Object.prototype therefore shouldn't cause the associated problems of doing so
	 *
	 *
	 *	- See :	http://ejohn.org/blog/simple-javascript-inheritance/
	 *			http://jsninja.com/Function_Prototypes
	 *
	 */
 
(function () {
	
	var initializing = false;

	// Determine if functions can be serialized
	var fnTest = /xyz/.test(function () {xyz; }) ? /\b_super\b/ : /.*/;
	
	// Create a new Class that inherits from this class
	Object.subClass = function (prop) 
	{
		var _super = this.prototype;
		
		// Instantiate a base class (but only create the instance and don't run the init constructor)
		initializing	= true;
		var proto		= new this();
		initializing	= false;
		
		// Copy the properties over onto the new prototype
		for (var name in prop) {
			// Check if we're overwriting an existing function
			proto[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function (name, fn)
			{
				return function ()
				{
					var tmp = this._super;
					
					// Add a new ._super() method that is the same method but on the super-class
					this._super = _super[name];
					
					// The method only need to be bound temporarily, so we remove it when we're done executing
					var ret		= fn.apply(this, arguments);
					this._super = tmp;
					
					return ret;
				};
			})(name, prop[name]) : prop[name];
		}
		
		// Dummy class constructor
		function Class()
		{
			// All construction is actually done in the init method
			if (!initializing && this.init)
			{
				this.init.apply(this, arguments);
			}
		}
		
		// Populate our constructed prototype object
		Class.prototype = proto;
		
		// Enforce the constructor
		Class.constructor = Class;
		
		// And make this class extendable
		Class.subClass = arguments.callee;
		
		return Class;
	};
})();






/**
 * GLOBAL UTILITY CLASS instance creation
 *
 * Self initialising GLOBAL UTILITY CLASS instance
 *
 * - Creates base global namespace object 'manheim' into which all other namespaces and classes are created
 *
 * - Provides a global utilities object (accessed via global object 'manheim.global') that provides a series generic core utility methods:
 *		- createNamespace(name)
 *		- isNamespaceDefined(name)
 *		- checkNamespaceVersion(name)
 */
	
(function (globalNamespace)
{
	
	var _global = globalNamespace;
	
	if (_global.manheim && (typeof _global.manheim !== "object" || _global.manheim.NAME))
	{
		throw new Error("GlobalNamespace 'manheim' already exists in an incompatible format and will be overridden");
	}
		
	
	/* Create base namespace object */
	_global.manheim = {};
	
	_global.manheim.NAME = "manheim";
	_global.manheim.VERSION = "1.0";
	
	
	/**
	 *********************************
	 * DEFINE 'Global' class 
	 * 
	 * Transient declaration : declare, use and destroy as currently only require single instance
	 *
	 * NOTE:	If in future wish to add CLASS LEVEL METHODS:
				Define in class in global scope via :
	 
				_global.manheim.Global = Object.subClass(
			
				IN PLACE OF
			
				var Global = Object.subClass(
	 *
	 *********************************
	 */
	
	var GlobalUtilities = Object.subClass(
		{
			init : function () 
			{
				this._className		= "manheim.GlobalUtilities";
				this._namespaces	= { "manheim" : "1.0" };
				//this._classes		= { this.className : "1.0"};
				
				//Page loaded status
				this._pageLoaded	= false;
				
				
				//Set page loaded status on document .ready()
				$(document).ready(function () {
					manheim.global.setPageLoadedStatus(true);
				});
				
			},
			
			/*
			className : "manheim.Global",
			
			namespaces : { "manheim" : "1.0" },
			
			classes : { this.className : true },
			*/
			
			createNamespace : function (name, version)
			{
				// Check name exists 
				if (!name)
				{
					throw new Error("manheim.Global.createNamespace(): name required");
				}
				
				// Check name doesn't begin or end with a period or contain two periods in a row
				if (name.charAt(0) === '.' || name.charAt(name.length - 1) === '.' || name.indexOf("..") !== -1)
				{
					throw new Error("manheim.Global.createNamespace((): illegal name: " + name);
				}
			
				// Break the name at periods and create an array of levels (the object hierarchy)
				var levels = name.split('.');

				// For each namespace component, either create an object or ensure that an object by that name already exists.
				var container = _global.manheim;
				
				for (var i = 0; i < levels.length; i++)
				{
					var level = levels[i];
					
					//If namespace fully resolved ie manheim.a.b... instead of a.b... skip first level
					if (level !== "manheim")
					{
						// If there is no property of container with this name, create an empty object.
						if (!container[level])
						{
							container[level] = {};
						}
						// Else if there is already a property, make sure it is an object
						else if (typeof container[level] !== "object") 
						{
							var n = levels.slice(0, i).join('.');
							throw new Error("manheim.Global.createNamespace() : " + n + " already exists and is not an object");
						}
						container = container[level];
					}
				}

				// The last container traversed above is the namespace created.
				var namespace = container;

				// It is an error to define a namespace twice. It is okay if the namespace object already exists, but it must not already have a NAME property defined.
				if (namespace.NAME)
				{
					throw new Error("manheim.Global.createNamespace() : " + name  + " is already defined");
				}

				// Initialize name and version fields of the namespace
				namespace.NAME		= name;
				namespace.VERSION	= (version) ? version : "0.0";

				// Register this namespace and version number
				this._namespaces[name] = namespace.VERSION;
				//this._namespaces[name] = namespace;

				// Return the namespace object to the caller
				return namespace;
			},
			
			
			isNamespaceDefined : function (name)
			{
				if (!name)
				{
					throw new Error("manheim.Global.isNamespaceDefined() : you must supply a name");
				}
				return name in this._namespaces;
			},
			
			
			/**
			 * Method for checking if either a 'class definition' OR a 'class instance' has been created
			 *
			 * @param	name [String]	period (".") delimited class path
			 * @return	[Boolean]
			 */
			isClassDefined : function (name)
			{
				if (!name)
				{
					throw new Error("manheim.Global.isClassDefined() : you must supply a name");
				}
				
				// Check name doesn't begin or end with a period or contain two periods in a row and contains a namespace : ie. contains AT LEAST one instance of (".") e.g. ("a.B" = valid) whereas ("B" = invalid)
				if (name.charAt(0) === '.' || name.charAt(name.length - 1) === '.' || name.indexOf("..") !== -1 || name.indexOf(".") === -1)
				{
					throw new Error("manheim.Global.isClassDefined((): illegal name: " + name);
				}
				
				// Extract namespace and Class
				var lastindex = name.lastIndexOf(".");
				
				var ns	= name.slice(0, lastindex);
				var c	= name.slice(lastindex + 1, name.length);
				//alert("ns = " + ns + " // c = " + c);
				
				//Check if namespace has been defined
				if (!this.isNamespaceDefined(ns))
				{
					return false;
				}
				else 
				{
					// Resolve namespace and test
					var nsObj = this.resolveStringToNamespaceObject(ns);
					return c in nsObj;
				}
			},
			
			
			
			/**
			 * Method for resolving a period (".") delimited Namespace string to an object reference
			 *
			 * @param	namespaceString [String]	period (".") delimited class path : THIS MUST BE A VALID NAMESPACE STRING - use this.isNamespaceDefined() to test
			 * @return	[Object]					reference to namespace object
			 */
			resolveStringToNamespaceObject : function (name)
			{
				// Check name doesn't begin or end with a period or contain two periods in a row
				if (name.charAt(0) === '.' || name.charAt(name.length - 1) === '.' || name.indexOf("..") !== -1 || name.indexOf(".") === -1)
				{
					throw new Error("manheim.Global.resolveStringToNamespaceObject((): illegal name: " + name);
				}
				
				var s = name;
				if (!this.isNamespaceDefined(s))
				{
					return false;
				}
				
				var a	= s.split(".");
				var objRef = _global;
				
				for (var i = 0; i < a.length; i++)
				{
					var c	= a[i];
					objRef	= objRef[c]; 
				}
				
				return objRef;
			},
			
			
			
			/**
			 * Method for resolving a period (".") delimited Namespace string to an object reference
			 *
			 * @param	namespaceString [String]	period (".") delimited class path : THIS MUST BE A VALID NAMESPACE STRING - use this.isNamespaceDefined() to test
			 * @return	[Object]					reference to namespace object
			 */
			resolveStringToClassInstanceObject : function (name)
			{
				// Check name doesn't begin or end with a period or contain two periods in a row
				if (name.charAt(0) === '.' || name.charAt(name.length - 1) === '.' || name.indexOf("..") !== -1 || name.indexOf(".") === -1)
				{
					throw new Error("manheim.Global.resolveStringToNamespaceObject((): illegal name: " + name);
				}
				
				// Extract namespace and Class
				var lastindex = name.lastIndexOf(".");
				
				var ns	= name.slice(0, lastindex);
				var c	= name.slice(lastindex + 1, name.length);
				
				//Check if namespace has been defined
				if (!this.isNamespaceDefined(ns))
				{
					return false;
				}
				else 
				{
					// Resolve namespace and test
					var nsObj = this.resolveStringToNamespaceObject(ns);
					
					if (c in nsObj)
					{
						return nsObj[c];
					}
					else 
					{
						alert("ouch : c = " + c + " // " + nsObj[c]);
						return false;
					}
				}
				
			},
			
			
			
			/**
			 * Method for 
			 *
			 * @param	[String]
			 * @return	[Object]
			 */
			checkNamespaceVersion : function (name)
			{
				if (typeof name !== "string")
				{
					throw new Error("manheim.Global.checkNamespaceVersion() name '" + name + "' is not a string");
				}
				
				if (!this.isNamespaceDefined(name))
				{
					throw new Error("manheim.Global.checkNamespaceVersion() : The namespace '" + name + "' is not defined");
				}
				
				return this._namespaces[name];
			},
			
			
			
			/**
			 * Method for 
			 *
			 * @return	[Boolean]
			 */
			isPageLoaded : function ()
			{
				return this._pageLoaded;
			},
			
			
			
			/**
			 * Method for 
			 *
			 * @param	[Booleam]
			 */
			setPageLoadedStatus : function (b)
			{
				this._pageLoaded = b;
			}
			
		}
		
	);
	
	try {
		_global.manheim.global = new GlobalUtilities();
		_global.manheim.global.createNamespace("manheim.rsm", "1.0");
	}
	catch (e)
	{
		alert("!! WARNING !! \n" + e.message);
	}
	
	
})(this);
