/**
 * Notifies the user that the session is about to close.
 * Redirects the user to a view after countdown (optional).
 *
 * Creates a document.sessionSupervisor, which is deleted onBeforeUnload.
 *
 * Requires JQuery.
 *
 * Define before this js-file:
 * - document.SESSION_MAX_INACTIVE_INTERVAL = [some number]
 *
 * @author heikkim
 */
function SessionSupervisor() {
    /*
     * CONFIGURABLE VARS
     *
     * - define either notifyBeforeSessionClosePercent or notifyTimeout. notifyTimeout overrides.
     */
    this.notifyBeforeSessionClosePercent = 90; // 3600s - (3600s * 0,90) = 360s = 6min | meaning: show notice 6 minutes before invalidation.
    this.notifyBeforeSessionCloseSecond = 300; // meaning: show notice 5 minutes before invalidation, overrides percent-definition.
    this.showElementJqSelector = 'div#sessionSupervisorNotification';
    this.oneMinuteSafetyCheck = false;
    this.afterCountdownRedirectTo = root + '/login/auth/?reason=sessionTimeout';

    this.DEBUG = false;
    this.FUNCTIONAL = document.SESSION_MAX_INACTIVE_INTERVAL != undefined && document.SESSION_MAX_INACTIVE_INTERVAL != '';

    /*
     * NON-CONFIGURABLE VARS
     */
    this.timeOutVars = [];
    this.intervalVars = [];
    this.sessionTimeout = null;
    this.counter = null;
    this.notificationVisible = false;
    this.timeToNotification = null;

    this.start = function() {
         if(this.DEBUG) {
            alert('Begin start()');
        }

        if(!this.FUNCTIONAL) {
             if(this.DEBUG) {
                alert('SessionSupervisor non-functional.');
            }

            return false;
        }

        if(this.afterCountdownRedirectTo != null && this.afterCountdownRedirectTo.indexOf(document.location.pathname) > -1) {
            if(this.DEBUG) {
                alert('Cancel start(), redirect address is current address.');
            }

            return false;
        }

        try {
            if(('' + (typeof document.SESSION_MAX_INACTIVE_INTERVAL)).toLowerCase() == 'string') {
                this.sessionTimeout = parseInt(document.SESSION_MAX_INACTIVE_INTERVAL, 10);
            } else {
                this.sessionTimeout = document.SESSION_MAX_INACTIVE_INTERVAL;
            }

            this.sessionTimeout *= 1000;

            this.counter = this.sessionTimeout;

            if(this.timeToNotification == null) {
                if(this.notifyBeforeSessionCloseSecond != null) {
                    this.timeToNotification = this.sessionTimeout - (this.notifyBeforeSessionCloseSecond * 1000);
                }  else {
                    this.timeToNotification = Math.floor(this.sessionTimeout * (this.notifyBeforeSessionClosePercent / 100));
                }
            }

            if(this.oneMinuteSafetyCheck) {
                if(this.timeToNotification < 60000) {
                     this.timeToNotification =  60000;
                }
            }

            if(this.DEBUG) {
                alert('this.timeToNotification: ' + this.timeToNotification + '\nthis.counter: ' + this.counter);
            }

            this.timeOutVars['notifyUser'] = setTimeout("if(document.sessionSupervisor){document.sessionSupervisor.notifyUser();}", this.timeToNotification);
            this.intervalVars['decreaseCounterByOne'] = setInterval("if(document.sessionSupervisor){document.sessionSupervisor.decreaseCounterByOne('s');}", 1000);
        } catch(e) {
                if(this.DEBUG) {
                    alert(e.message);
                }
            return false;
        }
    };

    this.decreaseCounterByOne = function(unit) {
        if(!unit) {
            unit = 'sec';
        }

        switch(unit) {
            case 's':
            case 'sec':
                this.counter -= 1000;
                break;
        }

        if(this.counter < 1) {
            this.counter = 0;
            clearInterval(this.intervalVars['decreaseCounterByOne']);
        }
    };

    this.notifyUserAlertedCountInDebug = 0;
    this.notifyUser = function() {
        if(this.DEBUG && this.notifyUserAlertedCountInDebug++ < 3) {
            alert('Begin notifyUser()');
        }

        try {
            var e = jQuery(this.showElementJqSelector);
            var countDownElement = e.find('span.counter');
            var curCounter = this.counter;

            if(countDownElement && countDownElement.length > 0 && curCounter > -1) {
                countDownElement.html('' + (this.formatTime(curCounter)));

                if(curCounter < 60000 && countDownElement.css('color') != '#e11') {
                    countDownElement.css('color', '#e11');
                }
            }

            if(!this.notificationVisible || e.css('display') == 'none') {
                e.slideDown('slow');
                this.notificationVisible = true;
            }

            if(curCounter > 0) {
                if(this.timeOutVars['notifyUser']) {
                    try {
                        clearTimeout(this.timeOutVars['notifyUser']);
                    } catch(e) {
                        // IGNORE
                    }
                }
                this.timeOutVars['notifyUser'] = setTimeout("if(document.sessionSupervisor){document.sessionSupervisor.notifyUser();}", 1000);
            } else {
                var notice = jQuery('<span/>').html('<br />' + messages.javascript.session.expiration.redirecting());
                e.find('p.message').append(notice);
                setTimeout("window.location.href = '" + this.afterCountdownRedirectTo + "'", 1500);
            }

        } catch(e) {
            if(this.DEBUG) {
                alert(e.message);
            }
        }
    };

    this.stop = function() {
         if(this.DEBUG) {
            alert('Begin stop()');
        }

        if(this.FUNCTIONAL && this.sessionTimeout != null) {
            try {
                var i = 0;

                try {
                    // for IE
                    clearInterval(this.intervalVars['decreaseCounterByOne']);
                    clearTimeout(this.timeOutVars['notifyUser']);
                } catch(e) {
                    // IGNORE
                }

                for(i = 0; i < this.timeOutVars.length; i++) {
                    try {
                        clearTimeout(this.timeOutVars[i]);
                    } catch(e) {
                        // IGNORE
                    }
                }

                for(i = 0; i < this.intervalVars.length; i++) {
                    try {
                        clearInterval(this.intervalVars[i]);
                    } catch(e) {
                        // IGNORE
                    }
                }

                var e = jQuery(this.showElementJqSelector);
                var countDownElement = e.find('span.counter');
                var curCounter = this.sessionTimeout;

                if(countDownElement && countDownElement.length > 0 && this.counter > 1) {
                    countDownElement.html('' + (this.formatTime(curCounter)));
                    countDownElement.css('color', '#0d0');
                }
            } catch(e) {
                if(this.DEBUG) {
                    alert(e.message);
                }
            }

            return true;
        }
    };

    this.formatTime = function(millis) {
        if(!millis) {
            return '0s';
        }

        var secs = millis / 1000;
        var mins = Math.floor(secs / 60);
        var hours = Math.floor(mins / 60);

        mins = Math.floor(mins % 60);
        secs = Math.floor(secs % 60);

        var ret = '';

        if(hours > 0) {
            ret += hours + 'h';
        }

        if(mins > 0 || hours > 0) {
            ret += ' ' + mins + 'm';
        }

        if(secs > 0 || mins > 0) {
            ret += ' ' + secs + 's';
        }

        if(ret == '') {
            ret = '0s';
        }

        return ret.replace(/^\s+|\s+$/g, '');
    };
}

if(jQuery) {
    /* Start the service */
    jQuery(document).ready(function() {
        document.sessionSupervisor = new SessionSupervisor();
        document.sessionSupervisor.start();
    });

    /* Prepare stop and deletion for unload */
    jQuery(window).bind("beforeunload", function() {
        if(document.sessionSupervisor) {
            try {
                document.sessionSupervisor.stop();
                delete document.sessionSupervisor;
            } catch(e) {
                if(this.DEBUG) {
                    alert(e.message);
                }
            }
        }
    });    
}
