// Additions
// dom extensions
Function.prototype.bind = function(object) {
	var func = this;
	return function() {
		return func.apply(object,arguments);
	}
}
Function.prototype.pack = function(object,args) {
	var func = this;
	return function() {
		return func.apply(object,args);
	}
}
Function.prototype.timer = function(timeout,object,args) {
	setTimeout(this.pack(object,args),timeout);
}



///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////
// Core

RS = {}

RS.Class = {}
RS.Class.create = function() {
	
	theClass = function() {
		
		// initialize new private vars... do this for every(!) instance
		this.__RSK_BINDINGS = {};
		this.__RSK_CALLSTACK = [];
		
		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 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();
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 = [];
	
	
	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;

	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('no way you are going to override '+k);
			continue;
		}
		if (k[0]=='$') {
			continue;
		}
		if (k=='superclass') {
			continue;
		}
		cls.prototype[k] = proto[k];
	}
		
	return cls;
	
}

RS.Object.prototype = {
	
	__RSK_BINDINGS: {},
			
	init: function() {
		
	},
	
	
	set: function(key,value) {
		this[key] = value;
		this.did_change_value_for_key(key,value);
	},
	
	get: function(key) {
		return this[key];
	},
	
	// bindings
	bind: function(key) {
		var b = new RS.Binding(this,key);
		return b;
	},
	
	did_change_value_for_key: function(key,value) {
		if (this.__RSK_BINDINGS[key]) {
			var b = null;
			for (var i=0; i < this.__RSK_BINDINGS[key].length; i++) {
				b = this.__RSK_BINDINGS[key][i];
				b.observer.set(b.observer_key, value);
			}
		}
	},
	
	add_binding: function(b) {
		// there can be multiple bindings for a key => use an array to store the binding objects
		if (!this.__RSK_BINDINGS[b.observee_key]) this.__RSK_BINDINGS[b.observee_key] = []
		this.__RSK_BINDINGS[b.observee_key].push(b);
	}
	
}

RS.Binding = RS.Object.extend({
	
	observer: null,
	observer_key: null,
	observee: null,
	observee_key: null,
	
	init: function(obj,key) {
		this.observer 		= obj;
		this.observer_key	= key;
	},
	
	to: function(obj,key) {
		this.observee		= obj;
		this.observee_key	= key;
		obj.add_binding(this);
	}
});
