/*
	WaitIndicator
	-------------

Waiting indicator class to show/hide a visual "wait" indicator.
Useful for providing feedback when making AJAX calls.
Features multi-call support and a flicker removal logic.

Written by:
 Mikhail Diatchenko
 Nov 2007
 
Methods:
    [constructor(element)]  - creates an instance of the WaitIndicator using an 'element' as the visial indicator.
	enable()    - make an indicator visible. Every time it's call a counter is increased.
	disable()   - submits a "hide indicator" request. 
	                If counter is 0 (i.e. is multiple calls were made to enable(), then wait for the same number of
	                disable() calls to hide the indicator)
	forceDisable() - immediately hides the indicator.

Examples:

    var indicator = WaitIndicator(document.getElementById("pleaseWait"));
	
	document.onmousedown = function() { indicator.enable(); }
	document.onmouseup = function() { indicator.disable(); }

Compatibility:
 The functionality has been tested with the following browsers:
	IE 7 (WinXP)
	IE 6 (WinXP)
	Firefox 2.0.0.9 (WinXP)
*/

//this is required to callback functions. read http://www.snook.ca/archives/javascript/javascript_pass/ for more info.
if ( ! Function.prototype.bind ) {
    Function.prototype.bind = function( object ) {
        var __method = this;
        return function() {
            __method.apply( object, arguments );
        };
    };
}

function WaitIndicator(element) {
    this.element = element;
    this.counter = 0; //used to count number of time it was enabled in a session.
    this.enabled = false;
    this.timeout = 30; //in seconds.
    this.flickerThreshold = 500; //minimum number of milliseconds that should pass to make the indicator visible
    
    this._toggleCounter = 0; //used to count number of times it was shown (during page life).
    this._duration = -1;//number of milliseconds an indicator was visible
    this._timeEnabled = 0;
    
    this._timeoutId = 0;
    this._noFlickerTimeoutId = 0;
    
    this.enable = function() {
        this.counter++;
        if (this.counter==1) {
            this.enabled = true;
            this._timeEnabled = new Date().getTime();
        }
            
        //remove flicker
        if (this._duration>=0 && this._duration<this.flickerThreshold) {
            if (this.counter==1) {
                this._noFlickerTimeoutId = setTimeout(this._noFlicker.bind(this), this.flickerThreshold);
            }
            return;
        }
            
        this.element.style.display = "block";
        if (this.counter==1) {
            //start a timeout timer on first call to enable()
            this._timeoutId = setTimeout(this._timedOut.bind(this), this.timeout*1000);
            this._toggleCounter++;
        }
    }
    
    this.disable = function() {
        if (this.counter>0) {
            this.counter--;
            if (this.counter==0) {
                clearTimeout(this._noFlickerTimeoutId);
                this._duration = (new Date().getTime())-this._timeEnabled;
                this.forceDisable();
            }
        }
    }
      
    this.forceDisable = function() {
        this.counter=0;
        this.element.style.display = "none";
        this.enabled = false;
        clearTimeout(this._noFlickerTimeoutId);
        clearTimeout(this._timeoutId);
    }
    
    this._timedOut = function() {
        this.forceDisable();
    }
    
    this._noFlicker = function() {
        //falsely identified as flicker. show indicator
        this.element.style.display = "block";
        //start a timeout timer on first call to enable()
        this._timeoutId = setTimeout(this._timedOut.bind(this), this.timeout*1000);
        this._toggleCounter++;
    }
}

