// Provide an implementation of the pop function if it doesn't
// already exist. For older browsers, Especially IE 5.2 For Mac
if (![].pop) {
   Array.prototype.pop = function () {
      var tempItem = this[this.length-1];
      this.length--;
      return(tempItem);
   };
}

// Provide an implementation of the push function if it doesn't
// already exist. For older browsers, Especially IE 5.2 For Mac
if (![].push) {
   Array.prototype.push = function () {
      this[this.length] = arguments[0];
      return(this.length);
   };
}

// Here is where we test for browser support for features.
function BrowserSupport() {
   this.strUserAgent = navigator.userAgent.toLowerCase();
   
   this.blnIsIE	 = ((this.strUserAgent.indexOf("msie") != -1) && (this.strUserAgent.indexOf("opera") == -1));
   this.blnIsOpera = (this.strUserAgent.indexOf("opera") != -1);
   this.blnIsMac   = (this.strUserAgent.indexOf("mac") != -1);
   this.blnIsMacIE = (this.blnIsIE && this.blnIsMac);
   this.blnIsWinIE = (this.blnIsIE && !this.blnIsMac);
   this.blnIsGecko = (navigator.product == "Gecko");
   this.blnIsKHTML = (this.strUserAgent.indexOf("khtml") != -1);
   
   if ( this.blnIsKHTML ) {
      this.strBrowserName = 'KHTML';
   } else if ( this.blnIsGecko ) {
      this.strBrowserName = 'Gecko';
   } else if ( this.blnIsWinIE ) {
      this.strBrowserName = 'WinIE';
   } else if ( this.blnIsMacIE ) {
      this.strBrowserName = 'MacIE';
   } else if ( this.blnIsOpera ) {
      this.strBrowserName = 'Opera';
   } else {
      this.strBrowserName = 'Unknown';
   }
   
   this.blnHasImageObj      = (document.images?true:false);
   // NOTE: IE for Mac doesn't support the W3C DOM and DHTML well enough. Too many crashes.
   this.blnHasDHTMLSupport  = ((document.getElementById || document.all || document.layers) && !this.blnIsMacIE?true:false);
   this.blnHasW3CDOMSupport = (document.getElementById && document.createElement && !this.blnIsMacIE?true:false);
};

// For easy display of browser features.
BrowserSupport.prototype.toString = function() {
   var output = "";
   
   output += "User Agent: "+this.strUserAgent+"\n";
   output += "\n";
   output += "Is IE: "+this.blnIsIE+"\n";
   output += "Is Opera: "+this.blnIsOpera+"\n";
   output += "Is Mac: "+this.blnIsMac+"\n";
   output += "Is Mac IE: "+this.blnIsMacIE+"\n";
   output += "Is Win IE: "+this.blnIsWinIE+"\n";
   output += "Is Gecko: "+this.blnIsGecko+"\n";
   output += "Is KHTML: "+this.blnIsKHTML+"\n";
   output += "\n";
   output += "Has Image Obj: "+this.blnHasImageObj+"\n";
   output += "Has DHTML Support: "+this.blnHasDHTMLSupport+"\n";
   output += "Has W3C DOM Support: "+this.blnHasW3CDOMSupport+"\n";
   
   return output;
}
Global_BrowserSupport = new BrowserSupport();
// Debuggin
//alert(Global_BrowserSupport);

// TimerManager: This class manages timers in a cross browser manner.
// The only cross browser manner that works is setInterval Timeout
// with evaluated text strings. So we expect a global instance of
// this class, which keeps track of the timers and is called
// for each timer to actually start execution.
//
// We Try to support 2 calling conventions, each with and without arguments.
// Global Function: Assumes funciton name passed is a global function.
// Class Method: Uses Given Class instance (FunctionOwner) and calls the method
// using it as the object to call with.
function TimerManager() {
   this.timers = new Array();
   
   // Debuggin
   /*var win = window.open('','TimerList',"width="+900+",height="+300+",top="+0+",left="+0+
                         ",menubar=no,toolbar=no,location=center,scrollbars=yes"+
                         ",resizable=yes,status=no,location=no'");
   win.document.write('');
   for( var i = 0; i < this.timers.length; i++) {
      if(this.timers[i]['Interval']!=null) {
         win.document.write('Index: '+i+'<br />');
         win.document.write('Interval: '+this.timers[i]['Interval']+'<br />');
         win.document.write('Function: '+this.timers[i]['Function']+'<br />');
         win.document.write('Arguments: '+this.timers[i]['Arguments']+'<br />');
         win.document.write('FunctionOwner: '+this.timers[i]['FunctionOwner']+'<br />');
         win.document.write('Reoccuring: '+this.timers[i]['Reoccuring']+'<br />');
         win.document.write('ID: '+this.timers[i]['ID']+'<br />');
      }
   }
   win.document.close();*/
};

// Start: This function registers the supplied function, possible arguments,
// and possible owning object in our array. Then it sets the javascript
// timer to call it at the specified interval. 
TimerManager.prototype.Start = function(iInterval, blnReoccuring, strFunction, objArguments, objFunctionOwner) {
   
   // The function name, and the interval are required.
   // The arguments and function owner can be skipped.
   if(typeof strFunction == "undefined" || typeof strFunction != "string")
      return;
   if(typeof iInterval == "undefined" )
      return;
   if(typeof objArguments == "undefined" )
      objArguments = null;
   if(typeof objFunctionOwner == "undefined" )
      objFunctionOwner = null;
           
   var iIndex = this.timers.push( new Array() );
   this.timers[iIndex-1]['Interval'] = iInterval;
   this.timers[iIndex-1]['Function'] = strFunction;
   this.timers[iIndex-1]['Arguments'] = objArguments;
   this.timers[iIndex-1]['FunctionOwner'] = objFunctionOwner;
   this.timers[iIndex-1]['Reoccuring'] = blnReoccuring;
   
   if(blnReoccuring) {
      this.timers[iIndex-1]['ID'] = setInterval("Global_TimerManager.Call("+(iIndex-1)+");",iInterval);
   } else {
      this.timers[iIndex-1]['ID'] = setTimeout("Global_TimerManager.Call("+(iIndex-1)+");",iInterval);
   }
   
   // Debuggin
   /*var win = window.open('','TimerList',"width="+900+",height="+300+",top="+0+",left="+0+
                         ",menubar=no,toolbar=no,location=center,scrollbars=yes"+
                         ",resizable=yes,status=no,location=no'");
   win.document.write('');
   for( var i = 0; i < this.timers.length; i++) {
      if(this.timers[i]['Interval']!=null) {
         win.document.write('Index: '+i+'<br />');
         win.document.write('Interval: '+this.timers[i]['Interval']+'<br />');
         win.document.write('Function: '+this.timers[i]['Function']+'<br />');
         win.document.write('Arguments: '+this.timers[i]['Arguments']+'<br />');
         win.document.write('FunctionOwner: '+this.timers[i]['FunctionOwner']+'<br />');
         win.document.write('Reoccuring: '+this.timers[i]['Reoccuring']+'<br />');
         win.document.write('ID: '+this.timers[i]['ID']+'<br />');
      }
   }
   win.document.close();*/
   return this.timers[iIndex-1]['ID'];
};

// Stop: This function unregisters a timer setup to continually call a function
// created with the SetInterval function.
TimerManager.prototype.Stop = function(iID) {
   for(var i = 0; i < this.timers.length; i++) {
      if(this.timers[i]['ID'] == iID) {
         if(this.timers[i]['Reoccuring']) {
            clearInterval(iID);
         } else {
            clearTimeout(iID);
         }
         this.timers[i]['Interval'] = null;
         this.timers[i]['Function'] = null;
         this.timers[i]['Arguments'] = null;
         this.timers[i]['FunctionOwner'] = null;
         this.timers[i]['Reoccuring'] = null;
         this.timers[i]['ID'] = null;
         break;
      }
   }
   
   // Debuggin
   /*
   var win = window.open('','TimerList',"width="+900+",height="+300+",top="+0+",left="+0+
                         ",menubar=no,toolbar=no,location=center,scrollbars=yes"+
                         ",resizable=yes,status=no,location=no'");
   win.document.write('');
   for( var i = 0; i < this.timers.length; i++) {
      if(this.timers[i]['Interval']!=null) {
         win.document.write('Index: '+i+'<br />');
         win.document.write('Interval: '+this.timers[i]['Interval']+'<br />');
         win.document.write('Function: '+this.timers[i]['Function']+'<br />');
         win.document.write('Arguments: '+this.timers[i]['Arguments']+'<br />');
         win.document.write('FunctionOwner: '+this.timers[i]['FunctionOwner']+'<br />');
         win.document.write('Reoccuring: '+this.timers[i]['Reoccuring']+'<br />');
         win.document.write('ID: '+this.timers[i]['ID']+'<br />');
      }
   }
   win.document.close();*/
};

// Call: This function actually calls the function registered with
// the corresponding index, in the proper way.
//
// We Try to support 2 calling conventions, each with and without arguments.
// Global Function: Assumes funciton name passed is a global function.
// Class Method: Uses Given Class instance (FunctionOwner) and calls the method
// using it as the object to call with.
TimerManager.prototype.Call = function(iIndex) {

   if(this.timers[iIndex]['Function'] == null ||
      this.timers[iIndex]['Interval'] == null ||
      this.timers[iIndex]['Reoccuring'] == null   ) {
      return;
   }
   var strFunction = this.timers[iIndex]['Function'];
   var objArguments = this.timers[iIndex]['Arguments'];
   var objFunctionOwner = this.timers[iIndex]['FunctionOwner'];
   
   // Class Method: call with function owner as the object
   if(objFunctionOwner) {
      if(objArguments) {
         objFunctionOwner[strFunction](objArguments);
      } else {
         objFunctionOwner[strFunction]();
      }
   // Global Function: simply call the global function
   } else {
      if(objArguments) {
         eval(strFunction+"(objArguments);");
      } else {
         eval(strFunction+"();");
      }
   }
   
   // Clear out references for one-use timers. This ensures a proper clean up.
   if(!this.timers[iIndex]['Reoccuring']) {
      this.timers[iIndex]['Interval'] = null;
      this.timers[iIndex]['Function'] = null;
      this.timers[iIndex]['Arguments'] = null;
      this.timers[iIndex]['FunctionOwner'] = null;
      this.timers[iIndex]['Reoccuring'] = null;
   }
   
   // Debuggin
   /*var win = window.open('','TimerList',"width="+900+",height="+300+",top="+0+",left="+0+
                         ",menubar=no,toolbar=no,location=center,scrollbars=yes"+
                         ",resizable=yes,status=no,location=no'");
   win.document.write('');
   for( var i = 0; i < this.timers.length; i++) {
      if(this.timers[i]['Interval']!=null) {
         win.document.write('Index: '+i+'<br />');
         win.document.write('Interval: '+this.timers[i]['Interval']+'<br />');
         win.document.write('Function: '+this.timers[i]['Function']+'<br />');
         win.document.write('Arguments: '+this.timers[i]['Arguments']+'<br />');
         win.document.write('FunctionOwner: '+this.timers[i]['FunctionOwner']+'<br />');
         win.document.write('Reoccuring: '+this.timers[i]['Reoccuring']+'<br />');
         win.document.write('ID: '+this.timers[i]['ID']+'<br />');
      }
   }
   win.document.close();*/
};

// Our Global Instance of the Timer Manager.
var Global_TimerManager = new TimerManager();