//##############################################################################
// Class:       STACK
// Notes:       Used to manage message queues, each object used in the stack
//              should have a DESTROY method for clean up.
//
// Properties:  
//  aryItems                      - Array of data objects
//  aryKeys                       - Array of keys, 1:1 relationship to aryItems
//  strError                      - Last error message
//  
// Methods:
//  STACK( Constructor )
//  DESTROY ( Destructor )        - JS doesn't support destructors, you call it!
//  Error                         - Internal error handler
//  Find                          - Find item by key
//  Peek                          - Returns an item in the stack
//  Pop                           - Removes an item from the top of the stack
//  Push                          - Places an item on the top of the stack
//  Add                           - Add item to the end of the stack
//  Remove                        - Remove specific item from stack
//  Length                        - The number of items in the stack
//##############################################################################
// History:
//  23/09/08  SP, Created
//##############################################################################
function STACK( intCapLimit )
{
  this.aryItems    = null;
  this.aryKeys     = null;
  this.strError    = null;
  this.intCapLimit = intCapLimit;
}
//##############################################################################
// Method:      DESTROY
// Parameters:  None
// Notes:       Call this when you are finished with the object to cleanup
//##############################################################################
STACK.prototype.DESTROY = function()
{
  try { 
    if ( this.aryItems )
      {
      while ( this.Length() )
        this.Remove( this.aryKeys[0] );
      }
    this.aryItems = null;
    this.aryKeys  = null;
    this.strError = null;
  } catch( e ) {
    this.Error( "DESTROY:", e );
  }
}
//##############################################################################
// Method:      Error
// Parameters:  strMsg, the error messsage
//              Exception
//##############################################################################
STACK.prototype.Error = function( strMsg, Exception )
{
  this.strError = "STACK:" + strMsg;
  
  if ( Exception.message )
    this.strError += Exception.message;
  else
     this.strError += Exception;
  alert( this.strError );
}
//##############################################################################
// Method:      Pop
// Parameters:  None
// Notes:       Returns and removes the top most item from the STACK
//##############################################################################
STACK.prototype.Pop = function()
{
  try {
    if ( this.Length() == 0 )
      return null;
    if ( this.aryKeys && this.Length() != this.aryKeys.length )
      throw( "Mismatch in Items and Keys" );
    var objItem = this.aryItems[0];
    var aryNewItems = new Array();
    var aryNewKeys = new Array();
    var blnFirst = true;
    for( var i in this.aryItems )
      {
      if ( blnFirst == true )
        blnFirst = false;
      else
        {
        aryNewItems[aryNewItems.length] = this.aryItems[i];
        aryNewKeys[aryNewKeys.length] = this.aryKeys[i];
        }
      }
    this.aryItems = aryNewItems;
    this.aryKeys = aryNewKeys;
    return objItem;
  } catch( e ) {
    this.Error( "Pop:", e );
  }
}
//##############################################################################
// Method:      Push
// Parameters:  objItem, item to push onto the stack
//              strKey, unique key that identifies item
// Returns:     None
//##############################################################################
STACK.prototype.Push = function( objItem, strKey )
{
  try {
    if ( objItem == null )
      return;
    var aryNewItems = new Array();
    var aryNewKeys = new Array();
    aryNewItems[aryNewItems.length] = objItem;
    
    if ( strKey )
      aryNewKeys[aryNewKeys.length] = strKey;
    else
      {
      var intIdx = aryNewKeys.length;
      aryNewKeys[aryNewKeys.length] = intIdx;
      }
    if ( this.Length() == 0 )
      {
      this.aryItems = new Array();
      this.aryKeys = new Array();
      }
    else
      {
      for( var i in this.aryItems )
        {
        aryNewItems[aryNewItems.length] = this.aryItems[i];
        aryNewKeys[aryNewKeys.length] = this.aryKeys[i];
  // Has the cap limit been reached ?        
        if ( this.intCapLimit != null && aryNewItems.length == this.intCapLimit )
          break;
        }
      }        
    this.aryItems = aryNewItems;
    this.aryKeys = aryNewKeys;

    if ( this.Length() != this.aryKeys.length )
      throw( "Mismatch in Items and Keys" );
  } catch( e ) {
    this.Error( "Push:", e );
  }
}
//##############################################################################
// Method:      Add
// Parameters:  objItem, item to add to the stack
//              strKey, unique key that identifies item 
// Returns:     None
//##############################################################################
STACK.prototype.Add = function( objItem, strKey )
{
  try {
    if ( objItem == null )
      return;
    if ( this.Length() == 0 )
      {
      this.aryItems = new Array();
      this.aryKeys = new Array();
      }
    // Has the cap limit been reached ?        
    if ( this.intCapLimit != null && this.aryItems.length == this.intCapLimit )
      return;
    this.aryItems[this.aryItems.length] = objItem;
    
    if ( strKey )
      this.aryKeys[this.aryKeys.length] = strKey;
    else
      {
      var intIdx = this.aryKeys.length;
      this.aryKeys[this.aryKeys.length] = intIdx;
      }
    if ( this.Length() != this.aryKeys.length )
      throw( "Mismatch in Items and Keys" );
  } catch( e ) {
    this.Error( "Add:", e );
  }
}
//##############################################################################
// Method:      Remove
// Parameters:  strKey, key that identifies item to remove
// Returns:     None
//##############################################################################
STACK.prototype.Remove = function( strKey )
{
  try {
    if ( strKey == null )
      return;
    if ( this.aryKeys && this.Length() != this.aryKeys.length )
      throw( "Mismatch in Items and Keys" );
    var aryNewItems = new Array();
    var aryNewKeys = new Array();
    for( var i in this.aryItems )
      {
      if ( this.aryKeys[i] == strKey )
        {
        var objItem = this.aryItems[i];
        
        if ( objItem && objItem.DESTROY )
          {          
          objItem.DESTROY();
          objItem = null;
          }         
        delete this.aryKeys[i];   
        }
      else
        {
        aryNewItems[aryNewItems.length] = this.aryItems[i];
        aryNewKeys[aryNewKeys.length] = this.aryKeys[i];
        }              
      }
    this.aryItems = aryNewItems;
    this.aryKeys = aryNewKeys;
  } catch( e ) {
    this.Error( "Remove:", e );
  }
}
//##############################################################################
// Method:      Length
// Parameters:  None
// Returns:     Returns the number of items in the STACK
//##############################################################################
STACK.prototype.Length = function()
{
  try {
    if ( this.aryItems == null )
      return 0;
    return parseInt( this.aryItems.length, 10 );
  } catch( e ) {
    this.Error( "Length:", e );
  }
}
//##############################################################################
// Method:      Peek
// Parameters:  intIdx, the index of the item to take a look at
// Returns:     Returns the item specified by intIdx, does not remove from stack
//##############################################################################
STACK.prototype.Peek = function( intIdx )
{
  try {
    if ( intIdx < 0 || intIdx >= this.Length() )
      return null;
    return this.aryItems[intIdx];        
  } catch( e ) {
    this.Error( "Peek:", e );
  }  
}
//##############################################################################
// Method:      Find
// Parameters:  strKey, the key of the item to find
// Returns:     Returns the item specified by strKey, does not remove from stack
//##############################################################################
STACK.prototype.Find = function( strKey )
{
  try {
    if ( this.aryKeys == null || this.aryKeys.length == 0 )
      return null;
    if ( this.Length() != this.aryKeys.length )
      throw( "Mismatch in Items and Keys" );
    for( var i=0; i<this.aryItems.length; i++ )
      {
      if ( this.aryKeys[i] == strKey )
        return this.aryItems[i];
      }
  } catch( e ) {
    this.Error( "Find:", e );
  }
  return null;             
}
STACK.prototype.aryItems;
STACK.prototype.aryKeys;
STACK.prototype.strError;
STACK.prototype.intCapLimit;
