﻿


///////// 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 'couk.liamprescott' 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;

			// Check for 'couk'
			if (_global.couk && (typeof _global.couk != "object" ||	_global.couk.NAME)) throw new Error("GlobalNamespace 'couk' already exists in an incompatible format and will be overridden");
			
			// Check for 'couk.liamprescott'
			if (_global.couk && _global.couk.liamprescott && (typeof _global.couk.liamprescott != "object" || _global.couk.liamprescott.NAME)) throw new Error("GlobalNamespace 'couk.liamprescott' already exists in an incompatible format and will be overridden");
			
			/* Create base namespace object */
			_global.couk = {};
			
			_global.couk.liamprescott = {};
			
			_global.couk.liamprescott.NAME = "couk.liamprescott";
			_global.couk.liamprescott.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.couk.liamprescott.Global = Object.subClass(
					
						IN PLACE OF
					
						var Global = Object.subClass(
			 *
			 *********************************
			 */
			
			var GlobalUtilities = Object.subClass(
				{
					init : function () 
					{
						this._className		= "couk.liamprescott.GlobalUtilities";
						this._namespaces	= { "couk.liamprescott" : "1.0" };
						//this._classes		= { this.className : "1.0"};
						
						//Page loaded status
						this._pageLoaded	= false;
						
						
						//Set page loaded status on document .ready()
						$(document).ready(function() {
							couk.liamprescott.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("couk.liamprescott.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("couk.liamprescott.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.couk.liamprescott;
						
						for(var i = 0; i < levels.length; i++) 
						{
							var level = levels[i];
							
							//If namespace fully resolved ie couk.liamprescott.a.b... instead of a.b... skip first 2 levels
							if (level != "couk" && level != "liamprescott")
							{
								// 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("couk.liamprescott.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("couk.liamprescott.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("couk.liamprescott.Global.isNamespaceDefined() : you must supply a name");
						return name in this._namespaces;
					},
					
					
					checkNamespaceVersion : function (name)
					{
						if (typeof name != "string") throw new Error("couk.liamprescott.Global.checkNamespaceVersion() name '" + name + "' is not a string");
						if (!this.isNamespaceDefined(name)) throw new Error("couk.liamprescott.Global.checkNamespaceVersion() : The namespace '" + name + "' is not defined");
						
						return this._namespaces[name];
					},
					
					
					isPageLoaded : function ()
					{
						return this._pageLoaded;
					},
					
					
					setPageLoadedStatus : function (b)
					{
						this._pageLoaded = b;
					}
					
				}
				
			);
			
			// Create instance of 'GlobalUtilities' class
			// _global.couk.liamprescott.global = new GlobalUtilities();
						// Create any default namespaces eg :
 						// _global.couk.liamprescott.global.createNamespace("couk.liamprescott.aaa", "1.0");
			
			try {
				_global.couk.liamprescott.global = new GlobalUtilities();
						// Create any default namespaces
						//_global.couk.liamprescott.global.createNamespace("couk.liamprescott.aaa", "1.0");
			}
			catch (e)
			{
				alert("!! WARNING !! \n" + e.message);
			}
			
			
		})(this);
	
	
	//alert("1: " + couk.liamprescott);
	//alert(this.couk.liamprescott.global._namespaces["couk.liamprescott"]);
	//alert(this.couk.liamprescott.global.isNamespaceDefined("couk.liamprescott"));
	//alert(this.couk.liamprescott.global.checkNamespaceVersion("couk.liamprescott"));
	//alert("this should be false (isNamespaceDefined) : " + this.couk.liamprescott.global.isNamespaceDefined("aaa"));
	
	
	