   /*    Fixed: the STACK bug 
         A first attempt at a Javascript Collections Framework modeled after the java.util package.
         Classes currently supported are:

            Class                   Methods
            ---------------------------------------------------------------------------------------------
            HashMap                keys(), values(), get(key), put(key, value), size(), isEmpty(), clear(), 
                                   remove(key), containsKey, toString

            ArrayList              values(), get(i), add(value), size(), isEmpty(), clear(), addAll(list)
                                   remove(i), contains(value), indexOf(value), reverse(), sort(), toString();

            Stack                 extends ArrayList + 2 methods (pop() & push(value));                                     

            Queue                 extends ArrayList + 2 methods (enqueue(value) & dequeue());                                     
            ---------------------------------------------------------------------------------------------

        
     You can put custom Javascript objects in these collections, the only requirement being that your custom object
     inherit from the CustomJSObject class below. Let say you have a Person class.

     function Person(id, name, ssn) {
        this.id = id;
        this.name = name;
        this.ssn = ssn;
     }
     
     to make it inherit CustomJSObject add the following line below,

     Person.prototype = new CustomJSObject;

     Now your Person object will inherit an Equals(..) method whose default implementation is given in the CustomJSObject class.
     You can override this. So for the Person object two Person's are equal if they have same SSN.

     function Person(id, name, ssn) {
        this.id = id;
        this.name = name;
        this.ssn = ssn;
        this.Equals = function (thatPersons) { return this.ssn = thatPersons.ssn; }
     }
     
     Now that your Person object inherits the CustomJSObject, the collection classes will use the Equals(..) method
     defined above to identify this object in a collection. 

     If your custom object does not inherit CustomJSObject then the "==" operator will be used for determining object
     equality.

     DISCLAIMER: This is work in progress. Haven't tested this on older versions of Netscape or IE. Open to suggestions and bug fixes.

   */
   //////////////////////////////////  UTILITY //////////////////////////////////  

    function CustomJSObject() {        
        this.Equals         = function (thatObject) {  return this == thatObject; }; 
        this.toString       = function ()           { return this; }; 
    }
    
    function isCustomObject (thatObject) {                
            return CustomJSObject.prototype.isPrototypeOf(thatObject);
    }
    
    function areEqual (x, y) {
            if (isCustomObject (x) && isCustomObject (y)) {                
                return x.Equals(y);
            } else {                
                return x == y;
            }
     }    

    function indexOf (zarray, y) {
          for (var i =0; i < zarray.length; ++i) {
                x = zarray[i];
                if (areEqual (x, y)) {
                    return i;
                }
          }
          return -1;
     } 

    //////////////////////////////////  HASHMAP //////////////////////////////////  

    /**
        This class is not a 'true' HashMap but I decided to keep that name so that Java prorgammers can relate to it.
    */
    function HashMap() {     
     this._values     = new Array();
     this._keys       = new Array();
     this.keys        = function() { return this._keys; }
     this.values      = function() { return this._values; }
     this.size        = function() { return this._keys.length;      };
     this.isEmpty     = function() { return this._keys.length == 0; };
     this.clear       = HashMap_clear;
     this.put         = HashMap_put; 
     this.get         = HashMap_get;
     this.remove      = HashMap_remove;
     this.containsKey = HashMap_containsKey;
     this.toString    = HashMap_toString;
    }

    function HashMap_remove(key) { 

        var i = indexOf (this._keys, key);
        if (i >= 0) {
                this._keys.splice(i,1);
                temp = this._values[i];
                this._values.splice(i,1);
                return temp;
         }    
        return null;
    }


    function HashMap_clear () {  
        this._keys = new Array();
        this._values = new Array();
    }

    function HashMap_get(key) {  

        var i = indexOf (this._keys, key);    
        if (i >= 0) return  this._values[i];
        return null;
    }

    function HashMap_put (key, value) {  
        if (key == null) {
            alert ("Cannot put null key in HashMap");
            return;
        }
        if (!this.containsKey (key)) {
            this._keys.push(key);
            this._values.push(value);
            return null;
        } else {
            var i = indexOf(this._keys, key);
            temp = this._values[i];
            this._values[i] = value;
            return temp;
        }
    }

    function HashMap_containsKey (key) {        

        var i = indexOf(this._keys, key);
        return (i >= 0);
    }

    function HashMap_toString() {    
        var s = "[";
        for(i =0; i < this._keys.length; ++i) {
           s += "{"+this._keys[i]+","+this._values[i]+"} "; 
        }
        s += "]";
        return s;
    }

    //////////////////////////////////  ARRAYLIST //////////////////////////////////  

    function ArrayList() {     
     this._values     = new Array();
     this.values      = function() { return this._values; }
     this.reverse     = function() { return this._values.reverse(); }
     this.sort        = function() { return this._values.sort(); }
     this.size        = function() { return this._values.length;      };
     this.isEmpty     = function() { return this._values.length == 0; };
     this.clear       = function () { this._values = new Array(); }
     this.add         = function (key) { this._values.push(key); };       
     this.addAll      = ArrayList_addAll;
     this.get         = function (i) { return this._values[i]; };
     this.remove      = function (i) { return this._values.splice(i,1); };
     this.contains    = ArrayList_contains;
    
     this.indexOf     = ArrayList_indexOf;
     this.toString    = ArrayList_toString;
    }

    function ArrayList_indexOf(key) { 
        return indexOf(this._values, key);
    }

    function ArrayList_addAll(list) { 
        var x = list.values();
        if (x) {        
            for (i = 0; i < this._values.length; ++i) this._values.pop();        
            this._values = this._values.concat(list.values());
        }       
    }

    function ArrayList_contains(key) {    
	  if (this._values.length == 0) return false; 	
        return (indexOf(this._values, key) >= 0);    
    }

   

    function ArrayList_toString() {    
        var s = "[";
        for(i =0; i < this._values.length; ++i) {
           s += this._values[i]+","; 
        }
        s += "]";
        return s;
    }

    //////////////////////////////////  STACK //////////////////////////////////  

    function Stack() {
       this._values = new Array(); 
       this.pop  = Stack_pop;
       this.push = Stack_push; 
    }

    function Stack_pop() {
        if (this._values.length == 0) return null;
        var tmp = this._values[0];
        this._values.splice(0, 1);
        return tmp;
    }
    function Stack_push(a) {

        var oldValues = new Array();
        for (var i =0; i < this._values.length; ++i) {
          oldValues.push(this._values[i]);
        }

        this._values = new Array();
        this._values.push(a);
        for (var i =0; i < oldValues.length; ++i) {
          this._values.push(oldValues[i]);
        }
    }

    Stack.prototype = new ArrayList;

    //////////////////////////////////  QUEUE //////////////////////////////////  

    function Queue() {
       this._values = new Array(); 
       this.enqueue  = function(a) { this._values.push(a); } 
       this.dequeue  = function()  { temp = this._values[0]; this._values.splice(0,1); return temp; } 
    }
    Queue.prototype = new ArrayList;
