/**
*	Class.extend
*
*	Extension class that allows for MVC class patterns
*/
// Inspired by base2 and Prototype
(function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;

  // The base Class implementation (does nothing)
  this.Class = function(){};
 
  // Create a new Class that inherits from this class
  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;
   
    // 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];
    }
   
    // The 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 = prototype;
   
    // Enforce the constructor to be what we expect
    Class.constructor = Class;

    // And make this class extendable
    Class.extend = arguments.callee;
   
    return Class;
  };
})();

/**
*	AbstractObject
*
*	@param	t - type string
*/
var AbstractObject = Class.extend(
	{
		init: function(t)
		{
			/**
			*	@property	type
			*
			*	Defines the objects type
			*/
			this.type = t;
			
			/**
			*	@property	includes
			*
			*	Defines the objects includes array
			*/
			this.includes = [];
		},
		
		/**
		*   getType
		*
		*   Returns the objects type
		*/
		getType: function()
		{
			return this.type;
		},
		
		/**
		*   addInclude
		*
		*   Adds a new include to the page
		*
		*	@param	s - script path to include
		*/
		addInclude: function(s)
		{
			// if already included
			// then exit the function
			if ( this.includes[s] != undefined ) 
				return;
			
			this.includes[s] = $( document ).write( '<script type="text/javascript" src="' + s + '"></script>' );
		},
		
		/**
		*	urlVars
		*	
		*	Returns an array of url vars
		*/
		urlVars: function()
		{
			var vars = [], hash;
			var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
			
			for(var i = 0; i < hashes.length; i++)
			{
				hash = hashes[i].split('=');
				vars.push(hash[0]);
				vars[hash[0]] = hash[1];
			}
		
			return vars;
		},
		
		/**
		*   broadcast
		*
		*   Broadcasts an event object
		*
		*	@param	t - event type
		*	@param	d - event data
		*/
		broadcast: function(t, d)
		{
			$( this ).trigger( t, d ); 
		},
		
		/**
		*   debug
		*
		*   Decorator function to the 'alert' method
		*
		*	@param	s - alert string
		*/
		debug: function(s)
		{
			alert( this.getType() + " " + s );
		}
	}
);

/**
*	AbstractModel
*
*	@param	t - type string
*	@param	p - application prefix
*/
var AbstractModel = AbstractObject.extend(
	{
		init: function(t, p)
		{
			this._super( t );
			
			// define props
			this.prefix = p;
		},
		
		/**
		*   getPrefix
		*
		*   Returns the application prefix
		*/
		getPrefix: function()
		{
			return this.prefix;
		}
	}
);

/**
*	AbstractControl
*
*	@param	t - type string
*	@param	c - model instance
*/
var AbstractControl = AbstractObject.extend(
	{
		init: function(t, c)
		{
			this._super( t );
			
			// set props
			this.core = c;
		},
		
		/**
		*   getCore
		*
		*   Returns the application model instance
		*/
		getCore: function()
		{
			return this.core;
		}
	}
);

/**
*	AbstractView
*
*	@param	t - type string
*	@param	m - manager instance
*	@param	h - view holder instance
*/
var AbstractView = AbstractObject.extend(
	{
		init: function(t, m, h)
		{
			this._super( t );
			
			// define props
			this.manager = m;
			this.holder = h;
		},
		
		/**
		*   getManager
		*
		*   Returns the views manager instance
		*/
		setManager: function(e) { this.manager = e; },
		getManager: function() { return this.manager; },
		
		/**
		*   getHolder
		*
		*   Returns the views holder instance
		*/
		setHolder: function(e) { this.holder = e; },
		getHolder: function() { return this.holder; },
		
		/**
		*   buildCallbackString
		*
		*   Builds a callback function based upon the contents of a callback object
		*
		*	@param	c - callback object
		*/
		buildCallbackString: function(c) 
		{
			// open a callback string
			callback = c.scope + '.' + c.call + '( ';
												  
			// loop through args and compile accordingly
			if ( c.args != null ) {
			// if there have been arguments set
				for ( i=0; i<c.args.length; i++ )
				{
					switch ( c.args[i].dataType )
					{
						// @@ case - string - callback data is typed string
						case "string":
						
							callback += '\'' + c.args[i].arg + '\'';
						
							break;
							
						// @@ case - number - callback data is typed number
						case "number":
						
							callback += c.args[i].arg;
						
							break;
					}
					
					if ( i != c.args.length-1 )
						callback += ', ';
				}
			}
			
			// finish string
			callback += ' );';
			
			// ...and return
			return callback;
		},
		
		/**
		*   setup
		*
		*   Sets up the view instance
		*/
		setup: function()
		{
			// sets up the view
		},
		
		/**
		*   build
		*
		*   Builds the view
		*/
		build: function()
		{
			// builds the view
		},
		
		/**
		*   update
		*
		*   Updates the view
		*
		*	@param	t - event type
		*	@param	d - data
		*/
		update: function(t, d)
		{
			// updates the view
		}
	}
);

/**
*	AbstractManager
*
*	@param	t - type string
*	@param	c - model instance
*/
var AbstractManager = AbstractObject.extend(
	{
		init: function(t, c)
		{
			this._super( t );
			
			// set props
			this.core = c;
			this.controls = new Object();
		},
		
		/**
		*   getCore
		*
		*   Returns the application model instance
		*/
		getCore: function()
		{
			return this.core;
		},
		
		/**
		*   setControls
		*
		*   Sets the manager controls array
		*
		*	@param	c - controls array
		*/
		setControls: function(c)
		{
			this.controls = c;
		},
		
		/**
		*   addControl / getControl
		*
		*   Adds / Returns a control instance
		*
		*	@param	id - control id
		*	@param	c - control instance
		*/
		addControl: function(id, c)
		{
			this.controls[id] = c;
		},
		getControl: function(id)
		{
			return this.controls[id];
		}
	}
);
