/**
 * Delegate class
 * Static class to create delegates or to chain them.
 * @version: 1.0
 * @author: kzm
 */
var Delegate = {
    /**
     * public Delegate.make()
     * Takes 2 or more arguments. Everything after the first two arguments will be passed as arguments to the given method when this delegate gets triggered.
     * @param: Object The object holding the method to be called
     * @param: Function The method to be called
     * @returns: Function The delegate..
     */
	make: function(target,funk){
		var del = function(){
					var self = arguments.callee;
					var args = Delegate.concat(self.args,arguments);
					return self.funk.apply(self.target,args);
				 };
		del.args   = Delegate.slice(arguments,2);
		del.funk   = funk;
		del.target = target;
		return del;
	},
	/**
	 * Delegate.wrap()
	 * Chains two delegates up. The outter delegate gets remodeled = changes
	 * @param: Function The function that should be called second in the chain.
	 * @param: Function The function that should be called first in the chain.
	 * @returns: Function The new formed function.
	 */
	wrap: function(inner,outter){
		var del = function(){
					var self = arguments.callee;
					var args = Delegate.concat(self.args,self.encapsled.apply(null,arguments),arguments);
					return self.funk.apply(self.target,args);
				};
		del.args      = outter.args;
		del.funk      = outter.funk;
		del.target    = outter.target;
		del.encapsled = inner;
		outter        = del;
		return del;
	},
	/**
	 * public Delegate.remove()
	 * Removes agiven delegate from the chain.
	 * @param: Function the delegate to look for.
	 * @param: Function the delegate chain to look in.
	 * @return: Function The changed chain.
	 */
	remove: function(remove,chain){
		if(remove!=null && chain!=null){
			if(chain.encapsled===remove){
				if(remove.encapsled!=null)
					chain.encapsled = remove.encapsled
				else
					delete chain.encapsled;
			}
			else if(chain.encapsled != null)
				Delegate.remove(remove,chain.encapsled);
			else if(chain===remove)
				chain = remove.encapsled;
		}
		return chain;
	},
	//// private methods ///
	/**
	 * private Delegate.concat()
	 * Takes multiple parameters of the type Array and concates them to a single one
	 * @returns: Array The new formed array.
	 */
	concat: function(){
		var arr = []; var brr = [];
		for(var i=0;i<arguments.length;i++){
			brr = arguments[i];
			if(brr!=null){
				for(var j=0;j<brr.length;j++){
					arr.push(brr[j]);
				}
			}
		}
		return arr;
	},
	/**
	 * private Delegate.slice()
	 * Slice slices an Array in two parts.
	 * @param: Array The array to slice from.
	 * @param: Integer The position from where to start.
	 * @returns: Array The new fromed array.
	 */
	slice: function(arr,start){
		var brr = [];
		for(var i=start;i<arr.length;i++){
			brr.push(arr[i]);
		}
		return brr;
	}
};