/**
 * @author camilo AT Bronson ID .com
 * A small attempt at some basic MVC methods for javascript. Not complete. Not full MVC. Just a small step.
 * The inheritance class functions are inspired by John Resig who in turn was inspired by Base2 and Prototype
 * Thank you for the inspiration and tips guys and girls.
 */
var BasicMVC = {};

(function()
{
	var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;

  	// The base Class implementation (does nothing)
  	this.BasicMVC.Class = function(){};

  	// Create a new Class that inherits from this class
  	BasicMVC.Class.extend = function(prop) 
	{
    	var _super = this.prototype;

	    // Instantiate a base class (but only create the instance,
	    // don't run the init constructor)
	    initializing = true;
	    var prototype = new this();
	    initializing = false;

		var hasConstructor = false;
		
	    // Copy the properties over onto the new prototype
	    for (var name in prop) {
	      // Check if we're overwriting an existing function
	      prototype[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];
			
			if (name == "constructor") hasConstructor = true;
			
	    }
		
		// this is for IE. ie doesnt list "constructor" as part of the key/value object "prop"	
		if (!hasConstructor) 
		{
			prototype["constructor"] = prop["constructor"];
		}
	
		prototype["localScope"] = function(fn)
		{
			var self = this;
			var args = arguments;
			
			return function()
			{
				var argsList = []
				for(var i = 0; i < arguments.length; i++)
				{
					argsList.push(arguments[i]);
				}
				if (args != null) 
				{
					for(var i = 0; i < args.length; i++)
					{
						argsList.push(args[i]);
					}
				}
				fn.apply(self, argsList);
			}
			
			delete self;
		}

	    // The dummy class constructor
	    BasicMVC.Class = function() 
		{
	      	// All construction is actually done in the init method
	      	if ( !initializing && this.constructor )
			{
				this.constructor.apply(this, arguments);
			}  
	  	}
		
	
	    // Populate our constructed prototype object
	    BasicMVC.Class.prototype = prototype;
	
		

	    // Enforce the constructor to be what we expect
	   	BasicMVC.Class.constructor = BasicMVC.Class;

	    // And make this class extendable
	    BasicMVC.Class.extend = arguments.callee;

	    return BasicMVC.Class;
  	};
}
)();



BasicMVC.Facade = function()
{
	this.objects = [];
	this.objectsRef = [];
	this.objectsFriendlyName = {};
	this.debug = false;
	this.debugShowData = false;
}

BasicMVC.Facade.facade;

BasicMVC.Facade.getInstance = function()
{
	if (BasicMVC.Facade.facade == null)
	{
		BasicMVC.Facade.facade = new BasicMVC.Facade();
	}
	return BasicMVC.Facade.facade;
}

/**
 * Register a class to the list of classes
 * @param {Object} object
 */
BasicMVC.Facade.prototype.register = function(object)
{
	
	// create a unique name
	var uniqueName = object.name + "-" + Math.random().toString().replace(/\./, "");
	object.uniqueName = uniqueName;
	
	// set a reference with the unique name
	this.objectsRef[uniqueName] = object;
	
	// create an array with friendly names
	if (this.objectsFriendlyName[object.name] == null)
	{
		this.objectsFriendlyName[object.name] = [];
	}
	
	// save the object in an array with friendly names
	this.objectsFriendlyName[object.name].push(object);
	
	
	object._innerEventHandlersRef = {};
	var handlerList = object.eventListeners();
	for (var i = 0; i < handlerList.length; i++)
	{
		if (handlerList[i] + "" == "undefined")
		{
			console.log("ERROR: event name not defined in object '" + object.name + "' when registering to facade.");
		}
		object._innerEventHandlersRef[handlerList[i]] = true;
	}
	this.objects.push(object);
	
}

BasicMVC.Facade.prototype.getInstanceByName = function(name)
{
	var returnObject = null;
	
	if (typeof this.objectsFriendlyName[name] == "object")
	{
		if (this.objectsFriendlyName[name].length > 1) 
		{
			returnObject = this.objectsFriendlyName[name];
		}
		else
		{
			returnObject = this.objectsFriendlyName[name][0];
		}
	}

	return returnObject;
}

/**
 * When an event is dispatched, we look trough the registered objects and call the ones that are listening
 * @param {Object} eventName
 */
BasicMVC.Facade.prototype.sendEvent = function(eventName)
{
	
	
	var message = { name: eventName };
	
	if (arguments.length == 2)
	{
		message.data = arguments[1];
	}
	
	//console.log("--------- ######## ---------- + arguments.length = " + arguments.length);
	if (arguments.length > 2)
	{
		var newArguments = [];
		for (var i = 1; i < arguments.length; i++)
		{
			newArguments.push(arguments[i]);
		}
		//console.log("--------- ######## ----------")
		//console.log(newArguments)
		message.data = newArguments;
	}

	if (this.debug) 
	{
		var now = new Date();
		console.log("BasicMVC EVENT: " + eventName);
		
		if (this.debugShowData) 
		{
			if (typeof message.data != "undefined") 
			{
				console.log(message.data);
				//console.log(" ");
			}
		}
	}

	for(var i = 0; i < this.objects.length; i++)
	{
		
		if (this.objects[i]._innerEventHandlersRef[eventName] === true)
		{
			this.objects[i].eventHandlers(message);
		}
	}
}


/**
 * This is the class that other classes should inherit from (or be based from)
 */
BasicMVC.Base = BasicMVC.Class.extend({

	constructor: function()
	{
		 	
	},
	
	facade: BasicMVC.Facade.getInstance(),
	
	/**
	 * This function dispatches an event and passes the event identifier and the data forward to the BasicMVCFacade "singleton" (or just a global variable in js)
	 * thereby triggering the chain that calls everythign else
	 * @alias BasicMVC.Base.prototype.sendEvent
	 * @param {Object} eventString
	 */
	sendEvent: function(eventName)
	{
		if (eventName + "" == "undefined") 
		{
			console.log("ERROR: event name not defined when dispatched from '" + this.name + "'");
		}
		else 
		{
			this.facade.sendEvent.apply(this.facade, arguments);
		}
	},
	
	/**
	 * @alias BasicMVC.Base.prototype.register
	 * @param {Object} name
	 */
	register: function(name)
	{
		this.register(this);
	},
	
	/**
	 * All classes inheriting from this one should have a function called listeners which returns an array
	 * @alias BasicMVC.Base.prototype.eventListeners
	 */
	eventListeners: function()
	{
		return [];
	},
	
	/**
	 * All classes inheriting from this one should have a function called eventHandlers
	 * @alias BasicMVC.Base.prototype.eventHandlers
	 * @param {Object} eventString
	 * @param {Object} data
	 */
	eventHandlers: function(eventString, data)
	{
		throw new TypeError("Cannot be called, must be overriden");
	}
	
});


