
/**
   namespace ispect - tools to provide high level constructs through
      introspection

   The function used to wrap the namespace accepts a single argment: this
   should be the global "this" object, which is the global context.  It is
   used to construct the import functionality.
 */
function ispect(globals) {

   /**
     imports a set of names from a namespace.  Namespaces are just objects.

     Note that this only imports into the global context - to import privately
     into another namespace, you need to assign the thing you are importing to
     a variable:

      // import the symbol "foo" from the namespace "ns"
      var foo = ns.foo;
 
     namespace: The object from which to import the names.
     names (optional): A list of strings indicating the names to be imported.
	If not provided, _all_ names are imported.
   */
   this.importNames = function (namespace, names) {
      if (!names) {
	 // the user didn't provide any names to import - build a list of all
	 // names in the namespace
	 names = [];
	 for (var name in namespace)
	    names.push(name);
      }

      // import the names by assigning them to the global context ("this")
      for (var i in names) {
	 var name = names[i];
	 if (namespace[name] == undefined)
	    throw 'Attempted to import undefined symbol ' + name;
	 globals[name] = namespace[name];
      }
   }

   /**
      private class SuperWrapper 

      constructor for an object that wraps a superclass.  Uses the "getter"
      mechanism to create "superclass methods" (methods of the base class
      which are bound to an instance of a derived class).
    */
   function SuperWrapper(base) {
      
      // returns a function that is bound to an instance - calling the
      // returned function will be the equivalent of "inst.func(...)"
      function bind(func, inst) {
	 return function () { return func.apply(inst, arguments); }
      }

      // function to return a "getter" that returns a superclass method that
      // has been bound to an instance
      function getterMaker(key) {
	 return function () { return bind(base[key], this._ispect_inst); }
      }

      // create properties for each method in the base class
      for (var key in base) {
	 if (typeof(base[key]) == 'function')
	    this[key] getter = getterMaker(key);
      }
   }

   /**
      returns a normalized class object constructor. 
      
      "base" is the base class (undefined if there is no base class).
	 Ordinary classes may be used.
      "body" is a function whose body corresponds to the body of the class.
	 the "this" within the scope of the function is the class object, not
	 the instance.  Create public functions by assigning functions to 
	 instance variables.

      The following special variables are used by this system:

      _ispect_class - attached to an instance to keep track of its class
         object.
      _ispect_super - attached to an instance, caches the super class binding
	 object for the instance (created upon invocation of the first super
	 class method).
      _ispect_base - attached to a class object to references its base class
	 object.  Only used if a base class is provided.
      _ispect_baseWrapper - attached to a class object, holds the super class
	 binding function, which creates an object containing the instance 
	 whose prototype will be the SuperWrapper for the base class.  Only
	 used if a base class is provided.
      _ispect_inst - attached to the super class binding object (per
	 instance).

      In general, instance variables beginning with "_ispect_" are reserved
      and should be avoided.

    */
   this.makeClass = function (base, body) {
      // make the base class our prototype - "base" will be a construction
      // function, so we obtain it's prototype which will be our "class
      // object".
      if (base)
	 body.prototype = base.prototype;

      // instantiate the class
      var classObj = new body;

      // add the _ispect_base variable to the class object
      if (base) {
	 classObj._ispect_base = base.prototype;

	 // create a generic super-wrapper for the class
	 superWrapper = new SuperWrapper(base.prototype);

	 // create a base wrapper which uses it as a prototype - this provides
	 // the getters of the super-wrapper with an instance to bind to
	 // superclass methods
	 classObj._ispect_baseWrapper = function BindingSuperWrapper(inst) {
	    this._ispect_inst = inst;
	 }
	 classObj._ispect_baseWrapper.prototype = superWrapper;

	 // give the class a superclass method if it hasn't inherited one from
	 // the base class
	 if (!classObj.superclass) {
	    classObj.superclass = function() {
	       if (!this._ispect_super) {
		  this._ispect_super = new this._ispect_baseWrapper(this);
	       }
	       return this._ispect_super;
	    }
	 }
      }

      // define a generic constructor
      function constructor() {
	 // assign our _ispect_class variable
	 this._ispect_class = classObj;

	 this.init.apply(this, arguments);
      }
      constructor.prototype = classObj;

      // ... and return it!
      return constructor;
   }
};
var ispect = new ispect(this);

