// This file uses JSDoc-friendly comments [ http://jsdoc.sourceforge.net/ ]

/**
 * @file         grvClasses.js
 * @fileoverview Alternate Collection of routines to emulate multiple-inheritance
 * classes in JavaScript. This "multiple inheritance" has the earlier
 * classes in the superclass list getting precedence over the later classes
 * with regard to resolving both explicit and implicit-via-super references.
 * A detailed explanation of the functionality of this file can
 * be found in the <a target="_blank"
 * href="http://www.polyglotinc.com/AJAXscratch/Class">AJAX from Scratch</a>
 * series of articles.<br/>
 * <b>NOTE:</b> Include this grvClasses.js file OR grvClass.js, but not both!
 *
 * @author       Bruce Wallace  (PolyGlotInc.com)
 * @version      2.2
 * @requires     grvValidate.js (optional; only required if validating constructor args)
 */

//////////////////////////////////////////////////////////////////
// GRAVEY LEXICAL CODING CONVENTIONS:
// (*) All private variables or functions start with "_"
// (*) All variables and functions start with a lowercase letter
// (*) All Classes start with an uppercase letter
// (*) All Class methods and instance variables start with lowercase
// (*) All Class "static" methods and variables start with uppercase
// (*) All constants start with "k"
// (*) All global variables start with "g"
// (*) All event handler functions start with "on"
//
// (*) All Gravey utility global variables start with "gGrv"
// (*) All Gravey MVC     global variables start with "gMVC"
// (*) All Gravey EDO     global variables start with "gEDO"
// (*) All Gravey utility functions start with "grv"
// (*) All Gravey MVC     functions start with "mvc"
// (*) All Gravey MVC event handler functions start with "onMVC"
// (*) All Gravey EDO event handler functions start with "onEDO"
// (*) All Gravey MVC classes start with "MVC"
// (*) All Gravey EDO classes start with "EDO"
//////////////////////////////////////////////////////////////////

/**
 * This function returns the name of a given function; It does this by
 * using a regular expression to extract the function name from the
 * function source code.
 * @param {Function} f reference to a function
 * @return name of given function
 * @type String
 * @author Bruce Wallace (PolyGlotInc.com)
 * @version 2.0
 */
function grvFuncName(f)
{
	var s = f.toString().match(/function\s*(\S*)\s*\(/)[1];
	return s ? s : "anonymous";
}

Class(GrvObject);
/**
 * @class This is the root class for all "classes" implemented
 * via the {@link GLOBALS#Class} function (ala Java "Object").
 * Class replaces the normal Javascript "constructor" function
 * with a new wrapper function that implements a robust
 * inheritence mechanism.
 * This mechanism supports "pretty" source code whereby
 * "methods" are declared inline, but the source code of
 * those methods are not copied into every object instance
 * as would otherwise be the case.<p>
 * The wrapper function also sets up a real "constructor"
 * that can use {@link GLOBALS#grvValidateArgs} to insure
 * that the required parameters are passed to it, throwing
 * an exception if not.<p>
 * The design pattern implemented by Class/Extends corrects
 * several problems that occur with the naive inheritence
 * mechanisms often used with Javascript.
 *<pre>
 *  The required coding convention for "GrvObject":
 *  (1) the "class" is declared via the utility
 *      function {@link GLOBALS#Class}
 *  (2) the "superclass" (if any) is declared via the
 *      .Extends method {@link GLOBALS#grvExtends}
 *  (3) the "constructor" logic for the class is placed
 *      in a "method" named "konstructor"
 *  (4) the konstructor method invokes the "super" constructor
 *      via its class name [rather than literally "super()"]
 *  (5) "interfaces" and extra "superclasses" (if any) are
 *      declared via the .Implements method {@link GLOBALS#grvImplements}
 *</pre>
 * @throws grvMissingArgException thrown by constructor wrapper
 * @see GLOBALS#Class
 * @see GLOBALS#grvExtends
 * @see GLOBALS#grvImplements
 * @author Bruce Wallace  (PolyGlotInc.com)
 * @version 2.2
 */
function GrvObject()
{
	/** Invokes the "super" version of whatever method that is calling souper.
	 * @return either the return value of the super method or null if no super exists
	 */
	this.souper = function() {
		var superMethod = this.souper.caller.souper;
		return (superMethod) ? superMethod.apply( this, arguments ) : null;
	}

	/** Invokes the version of whatever method that is calling souper_ from
	 * the specified superclass.
	 * @return either the return value of the super method or null if no super exists
	 */
	this.souper_ = function( superclass ) {
		var superMethod = this[superclass.cname]._[this.souper_.caller.mname];
		var theArgs     = Array.prototype.slice.call(arguments,1);
		return (superMethod) ? superMethod.apply( this, theArgs ) : null;
	}

	/** Is "this" a descendent of the given class?.
	 * This implementation works with Gravey's multiple inheritence.
	 * @param {Function} aClass the class to verify
	 * @return true iff "this" is an "instanceof" aClass
	 */
	this.isInstanceOf = function( aClass ) {
		if (aClass.cname==null) return false;
		var m = this[ aClass.cname ];
		return( m && m instanceof Function );
	}
}


/**
 * This utility function sets up multiple "implements" inheritance
 * with all of the interfaces/classes passed in as parameters.
 * Multiple inheritance is implemented where method references
 * (either explicit or implicit-via-super) are resolved with
 * left-to-right precedence (with "Extends" superclass getting highest)
 * @see #Class
 * @see GrvObject
 * @author Bruce Wallace  (PolyGlotInc.com)
 * @version 2.2
 */
function grvImplements()
{
	///////////////////////////////////////////////////////////////////
	// NOTE: At this point each superClass should have already had its
	// own Class and Extends calls performed. I.E. always "declare"
	// superclasses BEFORE any classes that extend them.
	///////////////////////////////////////////////////////////////////
	var N = arguments.length;
	for (var i=0; i<N; ++i)
	  if (!arguments[i].baseClass)
	    throw "Undeclared Super Class in .Implements";

	var s, m, superExemplar;
	var         rawExemplar = this.rawExemplar;
	var            exemplar = this.prototype;

	//foreach superclass, zip together "souper" links
	//to each ORIGINAL subclass method not already souper-linked.
	//
	//I.E. foreach superclass,
	//  foreach method in RAW exemplar,
	//    if method in CURRENT exemplar doesnt already have a souper link
	//    then if method exists in current superclass exemplar
	//         then zip together "souper" reference
	for (var i=0; i<N; ++i)
	{
		superExemplar = arguments[i].prototype;
		for (var property in rawExemplar)
		{
			if (!(rawExemplar[property] instanceof Function)) continue;
			m =      exemplar[property];  if (m.souper) continue; //already linked!
			s = superExemplar[property];
			if (s && (s instanceof Function)) m.souper = s;
		}
	}

	//foreach superclass, copy into exemplar a reference
	//to each superclass method not already in exemplar
	for (var i=0; i<N; ++i)
	{
		superExemplar = arguments[i].prototype;
		for (var property in superExemplar)
		{
			s = superExemplar[property];
			if ( exemplar[property]===void 0 && s instanceof Function )
			     exemplar[property] = s;
		}
	}
}


/**
 * This utility function sets up single inheritance.
 * @param {Function} superClass the "superclass constructor" function
 * @return the "class object" (an extended Function object)
 * @author Bruce Wallace  (PolyGlotInc.com)
 * @version 2.2
 */
function grvExtends( superClass )
{
	///////////////////////////////////////////////////////////////////
	// NOTE: At this point superClass should have already had its own
	// Class and Extends calls performed. I.E. "declare" superclasses
	// BEFORE those classes that extend them.
	///////////////////////////////////////////////////////////////////
	if (!superClass.baseClass) throw "Undeclared Super Class in .Extends";

	//get superclass exemplar but avoid infinite recursion on implied root class
	var superexemplar = (this==GrvObject) ? null
					  : (superClass ? superClass.prototype : null);

	//Recall that one can't change the exemplar.__proto__ property directly
	//SO, one must create a new exemplar instance after baseClass.prototype is set.
	this.baseClass.prototype = superexemplar;
	var exemplar = new this.baseClass();

	//for each method in exemplar, if there is a different method with the
	//same name in superexemplar, setup the .souper link between them.
	//To support multiple inheritence disambiguation, save the method name too.
	var s,m;
	for (var property in exemplar)// iterate over all properties
	{
		m =      exemplar[property]; if (!(m instanceof Function)) continue;
		m.mname =         property;  if (! superexemplar         ) continue;
		s = superexemplar[property];
		if (s && (s!=m) && (s instanceof Function)) m.souper = s;
	}

	//Note that it would normally be a problem if Extends were called after
	//someone has already created an instance of "this" class (via new).
	//However, that situation should never occur since all the calls to Class()
	//and Extends() are normally done at web page load time, and application
	//logic should only start after the page "onload" event, hence all these
	//exemplars should be stable.
	this.prototype = exemplar;
	exemplar.name  = this.cname;//default value

	// while "souper" works with konstructor, some may still prefer to
	// use the superclass name explicitly when invoking its constructor
	// so we leave this in to continue support for that.
	if (exemplar.konstructor==null) exemplar.konstructor = function(){};
	exemplar[this.cname]   = exemplar.konstructor;
	// and it is required for multiple-inheritence to resolve ambiguity
	exemplar.konstructor._ = exemplar;
	//save the original (unextended) exemplar to support .Implements
	if (superClass==GrvObject) this.rawExemplar = exemplar;

	return this;
}


/**
 * Declare a class and create the glue objects and code
 * to allow "pretty" source; A mechanism is set up to insure
 * that required constructor parameters each have a defined value;
 * This function also defines the "name" attribute of the specified
 * class and initializes it with the class name.
 * @param {Function} theClass the "class constructor" function
 * @param {StringArray} optConstructorArgDescArray optional array
 * of strings describing required parameters for this class'
 * "constructor"; Note: Optional constructor parameters should
 * not be included in this array.
 * @return the "class object" (an extended Function object)
 * @type Function
 * @see #Extends
 * @see #grvValidateArgs
 * @see GrvObject
 * @author Bruce Wallace  (PolyGlotInc.com)
 * @version 2.2
 */
function Class( theClass, optConstructorArgDescArray )
{
	// The "class" as passed in will really be an abstract base class. We
	// will squirrel that away and replace theClass with a wrapper function
	// so that method source code is not copied into each object instance
	// as would otherwise be the case.
	var baseClass = theClass;

	// create the new wrapper function to replace theClass
	var  className  = grvFuncName( theClass );
	self[className] = theClass = function(){
		var C = arguments.callee;
		if (C.required && self["grvValidateArgs"]!==void 0)
		  grvValidateArgs( C.cname, C.required, arguments );
		C.prototype.konstructor.apply( this, arguments );
	}
	theClass.required  = optConstructorArgDescArray;
	theClass.cname     = className; //FYI,netscape&firefox break with ".name"
	theClass.baseClass = baseClass;
	theClass.Extends   = grvExtends;//so we can call as methods...
	theClass.Implements= grvImplements;
	theClass.Extends(GrvObject);	//required here even if overridden later
	return theClass;
}
