(function($) {
	/*
	 * Root Bizit object
	 * All Bizits will extend this object
	 */
	$.bizit = {
		
	};

	/**
	 * @func $().bizit([selector])
	 * 
	 * @param [selector] {null|string|array|regexp} default: null
	 *	Specify which Bizits to interact with.
	 *	Not specifying anything or specifying null and ''
	 *	will utilize the element's "bizit" attribute
	 *	
	 * @param [single] {null|boolean} default: false
	 *	Specify wether or not to return only the first 
	 *	Bizit's reponse.
	 *	All functions being called will still apply
	 *	to all Bizits specified by the selector.
	 * 
	 * @return object {
	 *	data: function(var, [val]) {},
	 *	...
	 * }
	 * 
	 * Main function to interact with bizits
	 * that are bound to an element.
	 * Return available functions and properties depending
	 * on the selector and element used.
	 */
	$.fn.bizit = function(selector, single) {
		var $this = null; // Keeping a global (within this function) reference to the element
		if (!this.length) {
			$this = $(document);
		}
		else {
			$this = this;
		}
		 
		/**
		 * First thing we need to do is determine which
		 * Bizits we are going to interact with based on
		 * the selector.
		 */
		var bizits = Array(); // This Bizits we are going to interact with
		if (!selector) { // If no selector is provided...
			bizits = $.trim($this.attr('bizit')).split(' '); //...Utilize the element's "bizit" attribute
		}
		else if ((typeof selector) == 'string') { // If the selector is a string...
			bizits = $.trim(selector).split(' '); //...Utilize the string as opposed to the element's "bizit" attribute
			if ((single !== false) && (bizits.length == 1)) { // Force a single return if the string selector specifies a single Bizit to interact with
				single = true;
			}
		}
		else if (isRegExp(selector)) { // If the selector is a regular expression...
			attr = $.trim($this.attr('bizit')).split(' '); //...Create an array consisting of the Bizits from the element's "bizit" attribute
			bizits = Array();
			for (i in attr) { // If each Bizit listed in the array ("bizit" attribute)...
				if (attr[i].match(selector)) { //...And matches the provided regular expression (selector)...
					bizits.push(attr[i]); //..Add it to list of Bizits we are going to interact with
				}
			}
		}
		
		/**
		 * Now that we have the array of Bizits we are
		 * going to interact with, we need to obtain the
		 * properties (functions/variables) available to
		 * utilize from each bizit.
		 */
		if ((isArray(bizits)) && (bizits.length)) {
			var result = {}; // Initial object containing the properties to interact with
			var properties = {}; // Bizit properties (variables, etc)
			var functions = {}; // Bizit functions
			for (var b in bizits) { // Loop through Bizits
				var bizit = bizits[b]; // Set the Bizit name to a variable (eg: player)
				
				//var obj = $.bizit[bizit]; // Set the Bizit object to a variable (eg: $.extend($.bizit, { player: { /*Bizit Code*/ } }); )
				eval("var obj = $.bizit."+bizit+";"); // Set the Bizit object to a variable (eg: $.extend($.bizit, { player: { /*Bizit Code*/ } }); )
				if ((typeof obj) != 'undefined') { // If the Bizit exists
					/**
					 * The extention below will be a global function
					 * for each Bizit object.
					 * It will override any Bizit functions or properties
					 * which have the same name.
					 */
					obj = $.extend(obj, {
						/**
						 * @func $().bizit([selector]).data(var, [val])
						 * 
						 * @param [selector] {null|string|array|regexp}
						 * 
						 * @param var {string}
						 * 
						 * @param [vall] {null|string|array|regexp}
						 * 
						 * @return object {
						 *	bizit1: {...},
						 *	bizit2: {...},
						 *	bizit3: {...}
						 * }
						 * 
						 * A $().data() expansion which uses the Bizit object's properties as the 
						 * initial value and supports the custom 'multi bizit' return structure
						 */
						data: function() {
							var $ns = arguments[0].namespace;
							var $var = arguments[1];
							var $val = arguments[2]||null;
							switch (arguments.length) {
								case 2:
									$return = null;
									if (!($return = $(this).data($ns+'.'+$var))) {
										
										if ((typeof obj[$var]) != 'undefined') {
											$return = obj[$var];
										}
									}
									return $return;
									break;
								case 3:
									return $(this).data($ns+'.'+$var, $val);
									break;
							}
							
							return false;
						}
					});
					
					for (var i in obj) {
						eval('var item = obj.'+i+';');
						switch (typeof item) {
							case 'function':
								if ((typeof functions[i]) == 'undefined') {
									functions[i] = new Array();
								}
								functions[i].push({
									bizit: bizit, 
									func: item
								});
								break;
							case 'string':
							case 'number':
							case 'object':
								if ((typeof properties[i]) == 'undefined') {
									properties[i] = new Array();
								}
								properties[i].push({
									bizit: bizit, 
									prop: item
								});
								break;
							default:
								debug.log('typeof', (typeof item));
								break;
						}
					}
				}
			}
			
			//debug.log('functions', functions);
			var $single = false;
			for (var func in functions) {
				function calleerFunc(func, args) {
					var returns = {};
					for (var f in functions[func]) {
						var otrig = functions[func][f];
						var trigger = 'bizit.'+otrig.bizit+'.'+func;
						$this.bind(trigger, otrig.func);
						if (!single) {
							returns[otrig.bizit] = $this.triggerHandler(trigger, args);
						}
						else if (!$single) {
							$single = true;
							returns = $this.triggerHandler(trigger, args);
						}
						else {
							$this.triggerHandler(trigger, args);
						}
						
						$this.unbind(trigger);
					}
					return returns;
				}
				eval("result[func] = function "+func+"() { func = arguments.callee.toString().match(/function ([^\\(]+)/)[1]; return calleerFunc(func, arguments); }");
			}
			//debug.log('properties', properties);
			$bizits = $this[bizits];
			if ((typeof $bizits) == 'undefined') {
				$bizits = {};
			}
			for (var prop in properties) {
				var returns = {};
				for (var p in properties[prop]) {
					var otrig = properties[prop][p];
					$bizit = $bizits[otrig.bizit];
					if ((typeof $bizit) == 'undefined') {
						$bizit = {};
					}
					
					$prop = $bizit[prop];
					if ((typeof $prop) == 'undefined') {
						$prop = otrig.prop;
					}

					if (!single) {
						returns[otrig.bizit] = $prop;
					}
					else {
						returns = $prop;
						break;
					}
				}
				if (returns) {
					result[prop] = returns;
				}
			}
			//debug.log('result', result);
			return result;
		}
		else {
			return $this;
		}
	};
})(jQuery);


