/**
 * All classes should be subclasses of RS.Object. By doing so, you can come closer to inheritance than
 * with plain JavaScript objects. RS.Object can be seen as root object of a class hierarchy.
 * 
 * A subclass always can call superclass methods, even if they were overriden in the subclass. This allows
 * us to create more complex class hierarchies.
 * 
 * To create a subclass, you have to use the class method extend(). extend() takes an object as argument. 
 * This object just contains the prototype for the new class, including method overrides.
 * 
 * Subclasses of RS.Object come with a default constructor named init with optional arguments
 * 
 * 	Foo = RS.Object.extend({
 * 		init: function(a, b) {
 * 			alert('initializing foo with ' + a + ' ' + b);
 * 		}
 * 	});
 * 
 * 	var foo = new Foo('some','arguments'); // alerts "initializing foo with some arguments"
 * 
 * 
 * 
 * To call a super method, for example myMethod you just have to prefix the method name with $. Example:
 * 			
 * 	...
 * 		// Override myMethod
 * 		myMethod: function() {
 * 			// call the method of the superclass
 * 			this.$myMethod();	
 * 		}	
 * 	...
 * 		
 * 
 * 
 * Examples:
 * 
 * 		// Class A
 * 		A = RS.Object.extend({
 * 
 * 			foo: function() {
 * 				alert('foo from A');
 * 			}	
 * 
 * 			bar: function() {
 * 				alert('bar from A');	
 * 			}
 * 
 * 		});
 * 
 * 		// Class B is a subclass of A
 * 		B = A.extend({
 * 
 * 			foo: function() {
 * 				this.$foo();
 * 				alert('foo from B');
 * 			}
 * 
 * 		});
 * 
 * 		// Class C is a subclass of B
 * 		C = B.extend({
 * 			
 * 			foo: function() {
 * 				this.$foo();
 * 				alert('foo from C');
 * 			}			
 * 
 * 			bar: function() {
 * 				this.$bar();
 * 				alert('bar from C');
 * 			}
 * 
 * 		});
 * 
 * 		
 * 		var c = new C();
 * 
 * 		c.foo(); 	// alerts 'foo from A' then 'foo from B' then 'foo from C'
 * 		c.bar();	// alerts 'bar from A' then 'bar from C'
 * 
 */



RS = {}

RS.Class = {}
RS.Class.create = function() {
	
	theClass = function() {
		
		// initialize new private vars... do this for every(!) instance
		this.__RSK_BINDINGS = {};
		this.__RSK_CALLSTACK = [];
		
		// call the default constructor
		this.init.apply(this,arguments);
	}
	
	// define the distance from the root object (the root object will be RS.Object)
	theClass.__RSK_DEPTH = 0;
	
	return theClass;
	
}



RS.Util = {}

RS.Util._copy_stack = [];
RS.Util.copy = function(obj) { 
	
	if (typeof(obj)!='object') return obj;
	
	var rootCaller = (this._copy_stack.length==0);
	
	
	// check for cyclic references!!!!
	// if we are referenced by an object we want to copy => copy ourselves??? no need to start all over again.. and again... and again
	//if (this._copy_stack.indexOf(obj)>-1) return obj; 
	for (var i=0; i<this._copy_stack.length; i++) {
		if (this._copy_stack[i]==obj) return obj;
	}
	
	this._copy_stack.push(obj);
	
	var cp = {}
	for (var key in obj) {
		
		if (typeof(obj[key])=='object') {
			cp[key] = this.copy(obj[key]);
		}
		else {
			cp[key] = obj[key];
		}
	}
	
	if (rootCaller) this._copy_stack = [];
	
	return cp;
}


RS.Object = RS.Class.create();
// extend() does all the dirty work.
RS.Object.extend = function(proto) {
	
	// create the subclass
	var cls = RS.Class.create();
	
	// subclass needs a reference to its superclass
	cls.superclass = this;
	
	// the stack is used to put targets on it,
	// so we know at every point in which class/superclass we are.
	cls.__RSK_CALLSTACK = [];
	
	
	// Take care of class methods.
	for (var k in this) {
		
		if (k[0] == '$') 			continue;
		if (k == 'prototype')		continue;
		if (k == 'superclass')		continue;
		if (k == '__RSK_CALLSTACK')	continue;
		
		if (typeof(this[k]) == 'function' && k != 'extend') { // we don't allow to override extend()
			// initialize the callstack for this function
			cls.__RSK_CALLSTACK[k] = [cls];
			eval("cls.$"+k+" = function() {  "+
						"var stack 	= this.__RSK_CALLSTACK."+k+"; "+
						// we are calling super => we need the superclass of the current class
						"var target	= stack[stack.length-1].superclass; "+
						// put the superclass on the stack.
						// this is needed in case the superclass itself needs to call the superclass,
						// this way it will easily find it (like we did here).
						"stack.push(target); "+
						// execute the method
						"var ret = target."+k+".apply(this,arguments); "+
						// finished executing, remove from the calling stack
						"stack.pop(); "+
						"return ret; "+
					"}");
			// default implementation of the function just calls its superclass method
			eval("cls."+k+" = function() { return this.$"+k+".apply(this,arguments); }");
		}
		else {
			cls[k] = RS.Util.copy(this[k]);
		}
		
	}
	
	// we now are one deeper then our superclass
	// we already copied the value of __RSK_DEPTH, so we just need to increment it
	cls.__RSK_DEPTH++;
	
	//////////////////////////////////////////////////////////////////
	// Prototype
	cls.prototype.superclass = this.prototype;

	// Instance methods.
	for (var k in this.prototype) {
		
		if (k[0]=='$') 				continue;
		if (k=='superclass') 		continue;
		if (k=='__RSK_CALLSTACK')	continue;
		if (k=='__RSK_BINDINGS')	continue;
		
		if (typeof(this.prototype[k])=='function') {
			eval("cls.prototype.$"+k+" = function() {  "+
						"if (!this.__RSK_CALLSTACK."+k+") this.__RSK_CALLSTACK."+k+" = [this]; "+
						"var stack 	= this.__RSK_CALLSTACK."+k+"; "+
						"var target	= stack[stack.length-1].superclass; "+
						"stack.push(target); "+
						"var ret = target."+k+".apply(this,arguments); "+
						"stack.pop(); "+
						"return ret; "+
					"}");
			if (!proto[k]) {
				// default implementation just calls the supermethod
				eval("cls.prototype."+k+" = function() { return this.$"+k+".apply(this,arguments); }");
			}
		}
		else if (!proto[k]) {
			cls.prototype[k] = RS.Util.copy(this.prototype[k]);
		}
	}
	
	for (var k in proto) {
		if (k.substring(0,5)=='__RSK') {
			//alert('not letting you override '+k+'');
			continue;
		}
		if (k[0]=='$') {
			continue;
		}
		if (k=='superclass') {
			continue;
		}
		cls.prototype[k] = proto[k];
	}
		
	return cls;
	
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


/**
 * Chaosys Namespace
 */

OI = window.OI || {};


/**
 * Chaosys Root Object
 */

OI.Object = RS.Object.extend({});
