/*--------------------------------------------------------------------------
 *  sabinos.Timer , version 0.1
 *  (c) 2008 Felipe Sabino
 *
 *  http://www.sabinos.net
 *  sabinosfelipe@gmail.com
 *
 * This code is under GNU General Public License (GPL) http://www.gnu.org/licenses/gpl-3.0.txt
 *
 *--------------------------------------------------------------------------*/

if(Object.isUndefined(sabinos) || sabinos == null)
    var sabinos = {}; //defines 'sabinos' 'namespace'

sabinos.Timer = Class.create();

sabinos.Timer.prototype = {
          initialize: function(options) {
            this.Options = Object.extend({
                Interval: 1,                        //default interval (seconds)
                AutoReset: false,                   //if timer should be started again after elapsed
                Loops: -1,                          //number of loops for timer repeat. -1 if repeat forever
                Started: Prototype.emptyFunction,   //function fired each time timer is started
                Stoped: Prototype.emptyFunction,    //function fired each time timer is stoped
                Reseted: Prototype.emptyFunction,   //function fired each time timer is reseted
                Elapsed: Prototype.emptyFunction    //function fired each time timer is elapsed
            }, options || {});
            this.timer = null;                      //used to hold current timer id
            this.lastStartTime = null;              //used to hold the first time stamp for start method
            this.LoopsCompleted = 0;                //set amount of completed loops to 0
            this.IsRunning = false;                 //indicates if timer is running
            this.IsEnabled = true;                    //indicates if the timer is enabled and will call Elapsed function
          },
          start: function(resetLoopsCompleted, resetElapsedTime){
            //if timer was running before, clean it up.
            if(this.timer!=null)
                window.clearTimeout(this.timer); 
            reseted = false;
            if(arguments.length>2)
                reseted = arguments[2];           
            this.IsRunning = true;
            //Reset Loops completed
            if(resetLoopsCompleted || resetLoopsCompleted == null)
                this.LoopsCompleted=0;
            //reset elapsed time
            if(resetElapsedTime || resetElapsedTime == null || this.lastStartTime==null || !this.IsRunning)
                this.lastStartTime = new Date();
            //start native timeout event to fire the timer elapsed method
            this.timer = window.setTimeout(this.elapsed.bind(this), this.Options.Interval * 1000); 
            //Invoke Started event
            if(!reseted)
                this.invoke(this.Options.Started);
          },
          stop: function(){
            if(this.timer != null)
            {
                this.IsRunning = false;
                window.clearTimeout(this.timer);    //stop timer
                this.timer==null;                   //clear timer
            }
            //Invoke Stoped event
            this.invoke(this.Options.Stoped);

          },
          elapsed: function(){                      //raised when timer is elapsed
            if(this.Options.AutoReset){
                if((this.Options.Loops == -1 || this.LoopsCompleted <= this.Options.Loops) && this.IsEnabled){ //check if repeat forever or if loops completed is smaller than the total number of loops
                    this.LoopsCompleted++;
                    this.invoke(this.Options.Elapsed);
                    if(this.LoopsCompleted == this.Options.Loops)
                        this.stop();                    //stop timer
                    else
                        this.reset(false, false);                   //start timer again
                }
                else
                    this.reset(false,false);
            } else {
                this.invoke(this.Options.Elapsed);
                this.stop();
            }
          },
          invoke: function(functionToInvoke){                       //invoke function asynchronously
            if(typeof(functionToInvoke)=='function')
            {
                if(functionToInvoke != Prototype.emptyFunction && this.IsEnabled)
                    window.setTimeout(functionToInvoke,0);          //execute timer function provided
            }
            else if(typeof(functionToInvoke)=='undefined')
                throw 'sabinos.Timer Exception. Argument provided is undefined.';
            else
                throw 'sabinos.Timer Exception. Argument provided is not a function.';

          },
          reset: function(resetLoopsCompleted, resetElapsedTime){
            this.start(resetLoopsCompleted, resetElapsedTime, true);
            //Invoke Started event
            this.invoke(this.Options.Reseted);
          },
          getElapsed : function(){                  //return Elapsed Time (seconds) since first start or reset.
            if(this.lastStartTime!=null)
                return (new Date() - this.lastStartTime)/1000;
            else
                return 0;
          }
};