var
/****************
Constants
****************/
OSRequestSending = 0,
OSRequestLoading = 1,
OSRequestRecieving = 2,
OSRequestCompleted = 200
;

/****************
Pyro Object
****************/
var pyro = new function() {
/*Variables*/
var
/*functions*/
funcs=[], funcs_name=[],

/*Classes / Objects*/
cls=[],cls_ptr=[], obj_id=-1, obj_cnt=0, glbls=[], glbls_ptrs=[],

/*Contexts*/
cxt_list, cxt_id=-1,

/*Console*/
use_console, consoleTask,

/*Storage*/
pipes=[], pipe_names=[],

/*Messages*/
allow_msgs,msg_origin_list,

/*Scripts*/
_modules=[], _module_f_ext=[],
_import_file_loaded = []
;

/*Core */
this.func = {
	reg_func:	function(f_name, afunc) { funcs.push(afunc); funcs_name.push(f_name); },
	call:		function(f_name, args) {
		var afunc = funcs[funcs_name.indexOf(f_name)];
		if(afunc) return afunc.apply(null,args); else pyro.console.warn('The "'+f_name+'"'+' function does not exists.', 'ignored', null);
	},
	call_id:	function(f_i, args) {
		var afunc = funcs[f_i];
		if(afunc) return afunc.apply(null,args); else pyro.console.warn('The "'+f_i+'"'+' function id does not exists.', 'ignored', null);
	}
};

this.objects = {
	reg_class:		function(aName, aCls) { cls_ptr.push(aName); cls.push(aCls); },
	get_class:		function(aName) { var i=cls_ptr.indexOf(aName); if(i>-1) return cls[i]; else if(aName!='') pyro.console.warn('The "'+aName+'"'+' class does not exists.', 'ignored', null);},
	get_class_id:	function(c_i) { if(cls[c_i]) return cls[c_i]; else pyro.console.warn('The "'+c_i+'"'+' class id does not exists.', 'ignored', null);},
	reg_obj:		function(anObj) { obj_id++; anObj.set('id',obj_id); obj_cnt++; },
	unreg_obj:		function() { obj_cnt--; },
	reg_global:		function(gName,gVar) { glbls_ptrs.push(gName); glbls.push(gVar); },
	get_global:		function(aName) { var i=glbls_ptrs.indexOf(aName); if(i>-1) return glbls[i]; else pyro.console.warn('The "'+aName+'" global does not exists.', 'ignored', null);},
};

this.contexts = {
	reg_cxt: function(aCxt) { aCxt.id = cxt_id++; cxt_list.push(aCxt); },
	unreg_cxt:	function(aCxt) {
		var i=context_list.indexOf(aCxt);
		if(i>-1) { context_list = context_list.splice(i,1); aCxt.dealloc(); }else{ pyro.console.warn('Tried unregistering an unregistered context.', 'ignored', null); };
	}
};

this.event = {
	inputDown:		false,
	c_inputDown:	false,
	c_inputup:		false,
	c_inputMove:	false,
	c_inputOut:		false,
	c_inputOver:	false,
	c_keyDown:		false,
	c_keyUp:		false
	};

this.console = {
	error:		function(aMSG, aType, userInfo) {
		if(use_console) window.console.error(aType + ': ' + aMSG);
		if(consoleTask) consoleTask.error(aMSG, aType, userInfo);
	},
	
	warn:	function(aMSG, aType, userInfo) {
		if(use_console) window.console.warn('Warning:  ' + ': ' + aMSG + ' (' + aType + ')');
		if(consoleTask) consoleTask.warn(aMSG, aType, userInfo);
	},
	
	log:	function(aMSG, userInfo) {
		if(use_console) window.console.log(aMSG);
		if(consoleTask) consoleTask.log(aMSG, userInfo);
	}
};
if(window.console) use_console=true;

this.browser = {
	isWebkit:	false,
	isGecko:	false,
	isOpera:	false,
	isIE:		false,
	version:	0,
	platform:	'unknown',
	host:		'unknown',
	online:		true,
	
	compute:	function() {
		if(RegExp(" AppleWebKit/").test(navigator.userAgent)) {
			this.isWebkit = true;
		} else if(RegExp(" Gecko/").test(navigator.userAgent)) {
			this.isGecko = true;
		} else if(RegExp(" Opera/").test(navigator.userAgent)) {
			this.isOpera = true;
		} else if(document.all) {
			this.isIE = true;
		}
		this.version = parseFloat(navigator.userAgent.substring(navigator.userAgent.lastIndexOf('/')+1));
		this.platform = navigator.platform;
		this.host = navigator.oscpu;
		this.online = navigator.onLine;
	}
};

this.browser.compute();
		

/*Constructor*/
document.addEventListener('mouseup',function(e) {pyro.event.inputDown=false}, false);

/*********************/
}//end of Pyro Object//
/*********************/


/*********************/
//Javascript Module//
/*********************/
	

var
kPublic=0, kPrivate=1,kProperty=3,
__current_cls, __current_var_mode, __current_obj, __proc_prop;

function newGlobal(globalName, avValue) {
	pyro.objects.reg_global(globalName,avValue);
}

function global(globalName) {
	return 	pyro.objects.get_global(globalName);
}

function newFunction(funcName, afunc) {
	pyro.func.reg_func(funcName,afunc);
}

function call(funcName) {
	var args = Array.prototype.slice.call(arguments,1);
	return pyro.func.call_func(funcName, args);
}

var OSPipe = function() {
	this.data=	'';
}

var OSClass = function() {
	this.ivars=		[];
	this.v_ptrs=	[];
	this.var_mds=	[];
	this.ptrs=		[];
	this.imps=		[];
	this.imp_ptrs=	[];
	this.name=		'';
	this.superClass=	'';
}

function newClass(className, superClass) {
	__current_var_mode = 0;
	__current_cls = new OSClass;
	__current_cls.superClass = (superClass) ? superClass : '';
	__current_cls.name = className;
	addVar('id');
	pyro.objects.reg_class(className, __current_cls);
	addProperty('id', 'readonly');
}

function extendClass(className) {
	__current_var_mode = 0;
	__current_cls = fuel_object.get_class(className);
}

function endClass() {
	__current_var_mode = 0;
	__current_cls = undefined;
}

function addVar(aName, aValue, theMode, aType) {
	__current_cls.ivars[__current_cls.ivars.length] = aValue;
	__current_cls.v_ptrs[__current_cls.v_ptrs.length] = aName;
	__current_cls.var_mds[__current_cls.var_mds.length] = (theMode)?theMode : kPublic;
	if(theMode==kProperty) addProperty(aName,aType);
}

function addMethod(aName, aFunction) {
	var i = __current_cls.imp_ptrs.indexOf(aName);
	if(i > -1) {
		__current_cls.imps.splice(i,1);
		__current_cls.imp_ptrs.splice(i,1);
	}
	__current_cls.imps[__current_cls.imps.length] = aFunction;
	__current_cls.imp_ptrs[__current_cls.imp_ptrs.length] = aName;
}

function addProperty(varName, type) {

	var i = __current_cls.v_ptrs.indexOf(varName);
	
	if(i > -1) {
		if(type == 'writeonly') {
			addMethod(varName, function(newValue) { $(varName, newValue);});
		} else if(type == 'readonly') {
			addMethod(varName, function() { return $(varName);});
		} else {
			addMethod(varName, function(newValue) {
					if(exists(newValue)) {
						$(varName, newValue);
					} else {
						return $(varName);
					}
				}
			);
		}
		__current_cls.var_mds[i] = kProperty;
	}
}

var _active_objs=[], _active_objs_locals=[];
function send(msgName) {
	var i = _active_objs.length-1;
	if(i>=0) return _active_objs[i].sendWithArray(msgName, Array.prototype.slice.call(arguments,1));
	else pyro.console.warn('send is not in the scope of an object. Sent message: ' + msgName);
}

function set(varName, aValue) {
	var i = _active_objs.length-1;
	if(i>=0) return _active_objs[i].set(varName,aValue);
	else pyro.console.warn('set is not in the scope of an object.');
}

function get(varName) {
	var i = _active_objs.length-1;
	if(i>=0) return _active_objs[i].get(varName);
	else pyro.console.warn('get is not in the scope of an object.');
}

function $(varName, aValue) {
	var i = _active_objs_locals.length-1;
	if(i>=0) return _active_objs_locals[i].call(_active_objs[i],varName,aValue);
	else pyro.console.warn('Tring to acessing local variables outside the scope of an object');
}

function newObject(className) {
	var theClass = pyro.objects.get_class(className),
	superClass,
	notRoot = true,
	ivarArray = theClass.ivars.slice(),
	var_ptrArray = theClass.v_ptrs.slice(),
	var_mdeArray = theClass.var_mds.slice(),
	impsArray = theClass.imps,
	imp_ptrsArray = theClass.imp_ptrs;
	
	while(notRoot) {
		if(!superClass) superClass = theClass;
		superClass = pyro.objects.get_class(superClass.superClass);
		
		if(superClass && typeof superClass == 'object') {
			ivarArray = ivarArray.concat(superClass.ivars);
			var_ptrArray = var_ptrArray.concat(superClass.v_ptrs);
			var_mdeArray = var_mdeArray.concat(superClass.var_mds);
			impsArray = impsArray.concat(superClass.imps);
			imp_ptrsArray = imp_ptrsArray.concat(superClass.imp_ptrs);
		} else {
			notRoot = false;
		}	
	}

	function getSuperImp(impArray, impName, theLevel) {
		var i, imp_count=impArray.length, super_count=0;
		theLevel++;
		for(i=0; i< imp_count;i++) {
			if(impArray[i] == impName) {
				super_count++;
				if(super_count == theLevel) {
					return i;
					break;
				}
			}
		}
	}
	
	var theInstance = new function() {
		this.classObject = theClass;
		
		var
		ivars = ivarArray,
		v_ptrs = var_ptrArray,
		var_mds = var_mdeArray,

		props_type = [],
		
		imps = impsArray,
		imp_ptrs = imp_ptrsArray,
		super_level=0,
		current_var;
		
		this.lastMessage='';
		
		this.superClass = function() {
			super_level++;
			return this;
		}
		
		function setCurrentObject(localObject) {
			_active_objs.push(localObject);
			_active_objs_locals.push(localVar);
			return true;
		}
		
		function removeCurrentObject() {
			_active_objs.pop(); _active_objs_locals.pop();
		}
		
		function localVar(varName, aValue) {
			if(varName != v_ptrs[current_var]) current_var = v_ptrs.indexOf(varName);
			if(exists(aValue)) {
				ivars[current_var] = aValue;
			} else {
				return ivars[current_var];
			}
		}
		
		this.set = function(varName, aValue) {
			if(aValue != undefined) { 
				if(varName != v_ptrs[current_var]) current_var = v_ptrs.indexOf(varName);
				if(var_mds[current_var] == kPublic) {
					ivars[current_var] = aValue;
				} else if(var_mds[current_var] == kProperty) {
					this.send(varName, aValue);
				}
			}
			super_level=0;
			return this;
		}
		
		this.get = function(varName) {
			if(varName != v_ptrs[current_var]) current_var = v_ptrs.indexOf(varName);
			if(var_mds[current_var] == kPublic) {
				return ivars[current_var];
			} else if(var_mds[current_var] == kProperty) {
					return this.send(varName);
			}
			super_level=0;
		}
		
		this.send = function(msgName) {
			var args = Array.prototype.slice.call(arguments,1);
			return this.sendWithArray(msgName, args);
		}
		
		this.sendWithArray = function(msgName, args) {
			var fromObj = (_active_objs.length <= 0) ? undefined : _active_objs[_active_objs.length-1];
			var setObj = (fromObj !== this) ? setCurrentObject(this) : false;
			if(!fromObj) fromObj=this;
			var imp_level = (super_level==0) ? 0 : getSuperImp(imp_ptrs, msgName, super_level);
			var i=imp_ptrs.indexOf(msgName,imp_level);
			var results;
			if(i > -1) { 
				this.lastMessage = msgName;
				results = imps[imp_ptrs.indexOf(msgName,imp_level)].apply(this, args)
			} else {
				var fromClass = (_active_objs.length <= 1) ? _active_objs[0] : _active_objs[_active_objs.length-2];
				pyro.console.warn('The class "' + this.classObject.name +'" does not understand the message "' + msgName + '". Sent from the class "' + fromObj.classObject.name + '" in method "' + fromObj.lastMessage + '".', 'ignored');
			}
			super_level=0;
			if(setObj) removeCurrentObject();
			return results;
		}
		
		this.imp = function(msgName) {
			imp_level = (super_level==0) ? 0 : getSuperImp(imp_ptrs, msgName, super_level); super_level=0;
			var results = imps[imp_ptrs.indexOf(msgName,imp_level)];
			super_level=0;
			return results;
		}
		
		this.sel = function(msgName) {
			imp_level = (super_level==0) ? 0 : getSuperImp(imp_ptrs, msgName, super_level); super_level=0;
			var results = imp_ptrs.indexOf(msgName,imp_level);
			super_level=0;
			return results;
		}
		
		this.i_set = function(var_i, aValue) {
			if(aValue != undefined) { 
				if(var_mds[i_set] == kPublic) ivars[i_set] = aValue;
				else if(var_mds[i_set] == kProperty) this.i_send(i_set, aValue);
			}
			super_level=0;
			return this;
		}
		
		this.i_get = function(var_i) {
			if(var_mds[var_i] == kPublic) return ivars[var_i];
			else if(var_mds[var_i] == kProperty) return this.i_send(var_i);
			super_level=0;
		}
		
		this.i_send = function(i_msg) {
			var args = Array.prototype.slice.call(arguments,1);
			return this.i_sendWithArray(i_msg, args);
		}
		
		this.i_sendWithArray = function(i_msg, args) {
			var fromObj = (_active_objs.length <= 0) ? undefined : _active_objs[_active_objs.length-1];
			var setObj = (fromObj !== this) ? setCurrentObject(this) : false;
			if(!fromObj) fromObj=this;
			var results;
			this.lastMessage = imp_ptrs[i_msg];
			results = [i_msg].apply(this, args);
			super_level=0;
			if(setObj) removeCurrentObject();
			return results;
		}
		
		
		this.archive = function() {
			var i,v_count=v_ptr.length;
			var output='<obj>'+this.name+':'+this.superClass.name;
			
			function process_object(anObj) {
				output+=anObj.archive();
			}
			
			function process_js_object(anObj) {
				var var_name;
				for(var i2=0; i2 < anObj.length; i2++) {
					var_name = anObj[i2];
					if( typeof(anObj[ivar_name]) == 'object') {
						if(anObj[var_name].classObject) {
							output += var_name+':obj:'+process_object(anObj[var_name]);
						} else {
							output = v_ptrs[i]+':js:'+process_js_object(anObj[var_name]);
						}
					} else {
						output += var_name+'::'+ivars[var_name];
					}
				}
			}
			
			for(i=0; i < v_count; i++) {
				output += '<ivar>';
				if( typeof(ivars[i]) == 'object') {
					if(ivars[i].classObject) {
						output += v_ptrs[i]+':obj:'; process_object(ivars[i]);
					} else {
						output += v_ptrs[i]+':js:'; process_js_object(ivars[i]);
					}
				} else {
					output += v_ptrs[i]+'::'+ivars[i];
				}
			}
			output+='</obj>';
			return output;
							
		}
	}
	if(arguments.length >= 2) {
		var args = Array.prototype.slice.call(arguments,2);
		theInstance.sendWithArray(arguments[1], args);
	} else {
		theInstance.send('init');
	}
	
	return theInstance;
}

/******************/
/*Variable functions*/
/******************/

function toggle(anObj, aVar) {
	var aValue = anObj.get(aVar);
	if(typeof aValue == 'boolean') anObj.set(aVar,(aValue==true) ? false : true)
	else return (aValue !=undefined) ? true : false;
}

function exists(aValue) {
	return (aValue != undefined) ? true : false;
}

function classObject(className) {
	return pyro.objects.get_class(className);
}

//pyro.scripts.load('fuel.js');