/**	
	@author			nathaniel skulic <nate@skulic.name>
	@copyright 		Copyright 2006, Nathaniel Skulic. All Rights Reserved.
	@fileOverview	
*/


/* 


function object( proto )
{
  proto = proto || {};
  var T = function () {};
  T.prototype = proto;
  return new T();
}

freja:
Freja.Class = {};
Freja.Class.extend = function(subClass, superconstructor) {
        var inlineSuper = function(){};
        inlineSuper.prototype = superconstructor.prototype;
        subClass.prototype = new inlineSuper();
        subClass.prototype.constructor = subClass;
        subClass.prototype.superconstructor = superconstructor;
        subClass.prototype.supertype = superconstructor.prototype;
};
*/
/* Prototyping encapsulation. */

function instanceOf(object, klass) {
  // Handle exceptions where the target object originates from another frame.
  // This is handy for JSON parsing (amongst other things).
  
  if (typeof klass != "function") {
    throw "Invalid 'instanceOf' operand.";
  }

  if (object == null) return false;
  
  /*@cc_on  
  // COM objects don't have a constructor
  if (typeof object.constructor != "function") {
    return typeOf(object) == typeof klass.prototype.valueOf();
  }
  @*/
  /*@if (@_jscript_version < 5.1)
    if ($Legacy.instanceOf(object, klass)) return true;
  @else @*/
    if (object instanceof klass) return true;
  /*@end @*/

  // If the class is a base2 class then it would have passed the test above.
  //if (Base.ancestorOf == klass.ancestorOf) return false;
  
  // base2 objects can only be instances of Object.
  //if (Base.ancestorOf == object.constructor.ancestorOf) return klass == Object;
  
  switch (klass) {
    case Array: // This is the only troublesome one.
      return !!(typeof object == "object" && object.join && object.splice);
    case Function:
      return typeOf(object) == "function";
    case RegExp:
      return typeof object.constructor.$1 == "string";
    case Date:
      return !!object.getTimezoneOffset;
    case String:
    case Number:  // These are bullet-proof.
    case Boolean:
      return typeof object == typeof klass.prototype.valueOf();
    case Object:
      return true;
  }
  
  return false;
};

var Prototype = {
    construct:function(parent, definition){
        
        // if we only pass a definition, make it known
        if (arguments.length == 1) {
            // set the definition as the first argument
            definition = parent;
            parent = null;
        }
        
        // create the constructor function, this just redirects the arguments to the initializers, parent first
        var initializer = function(){
            try{
					// call the parent initializer if extending
					if(this.$parent || this.$extended) {
						parent = this.$parent;
						parents = [];
						// fetch all parents and run initializers in reverse
						while(parent){
							parents.push(parent);
							parent = parent.$parent;
						}
						for(var i = 0; i < parents.length; i++){
							parents[i].initialize.apply(this, arguments);
						}
						 //this.$parent.initialize.apply(this, arguments);
					 }
					 try {
					 // try calling the construct
					 this.initialize.apply(this, arguments);
					 }
					 catch(E){
					 return _error('cant initialize prototype. '+this.name+' '+E.fileName+' '+E.lineNumber+' '+E.message);
					 }
           } 
            catch(error){
                return _error('cant initialize parent prototypes. '+' '+error.fileName+' '+error.lineNumber+' '+error.message);
            }
				
        }
		  // the prototype is not extended by default
		  initializer.prototype.$extended = false;
		  
		  // if we have a parent and its a function, copy the parents prototype, set the initializer to extended
		  if(typeof(parent) == 'function'){
			  
			  for (var i in parent.prototype) {
					//// if we have an object instance, set the member as the objects constructor
					if(typeof parent.prototype[i] == 'object'){
						var pointer = parent.prototype[i];
						var new_member = function(){
							 this.apply(this, arguments);
						}
						new_member.prototype.constructor = pointer;
						initializer.prototype[i] = new_member; 
						initializer.prototype[i].prototype = pointer; 
					}
					else {
						 initializer.prototype[i] = parent.prototype[i];
					}
				}
				
			  initializer.prototype.$extended = true;
			  
			  
			  
		  }
		  /* if(instanceOf(parent.prototype, Array)){
			  initializer.prototype = parent.prototype;
		  }
		  else  */if(parent) initializer.prototype.$parent = parent.prototype;              
		  
		  /* var F = function() {};
		  		F.prototype = superc.prototype;
			subc.prototype = new F();
			subc.prototype.constructor = subc;
			 */
		
			/* if (overrides) {
				for (var i in overrides) {
					subc.prototype[i] = overrides[i];
				}
			}
	 */
        initializer.prototype.toString = function(){
            return this.name || 'Prototype';
        }
		  
        // copy the members of definition to the prototype of initializer
        for(variable in definition){
            // if we have an object instance, set the member as the objects constructor
            if(typeof definition[variable] == 'object'){
                
               var pointer = definition[variable];
					
			   
			   if (pointer == null || (pointer && pointer.constructor == Array)) {
					
				   
					//initializer.prototype[variable] = definition[variable];
					initializer.prototype[variable] = null;//
					continue;
				}
               var new_member = function(){
                   this.apply(this, arguments);
               }
               new_member.prototype.constructor = pointer;
               // // initialize.prototype.variable = 
               initializer.prototype[variable] = new_member; 
               // 
               initializer.prototype[variable].prototype = pointer; 
               // 
               continue;   
            }
            else {
                initializer.prototype[variable] = definition[variable];
            }
        }
        
        return initializer;
    }
};
Prototype.Singleton = function(parent, definition){
    // if we only pass a definition, make it known
    if (arguments.length == 1) {
        // set the definition as the first argument
        definition = parent;
        parent = null;
    }
        
    var new_singleton = function(){
        //try{
            if (this.caller != this.getInstance) {
                throw new Error("There is no public constructor for this singleton!");
            }
            
            //this.initialize.apply(this, arguments);
            
        //} 
        //catch(e){
        //    alert('Error initializing class!: '+e);
        //}
    };
    
    new_singleton.__instance__ = null;
    
    new_singleton.getInstance = function () {
        if (this.__instance__ == null) {
            this.__instance__ = new this();
        }
        return this.__instance__;
    }
    
    // copy the members of definition to the prototype of initializer
    for(variable in definition){
        // if we have an object instance, set the member as the objects constructor
        if(typeof definition[variable] == 'object'){
            
           // var pointer = definition[variable];
           // 
           // //alert(pointer);
           // 
           // var new_member = function(){
           //     //this.apply(this, arguments);
           // }
           // //new_member.prototype.constructor = definition[variable];
           // // initialize.prototype.variable = 
           // initializer.prototype[variable] = new_member; 
           // 
           // initializer.prototype[variable].prototype = pointer; 
           // 
           // continue;   
        }
        else {
            new_singleton[variable] = definition[variable];
        }
    }
    
    return new_singleton;

}


/* a = Prototype.construct(Array, {

		test:function(){}
});
b= new a();
c = []; */



Prototype.extend = function(subClass, baseClass, baseFuncName) { 
    function inheritance() {}
    inheritance.prototype = baseClass.prototype;
    extend(subClass.prototype, new inheritance());
    /* subClass.prototype.constructor = subClass;
    if (!baseFuncName || baseFuncName == "")
        baseFuncName = "base"; */
    //subClass[baseFuncName] = baseClass.prototype.initialize;
}

function extend(destination, source, recursive) {
	if (typeof(source) != "object") return source;
	if (!destination) destination = (source instanceof Array) ? [] : {};
	
	for (var property in source){
		// dont copy properties already there
		if(destination[property]) continue;
		destination[property] = 
			(recursive !== true || typeof(source[property]) != "object" || source instanceof Array) 
				? source[property] 
				: extend(destination[property], source[property], recursive);
	}
	return destination;
};


