/**
	@fileoverview This file contains the core components needed to build a MVC driven
	JavaScript application.  An application should be initialized as follows
	
	@example	
	<script type="text/javascript" src="core.js"></script>
	<script type="text/javascript">
		MVC = typeof MVC != 'undefined' ? MVC : {};
		
		// This object is required for all mvc apps
		MVC.config = {
			// The path to all your javascript resources.  It should end with a trailing slash
			baseUrl: '/path/js/',
			
			// Holds all the applications to load
			apps: [
				// The app name is used to build a request to the appropriate app js file
				// The request should look something like ..../mvc/app/appName1/appName2
				'appName1',
				'appName2',
				....
			],
			// Any data that should be shared by your applications
			data: {
			
			},
			
			// Configuration for all the applications' controllers
			controllers: {
				'ControllerName': {
					view: {
						'ViewName': {
						
						}
					},
					models: {
						'ModelName': {
						
						}
					}				
				}
			}
		};
	</script>
	<script type="text/javascript" src="mvc/core.js"></script>
*/
if(typeof MVC == 'undefined'){
	/**
	    @namespace Holds the components related to MVC.
	*/
	MVC = {};
}

/**
	@namespace Holds all the models
*/
MVC.Models = {};

/**
	@namespace Holds all the views
*/
MVC.Views = {};

/**
	@namespace Holds all the controllers
*/
MVC.Controllers = {};

(function(){	
	
	/**
		Copy the properties of one object to another
		@static
		@param obj1 {Object} The object to copy the properties to
		@param obj2 {Object} The object to copy the properties from
	*/
	MVC.mix = function()
	{
		var args = arguments;
		var len = args.length;
		var src;
		
		// If one parameter is passed in, extend Sys.$
		if(len == 1){
			args = [this, args[0]];			
			len++;
		}
		
		var obj = args[0];
		var propObj;
		// Merge properties from right to left
		for(var i=len-1; i > 0; i--)
		{
			src = args[i];
			for(var property in src)
			{
				propObj = src[property];
				// Don't copy undefined values (nulls are ok).  Prevent infinite recursion for circular references
				if(propObj != undefined && propObj != null && propObj != obj)
				{
					if(typeof(propObj) == 'object' && obj[property])
					{
						 MVC.mix(obj[property], propObj);
					}
					else
					{
						obj[property] = propObj;
					}
				}
			}
		}		
		
		return obj;
	};
	
	/*	========================================================================================
		BEGIN FUNCTION PROTOTYPE EXTENSIONS
		======================================================================================== */
		
	/**
		Extend the function prototype to support subscriptions and getters / setters
	*/
	MVC.mix(Function.prototype, 
	/** @scope Function */
	{		
		/**
			Used to designate that this function is a property, therefore it is gettable and settable
			@param {String} [propertyName1] A name of a property this function is dependent on
		*/
		isProperty: function()
		{
			this.isProp = true;
			var pubs = [].slice.call(arguments, 0);
			this.observerNames = this.observerNames != undefined ? this.observerNames.concat(pubs) : pubs;					
			return this;
		},
		
		/**
			A list of publishers to listen for
			@param {String} [propertyName1] A name of a property this function is dependent on
		*/
		observes: function()
		{
			var pubs = [].slice.call(arguments, 0);
			this.observerNames = this.observerNames != undefined ? this.observerNames.concat(pubs) : pubs;
			return this;
		},
		
		/**
			Execute the function in a specific scope
		*/
		scope: function(scopeObj)
		{
			var me = this;
			return function(){
				me.apply(scopeObj, arguments);
			};
		}
	});
	
	/*	========================================================================================
		END FUNCTION PROTOTYPE EXTENSIONS
		======================================================================================== */
	
	/*	========================================================================================
		BEGIN BASE OBJECT DEFINITION
		======================================================================================== */
	
	/**
		Shorthand for creating a property
		@static
		@param {String} name The name of the property
		@param {Object|Function} [value] The value of the property
	*/
	MVC.prop = function(name, value)
	{		
		return new MVC.Property(name, value);
	};
	
	/**
		Wrapper for creating javascript objects
		@return Returns a custom MVC.ObjectBase instance
		@type MVC.ObjectBase
	*/
	MVC.Object = function(oProps)
	{		
		return new MVC.ObjectBase(oProps);
	};	
	
	/**
		Wrapper for creating javascript classes
		@return Returns a class based on MVC.ObjectBase
		@type object
	*/
	MVC.Class = function(oProps)
	{
		oProps.construct = oProps.construct || function(){};
		
		// Create the constructor for the class
		var newClass = function()
		{	
			// Create the hidden prop container
			this.__props__ = this.__props__ || {};			
			
			this.construct.apply(this, arguments);
			
			// Init the function observers
			// TBD: Can this be refactored
			this.initFnObservers();
		};		
		
		// The class is not being extended via inheritance
		if(arguments.callee === MVC.Class)
		{
			// Store the new prototype data			
			newClass.prototype = new MVC.ObjectBase(oProps);
				
			// Need to delete the props parameter otherwise it is treated statically which causes problems
			// TBD: Refactor class logic
			delete newClass.prototype.__props__;			
		}
		else
		{
			// Create an empty prototype to hold the previous classes prototype methods
			var proto = new this;			
			
			var fn;				
			// TODO: Build in inheritance support for constructor
			for(var propName in oProps)
			{					
				proto[propName] = oProps[propName];					
			}
			// Store the new prototype data
			newClass.prototype = proto;
		}
		
		// Copy over all the necessary properties for the class
		newClass.constructor = newClass;
		
		// Add a new method called extend so the class is extendable
		//newClass.extend = MVC.Class;
		
		return newClass;
	};
	
	/**
		The base class for all objects
		@class
		The constructor
		@param {Object} oProps The properties for the object
	*/
	MVC.ObjectBase = function(oProps)
	{
		/*
			The Object should:
				- Create properties on demand to reduce initial overhead
				- The first call to this.prop should create the MVC Property 
					and  bind all its observers if it is a function
		*/
		var prop;
		this.__props__ = {};
		
		// Mix in all the properties
		for(var key in oProps)
		{
			this[key] = oProps[key];
		}
		this.initFnObservers();				
	};
	
	MVC.ObjectBase.prototype = {			
		/**
			All objects have a getter.
			@param {String} name The name of the property.  This can be a "." delimitted string.  For example, "foo.bar.value"
		*/
		get: function(name)
		{
			return this._fromPath(name);
		},
		
		/**
			All objects have a setter.  
			@param {String} name The name of the property.  This can be a "." delimitted string.  For example, "foo.bar.value"
			@param {Object} value The name of the value
			@return This returns the calling object for chainability
		*/
		set: function(name, value)
		{	
			this._fromPath(name, value);			
			return this;
		},
		
		/**
			Check to see whether the current property is defined
			@return
			@type Boolean
		*/
		has: function(name)
		{
			return this.__props__[name] != undefined;
		},
		
		/**
			observe to a property
			@param {String} name The name of the property
			@param {Function} fn The observer function
			@param {Object} [scope] The scope to run the callback
			@return This returns the calling object for chainability
		*/
		observe: function(name, fn, scope)
		{	
			this.prop(name).observe(fn, scope);
			return this;
		},
		
		/**
			Binds two or more properties together.  This by default does two way binding		
			@param {String|MVC.Property}  arg1 A string value for a local property or a MVC.Property instance
			@param {String|MVC.Property}  arg2 A string value for a local property or a MVC.Property instance
			@return This returns the calling object for chainability
		*/
		bind: function(arg1, arg2, argN)
		{
			// Iterate over every argument
			for(var x=0, arg, len=arguments.length; x < len; x++)
			{
				arg = arguments[i];
				// Re-iterate over every argument and bind 
				for(var y=0; y < len; y++)
				{
					if(y != x)
					{
						this.bindTo(arg, arguments[y]);
					}
				}
			}
			return this;
		},
		
		/**
			Binds one object to another.  This does one way binding
			@param {String|MVC.Property} targetName The name of the property to be observed to
			@param {String|MVC.Property} observer1 The name of the property or actual property itself that will be bound to the target 
			@param {String|MVC.Property} [observer2] The name of the property or actual property itself that will be bound to the target 
			@return This returns the calling object for chainability
		*/
		bindTo: function(targetName, observer1, observer2)
		{
			var targetProp = (targetName instanceof MVC.Property) 
				? targetName : this.prop(targetName);			
			
			for(var i=1, destProp; i < arguments.length; i++)
			{
				destProp = arguments[i];
				destProp = (destProp instanceof MVC.Property) 
					? destProp : this.prop(destProp);
				targetProp.observe(destProp.set, destProp);
			}
			
			return this;
		},
		
		/**
			Gets the MVC.Property instance associated with the property
			@param {String} name The name of the property			
			@return
			@type MVC.Property
		*/
		prop: function(name)
		{
			var prop = this.__props__;			
			
			// Create the MVC.Property instance on demand if it does not already exist
			prop = prop[name] || this._setProp(name, this[name]);
			
			return prop;
		},
		
		/**
			This method is needed to init all the function observers in the object
		*/
		initFnObservers: function()
		{
			// Loop through all the properties and find functions that have the observerNames property
			for(var name in this)
			{
				this.initFnObserver(name, this[name]);
			}
		},
		
		/**
			Initializes a single function observer
		*/
		initFnObserver: function(name, fn)
		{
			if(typeof fn == 'function' && fn.observerNames)
			{
				// Initialize the function getter / setter.  This will also initialize any of its publishers
				this.prop(name);
			}
		},
		
		/**
			Helper for getting a property
			@type MVC.Property
		*/
		_setProp: function(name, value)
		{
			/*
				Cases
				1. The user passes no property value
				2. The user passes an object for the property value
				3. The user passes a Function for the property value that should be used as a property
				4. The user passes a Function for the property value that should not be used as a property and is an observer function
				5. The user passes a Function for the property value that should not be used as a property and is not an observer function
			*/
			var me = this;
			
			// Case 1 and 2			
			var prop = MVC.prop(name, value);
			
			// Case 3, 4
			if(typeof value == 'function' && (value.isProp || value.observerNames))
			{
				var observerNames = value.observerNames || [];
								
				// Bind the function to all its publishers				
				// Case 3
				if(value.isProp)
				{
					// Reset the "private" getter and setter for the property to call the function in the current scope
					prop.scope = this;
					prop.fn = value;
					
					// Bind the properties
					for(var i=0,len=observerNames.length; i < len; i++)
					{
						this.bindTo(observerNames[i], prop);
					}
				}
				// Case 4
				else
				{
					// Register the observer function with all the observers
					for(var i=0,len=observerNames.length; i < len; i++)
					{
						this.prop(observerNames[i]).observe(value, this);
					}
				}
				
			}			
			// Case 5
			else if(typeof value == 'function')
			{
				throw 'You are trying to use a function named ' + name + ' that is unsupported for getters and setters.  Try setting the isProperty() method on the function definition';
				return;
			}		
			
			// Store the  MVC.Property in the hidden property collection
			this.__props__[name] = prop;
			
			// Delete the property from "this" to save on memory as well as force the idea of getters and setters :-)
			delete this[name];
			
			return prop;
		},
		
		/**
			Helper to retrieve nested properties
		*/
		_fromPath: function(name, value)
		{
			var parts = name.split('.');
			var obj = this.prop(name);
			for(var i=1, part,len=parts.length; i<len; i++)
			{
				part = parts[i];
				if(obj.has && obj.has(part))
				{
					obj = obj.prop(part);
				}
				else
				{
					// If no getters or setters are defined directly update the property
					if(value == undefined)
					{
						return obj[name];
					}
					else
					{
						obj[name] = value;
					}
				}
			}
			
			if(value == undefined)
			{
				return obj.get(name);
			}
			else
			{
				obj.set(value);
			}
		}
	};
	
	/**
		A class that represents properties used in MVC.  All properties have getters and setters
		that are both observable and bindable
		@class		
		@param {String} name The name of the property
		@param {Object|Function} [value] The value of the property
	*/
	MVC.Property = function(name, value)
	{
		this.name = name;
		this.value = value;
		
		// Holds all the observers
		this._observers = {};
	};
	
	MVC.Property.prototype = {
	
		/**
			Get the property's value
		*/
		get: function()	{return this.fn.call(this.scope || this)},
		
		/**
			Set the property's value
		*/
		set: function(value)
		{	
			this.fn.call(this.scope || this, value, this.name);
			this._notify(this.get());
		},
		
		/**
			Observes to when the property changes
			@param {Function} fn The callback to execute when the property's value changes
			@param {Object} [scope] The scope the observer should be executed in
		*/
		observe: function(fn, scope)
		{
			this._observers[fn.toString()] = {fn: fn, scope: scope || {}};
			return this;
		},
		
		/**
			Unobserves to when the property changes
			@param {Function} fn The callback to execute when the property's value changes
		*/
		unObserve: function(fn)
		{
			delete this._observers[fn.toString()];
			return this;
		},
		
		/**
			The overall getter and setter.  This function can be overidden for function getters and setters
			@param {Object} [value] The value to use for a setter
		*/
		fn: function(value)
		{
			if(value !== undefined)
			{
				this.value = value;
			}
			else
			{
				return this.value;
			}
		},
		
		/**
			Notifies all observers that the properties value has changed
		*/
		_notify: function(value)
		{
			var observers = this._observers;			
			var sub;
			for(var prop in this._observers)
			{
				sub = observers[prop];
				// All observers should  get the new value of the property as well as the property name
				sub.fn.call(sub.scope, value, this.name);
			}			
		}
	};
	
	/*	========================================================================================
		END BASE OBJECT DEFINITION
		======================================================================================== */
	
	/*	========================================================================================
		BEGIN CONTROLLER CLASS DEFINITION
		======================================================================================== */
	/**
		Creates an instance of a controller
		@class This is the MVC.Controller class.  
	**/
	MVC.Controller = MVC.Class(
	/** @scope MVC.Controller */
	{
		/**
			The constructor
			@param {String} name The name of the controller
			@param {Object} actions The actions for the controller			
			@property {String} name The name of the controller
			@property {Function[]} actions A collection of actions
			@property {Object} views A collection of MVC.Views
			@property {Object} models A collection of models
			@property {Object} _observers The observers for the controller		
		*/
		construct: function(name, oProps)
		{
			MVC.mix(this, oProps, {
				name: name,
				initialized: false,
				_observers: {},
				views: null,
				models: {}
			});
						
			// Add the controller to the Overall controller collection
			MVC.Controller.addController(this);
		},
		
		/**
			Call the initialization method
			@methodOf MVC.Controller
		*/
		Init: function()
		{
			if(this.actions['Init'])
			{
				// Get all the views
				this.views = MVC.View.getViews(this.name);				
				return this.invokeAction('Init', {args: arguments});
				this.initialized = true;
			}
		},
		
		/**
			Invokes an action - TBD Refactor
			@methodOf MVC.Controller
			@param {String} action Action name
			@param {Object} params (optional) The param configuration
				@param {Object} [params.originScope] The scope of the action should be executed in
				@param {Array} [params.args] A list of arguments			
		*/
		invokeAction: function(action, params)
		{				
			var context = new MVC.ActionContext(this, params);			
			
			if(!this.actions[action])
			{
				throw 'The action name ' + action + ' does not exist';
			}
			// Execute the action
			var returnVal =  this.actions[action].apply(context, context.args);
			
			// Invoke the observers
			var observers = this._observers[action];
			
			if(observers != undefined && observers.length > 0){
				this._invokeobservers(context, observers);
			}			
			
			return returnVal;
		},
		
		/**
			Used for returning an action callback.  This would be used in scenarios where a controller wants to
			observe to another controller
			@param {String} action The name of the action	
			@param {Object} [data] Data to pass to the action
			@return 
			@type {Function}

		*/
		routeAction: function(action, data)
		{
			var controller = this;
			data = data || {};			
			return function(){
				return controller.invokeAction(action, {originScope: this, args: arguments, data: data});
			};
		},
		
		/*
			Returns a view
			@param {String} viewName The name of the view to retrieve
		*/
		getView: function(viewName)
		{
			return this.views[viewName];
		},
		
		/**
			Renders the view
			@methodOf MVC.Controller
			@param {String} viewName The view name to render
			@param {Object} oProps The parameters to pass to the view
				@param {String} oProps.template The template to render
				@param {HtmlElement|HtmlElement[]} oProps.targets The parent elements whose
				innerHTML will use the template
				@param {Object} [oProps.data] The data to use in rendering the view		
		*/
		renderView: function(viewName, oProps)
		{
			return this.getView(viewName).render(oProps.template, oProps.targets, oProps.data);
		},
		
		/**
			observe to a action
			@methodOf MVC.Controller
			@param {String} action The name of the action to observe to
			@param {Function} fn The callback for the action
		*/
		observeAction: function(action, fn)
		{
			this._observers[action] = this._observers[action] || [];
			this._observers[action].push(fn);
		},
		
		/**
			Invokes a list of observers
			@methodOf MVC.Controller
			@private
			@param {Object} context The context to run the observers
			@param {Array} observers A list of observers
			@param {Array} [args] A list of parameters for the observer methods
		*/
		_invokeobservers: function(context, observers, args)
		{
			args = args || [];
			for(var i=0, len=observers.length; i < len; i++)
			{
				observers[i].apply(context, args);				
			}			
		}	
	});
	
	
	/*	=======================
		BEGIN STATIC MEMBERS
		======================= */		
	
	MVC.mix(MVC.Controller, 
	/** @scope MVC.Controller */
	{
		/**
			A collection of all the controllers
			@static
		*/
		controllers: {},
		/**
		Shorthand for creating an instance of a controller
		@methodOf MVC.Controller
		@static		
		@param {String} name The name of the controller
		@param {Object} actions The actions for the controller			
		*/
		create: function(name, actions)
		{
			return new MVC.Controller(name, actions);
		},
		
		/**
			Shorthand for initializing a controller
			@methodOf MVC.Controller
			@static
			@param {MVC.Controller|MVC.Controller[]} controller A list or single reference to a controller 
			@param {Object} config The config for the Init action
		*/
		setup: function(controller, config)
		{
			if(controller instanceof MVC.Controller)
			{
				controller = [controller];
			}
			
			for(var i in controller)
			{
				ctrl=controller[i];
				ctrl.Init(config[ctrl.name]);		
			}
		},
		
		/**
			Adds a controller to the collection
			@methodOf MVC.Controller
			@static
			@param {MVC.Controller} controller Reference to the controller
		*/
		addController: function(controller)
		{
			MVC.Controller.controllers[controller.name] = controller;
		},
		
		/**
			Returns a reference to a controller
			@methodOf MVC.Controller
			@static
			@param {String} controllerName The name of the controller
			@return 
			@type {MVC.Controller}
		*/
		getController: function(controllerName)
		{
			return MVC.Controller.controllers[controllerName];
		},
		
		/**
			Shorthand for subscribing to a controller action
			@methodOf MVC.Controller
			@static
			@param {String} controllerName The name of the controller
			@param {String} action The name of the action
			@param {Function} fn The callback		
		*/
		observeAction: function(controllerName, action, fn)
		{
			MVC.Controller.getController(controllerName).observeAction(action, fn);
		}
	});	
	
	/*	=======================
		END STATIC MEMBERS
		======================= */	
	/**
		Creates the context in which an action method is executed
		@class This is the MVC.ActionContext class		
	*/
	MVC.ActionContext = MVC.Class(
	/** @scope MVC.ActionContext */
	{
	
		/**
			The constructor		
			@param {MVC.Controller}  controller A reference to the controller
			@param {Object} [oProps] The config for the object			
				@param {Object} [oProps.originScope] The scope of the action method
				@param {Array}  [oProps.args] A list of arguments
				@param {Object} [oProps.data] Any custom data that needed to be passed with the event
		*/
		construct: function(controller, oProps)
		{
			this.controller = controller;
			this.originScope = oProps.originScope;
			this.data = oProps.data || {};
			this.args = oProps.args || [];
		},
		
		/**
			Getters for the action context.  This enables 
		*/
		get: function(name)
		{
			if(name == 'originScope' || name == 'data' || name == 'args'){
				return this[name];
			}			
			return this.controller.get(name);
		},
		
		set: function(name, value)
		{
			this.controller.set(name, value);
			return this;
		},
		
		/**
			@see MVC.Controller.getView
		*/
		getView: function(name)
		{
			return this.controller.getView(name);
		},
		
		/**
			@see MVC.Controller.renderView
		*/
		renderView: function(viewName, oProps)
		{
			return this.controller.renderView(viewName, oProps);
		},
		
		/**
			@see MVC.View.renderData
		*/
		renderData: function(template, data)
		{
			return this.views.renderData(template, data);
		},
		
		/**
			Continues from the current action to a new action.  All arguments and scope
			are passed from the originating action
			@methodOf MVC.ActionContext
			@param {MVC.Controller}  controller A reference to the controller
			@param {Object} oProps The config for the object			
				@param {Object} [oProps.originScope] The scope of the action method
				@param {Array}  [oProps.args] A list of arguments
		*/
		continueToAction: function(action, args)
		{
			return this.controller.invokeAction(action, {
				originScope: this.originScope,
				args: args || this.args || []
			});
		}
	
	});	
	
	/*	========================================================================================
		END CONTROLLER CLASS DEFINITION
		======================================================================================== */
	
	/*	========================================================================================
		BEGIN VIEW  CLASS DEFINITION
		======================================================================================== */	
	/**
		Creates an instance of a view
		@class This is the MVC.View class.  				
	*/
	MVC.View = MVC.Class(
	/** @scope MVC.View */
	{
		/**
			The constructor
			@param {String} name The name of the view
			@param {Object}  oProps The config object
				@param {String} oProps.controllerName The name of the controller the view belongs to
				@param {Function} oProps.init The initializer for the view (Sets all the event handlers, etc.)
				@param {Object} oProps.helpers A list of helper functions for the view
				@param {String|HtmlElement} [oProps.template] The template to use
		*/
		construct: function(name, oProps)
		{
			oProps.controllerName = oProps.controllerName || name;			
			
			MVC.mix(this, oProps.helpers, {
				controllerName: oProps.controllerName,
				_init: oProps.init,
				template: oProps.template,
				name: name,
				initialized: false				
			});			
			
			// Add the controller to the overall view collection
			MVC.View.addView(this);		
		},
		/**
			Initialization method
			@methodOf 	MVC.View
		*/
		Init: function()
		{
			this._init.apply(this, arguments);
			this.initialized = true;
		},
		
		/**
			Get the view's controller
		*/
		getController: function()
		{
			return MVC.Controller.getController(this.controllerName);
		},
		
		/**
			Routes the event to the appropriate controller and action
			@methodOf 	MVC.View
			@param {String} action The name of the action	
			@param {Object} [data] Data to pass to the action
			@return 
			@type {Function}
		*/
		routeEvent: function(action, data)
		{
			var controller = this.getController();
			data = data || {};
			return function(){
				return controller.invokeAction(action, {originScope: this, args: arguments, data: data});
			};
		},
		
		/**
			Render the view into a string
			@methodOf 	MVC.View
			@param {String} template The template to render
			@param {HtmlElement|HtmlElement[]} targets The parent elements whose
			innerHTML will use the template
			@param {Object} data (optional) The data to use in rendering the view
			@return {String}
		*/
		render: function(template, targets, data)
		{
			targets = targets.length != undefined ? targets : [targets];
			for(var i=0, len=targets.length; i < len; i++)
			{
				targets[i].innerHTML = this.renderData(template, data);
			}
		},		
		
		/**
			Takes data and makes the appropriate string replacements
			@methodOf MVC.View
			@param {String} template The template to render
			@param {Object} [data] The data to be used while rendering
		*/
		renderData: function(template, data)
		{
			Sys.$.forEach(data, function(key, elem){
				var regex = new RegExp('\{' + key + '\}', 'g');
				template = template.replace(regex, elem);
			});
			return template;
		}		

	});
	
	/*	==========================
		BEGIN STATIC MEMBERS
		========================== */	
	MVC.mix(MVC.View, {
		
		views: {},
		/**
		Shorthand for creating an instance of a view
		@methodOf MVC.View
		@static
		@param {String} name The name of the view
		@param {String} controllerName The name of the controller the view is associated
		@param {Function} fn The initializer for the view
		*/
		create: function(name, controllerName, fn)
		{
			return new MVC.View(name, controllerName, fn);
		},
		
		/**
			Adds a controller to the collection
			@methodOf MVC.View		
			@static
			@param {MVC.Controller} controller Reference to the controller
		*/
		addView: function(view)
		{
			MVC.View.views[view.controllerName] = MVC.View.views[view.controllerName] || {};
			MVC.View.views[view.controllerName][view.name] = view;				
		},
		
		/**
			Returns a reference to a View
			@methodOf MVC.View		
			@static
			@param {String} controllerName The name of the controller
			@param {String} viewNameThe name of the view
			@return 
			@type {MVC.View}
		*/
		getView: function(controllerName, viewName)
		{
			return MVC.View.views[controllerName][viewName];
		},
		
		/**
			Returns all the views for a controller
			@methodOf MVC.View		
			@static
			@param {String} controllerName The name of the controller		
			@return 
			@type {[MVC.View]}
		*/
		getViews: function(controllerName)
		{
			return MVC.View.views[controllerName];
		}
		
		/*	=======================
			END STATIC MEMBERS
			======================= */	
	});
	/*	========================================================================================
		END VIEW  CLASS DEFINITION
		======================================================================================== */
})();

(function(){
	/**
		Loads a module
		@param {Array|String} module The  module to load.  This name should be defined in the dependencies object
		@param {Function} [fn] A function to execute after the module is loaded
		@return Returns an array of script elements
		@type ScriptElement []
	*/
	require = function(module, fn)
	{
		var scripts = [];
		var callback;
		// An array module was passed.  Recursively load it's dependencies
		if(typeof module != 'string')
		{
			for(var i=0,len=module.length, mod; i < len; i++)
			{
				// Check to see if a fn has been passed and if we are on the last module.
				// We want the callback to be associated with the very last script
				callback = typeof fn != 'undefined' 
							&& i + 1 == len ? fn : undefined;
				// Recursively look up dependencies
				mod = require(module[i], callback);
				
				// The module has not been loaded
				if(mod.length > 0){
					scripts = scripts.concat(mod);
				}
			}
		}
		else
		{
			// Only include scripts once just to be safe
			var script = include_once(module, fn);
			
			// Null is reterence if the script is already included
			if(script != null){
				scripts.push(script);
			}
		}
		
		return scripts;
	};

	/**
		Includes a js file
		@param {String} fileName The name of the file to load
		@param {Function} [fn] A function to execute after the module is loaded
		@return Returns the script element
		@type ScriptElement
		
	*/
	include = function(fileName, fn)
	{
		var cache = include.cache;
		var id = 'inc_script' + new Date().getTime() + 1;
		var script = document.createElement('script');
		script.type = 'text/javascript';
		script.id = id;
		script.src = fileName;
		
		// This handles the case where we are loading multiple scripts from the same source
		// This is primarily for handling RPCs.  For example, if you have to keep making calls to the same
		// web service
		if(cache[fileName] != undefined){
			head.removeChild(document.getElementById(cache[fileName]));
		}		
		cache[fileName] = id;		
		include.head.appendChild(script);
		
		// A callback has been defined
		if(typeof fn != 'undefined')
		{
			// Add the callback to the queue
			include.queue.push(fn);
			
			// IE won't let you add a text node to a script element
			if(document.compatMode && document.all){
				script.onreadystatechange = function(){
					if(/loaded|complete/.test(this.readyState))
					{
						// yield control here just to be safe
						setTimeout(include.load, 0);
					}
				};
			}
			else{
				// All other browsers will work if you append a script after the last executing script
				var lastScript = document.createElement('script');
				lastScript.type = 'text/javascript';
				lastScript.appendChild(document.createTextNode("include.load()"));
				include.head.appendChild(lastScript);
			}
		}
		return script;
	};

	/**
		Includes a js file only once.
		@param {String} fileName The name of the file to load
		@param {Function} [fn] A function to execute after the module is loaded
		@return Returns the script element
		@type {ScriptElement|null}
	*/
	include_once = function(fileName, fn)
	{
		var scripts = include.scripts;
		// Don't include the file if it is already loading or loaded
		if(scripts[fileName] != undefined){return null}
		
		scripts[fileName] = fileName;
		return include(fileName, fn);
	};

	/**
		A reference to the head element of the document
	*/
	include.head = document.getElementsByTagName('head')[0];

	/**
		Contains a collection of loaded scripts
	*/
	include.scripts = {};

	/**
		A queue of callbacks to execute after a script has been loaded
	*/
	include.queue = [];

	/**
		Contains all the loaded scripts.  This will be used to remove references to scripts in the case of repeated RPCs
	*/
	include.cache = {};
	
	/**
		Callback used to fire the callback from a script
	*/
	include.load = function()
	{
		var queue = include.queue;		
		if(queue.length == 0)
		{
			return;
		}
		
		var callback = queue.shift();
		if(typeof callback == 'function')
		{
			callback();
		}
	};	
	
	// Try to load the application files
	if(typeof MVC.config != 'undefined'
		&& typeof MVC.config.apps != 'undefined')
	{
		var apps = MVC.config.apps;
		var baseUrl = MVC.config.baseUrl || '/';
		baseUrl += 'mvc/apps/';
		
		// The application path should look like ..../mvc/apps/AppName/AppName.js
		for(var i=0, len=apps.length, app; i < len; i++)
		{
			app=apps[i];
			// Only include the app files once
			include_once(baseUrl + app + '/' + app + '.js');
		}
	}
})();