
function ProgressDisplay()
{
    var $waitCursorHtml;
    var timerCursor;
    var disabled = false;
    var waitShowingSince = -1;
    var userCanCancelAfter = 10000;
    var waitAllowCancel;

    var waitShowingDelay = 3000;
    var timerProgressDisplay;

    var waitCursorEnabled= true;
    var immediateDisplayMode;

    function provideWaitCursorHtml()
    {
        if ( !waitCursorEnabled )
            return false;

        if ( $waitCursorHtml !== undefined )
            return true;

        $waitCursorHtml = $("<div class='wc-ProgressDisplayCursor' style='display:none'/>");
        $(document.body).append($waitCursorHtml);

        return true;
    }

    function refreshCursorPosition(e)
    {
        if ( !provideWaitCursorHtml() )
            return;

        $waitCursorHtml.css("top", e.pageY );
        $waitCursorHtml.css("left", e.pageX );
    }

    function showCursor()
    {
        if ( !provideWaitCursorHtml() )
            return;

        //add listener to refresh logo position
        var $poselem = $();
        $poselem.pageX = webcore.getMousePosX();
        $poselem.pageY = webcore.getMousePosY();
        refreshCursorPosition($poselem);
        $(document).bind("mousemove.progressDisplayCursor", refreshCursorPosition);
        timerCursor = setTimeout( function()
        {
            $waitCursorHtml.fadeIn(500);
        }, 750 );
    }

    function showImmediately( allowCancel )
    {
        if ( disabled )
            return;
        showCursor();

        if ( allowCancel == undefined )
            allowCancel = true;

        waitAllowCancel = allowCancel;
        timerProgressDisplay = null;
        var $progressDisplayHtml = $( '#progressDisplayContainer' );
        if ($progressDisplayHtml.length == 1)
        {
            $progressDisplayHtml.css( 'visibility', 'visible' );
            updateDimension();
            waitShowingSince = new Date().getTime();
        }
    }

    function showDelayed( allowCancel, delay )
    {
        if( delay == undefined )
            delay = waitShowingDelay;

        if ( allowCancel == undefined )
            allowCancel = true;

        showCursor();

        if ( immediateDisplayMode )
            webcore.getProgressDisplay().showImmediately( allowCancel );
        else
        {
            if (!timerProgressDisplay)
            {
                if (allowCancel)
                    timerProgressDisplay = setTimeout("webcore.getProgressDisplay().showImmediately(true)", delay);
                else
                    timerProgressDisplay = setTimeout("webcore.getProgressDisplay().showImmediately(false)", delay);
            }
        }
    }

    function removeDelayedDisplayTimer()
    {
        if (timerProgressDisplay)
        {
            clearTimeout(timerProgressDisplay);
            timerProgressDisplay = null;
        }
    }

    function hide()
    {
        clearTimeout(timerCursor);

        if ( provideWaitCursorHtml() )
        {
            $waitCursorHtml.fadeOut(500);
            $(document).unbind("mousemove.progressDisplay");
        }

        removeDelayedDisplayTimer();

        var $progressDisplayHtml = $( '#progressDisplayContainer' );
        if( $progressDisplayHtml )
        {
            $progressDisplayHtml.css( "visibility", 'hidden' );
        }
    }

    function enable()
    {
        disabled = false;
    }

    function disable()
    {
        disabled = true;
    }

    function disableWaitCursor()
    {
        waitCursorEnabled = false;
    }

    function enableWaitCursor()
    {
        waitCursorEnabled = true;
    }

    function setImmediateDisplayMode( flag )
    {
        immediateDisplayMode= flag;
    }

    function setWaitShowingDelay( v )
    {
        waitShowingDelay = v;
    }

    function cancelWait()
    {
        if( waitAllowCancel && new Date().getTime() - userCanCancelAfter > waitShowingSince )
            hide();
    }

    function updateDimension()
    {
        var $progressDisplayHtml = $( '#progressDisplayContainer' );
        var isVisible = ($progressDisplayHtml.css( 'visibility' ) == 'visible');
        if( !isVisible )
            return;

        var windowHeight = $( window ).height();

        var $application = $(".wc-Application");
        var $waitContainerBox = $("#waitContainerBox");
        if ( $application.length && $waitContainerBox.length )
        {
            var applicationOffset = $application.offset();
            var boxWidth = $waitContainerBox.width();
            var boxHeight = $waitContainerBox.height();

            var boxTop = (windowHeight - boxHeight) / 2 + applicationOffset.top;
            var boxLeft = ($application.width() - boxWidth) / 2 + applicationOffset.left;
            $waitContainerBox.css('margin-top', boxTop + "px");
            $waitContainerBox.css('margin-left', boxLeft + "px");
        }
    }

    return {
        showImmediately: showImmediately,
        showDelayed : showDelayed,
        setWaitShowingDelay: setWaitShowingDelay,
        hide: hide,
        enable: enable,
        disable: disable,
        enableWaitCursor: enableWaitCursor,
        disableWaitCursor: disableWaitCursor,
        cancelWait: cancelWait,
        setImmediateDisplayMode: setImmediateDisplayMode,
        updateDimension: updateDimension
    }
}



WebCore = function()
{
    var actionRunning = true;

    /*
     * Mouse Tracking
     */
    var mousePosX;
    var mousePosY;

    var hoverDelayTimer;

    var progressDisplay = new ProgressDisplay();

    var refocusAfterLoad = true;
    var elementIdToFocusAfterLoad = "";

    var storageAvailable;
    
    var settings={};

    try {
        sessionStorage["storageAvailable"] = true;
        localStorage["storageAvailable"] = true;
        storageAvailable = true;
    }
    catch (e)
    {
        storageAvailable = false;
    }

    function init()
    {
        defineIndexOfForArrays();
        disableBrowserHistory();
        bindMouseMoveRecording();
        bindProgressDisplayRepositioner();
        bindRefocusHandler();
        bindProgressDisplayHandler();
        bindResetHandler();
        initDefaultSettings();
    }

    function bindRefocusHandler() {
        $( document ).bind( "ajaxStart.refocusHandler", function () {
            if (!refocusAfterLoad)
                return;
            
            var $focusedElement = $( "*:focus" );
            if ( $focusedElement.length == 1 && $focusedElement.attr( "id" ) )
                elementIdToFocusAfterLoad = $focusedElement.attr( "id" );
            else
                elementIdToFocusAfterLoad = "";
        } );

        $( document ).bind( "ajaxStop.refocusHandler", function () {
            if (!refocusAfterLoad)
                return;
            
            if ( elementIdToFocusAfterLoad && elementIdToFocusAfterLoad.length > 0 ) {
                var $elementToFocus = $( "#" + elementIdToFocusAfterLoad );
                if ( $elementToFocus.length == 1 ) {
                    var eventHandler = $._data( $elementToFocus[0], 'events' );
                    if ( !eventHandler || eventHandler.focus == null )
                        $elementToFocus.focus();
                }
            }
        } );
    }

    function bindProgressDisplayHandler() {
        $( document ).bind( "ajaxStart.progressDisplayHandler", function () {
            webcore.getProgressDisplay().showDelayed();
        } );

        $( document ).bind( "ajaxStop.progressDisplayHandler", function () {
            webcore.getProgressDisplay().hide();
        } );

        $(document).ready(progressDisplay.hide);
    }

    function bindResetHandler() {
        $( document ).bind( "ajaxStop.resetHandler", resetClickOnce );
    }

    function bindMouseMoveRecording() {
        $( document ).ready( function () {
            $( document ).mousemove( function ( e ) {
                mousePosX = e.pageX;
                mousePosY = e.pageY;
            } );
        } );
    }

    function bindProgressDisplayRepositioner() {
        $( window ).scroll( function () {
            webcore.getProgressDisplay().updateDimension();
        } );

        $( window ).resize( function () {
            webcore.getProgressDisplay().updateDimension();
        } );
    }

    function initDefaultSettings() {
        settings = {
            locale: {
                decimal: ",",		// decimal point separator
                thousand: "."		// thousands separator
            }
        };
    }
    var customHistory;
    function pushHistoryState( data, title, location )
    {
        customHistory = {data: data, title: title, location: location};
    }
    function disableBrowserHistory()
    {
        //disable browser history functionality
        if (history.pushState)
        {
            var manipulateHistory = function ()
            {
                history.pushState(customHistory.data, customHistory.title, customHistory.location);
                $(window).trigger("historyback");
            };
            $(window).on('popstate.disableHandling', manipulateHistory);

            history.pushState({}, window.document.title, window.location);
            customHistory = {data: {}, title: window.document.title, location: window.location};
        }
    }

    function defineIndexOfForArrays()
    {
        if( !Array.prototype.indexOf )
        {
            Array.prototype.indexOf = function( elt /* , from */ )
            {
                var len = this.length >>> 0;

                var from = Number( arguments[1] ) || 0;
                from = (from < 0)
                    ? Math.ceil( from )
                    : Math.floor( from );
                if( from < 0 )
                    from += len;

                for( ; from < len; from++ )
                {
                    if( from in this &&
                        this[from] === elt )
                        return from;
                }
                return -1;
            };
        }
    }

    function getMousePosX()
    {
        return mousePosX;
    }

    function getMousePosY()
    {
        return mousePosY;
    }

    function resetClickOnce()
    {
        $.each($(document).data(),
            function(name,elem) {
                if(name.indexOf("clickOnceBlockedElement_")==0) {
                    $(document).removeData(name);
                }
            }
        );
    }

    function clickOnce( elementId )
    {
        if( $(document).data( "clickOnceBlockedElement_" + elementId ) == null )
        {
            $(document).data( "clickOnceBlockedElement_" + elementId, true );
            return true;
        }
        return false;
    }

    function setActionRunning( flag )
    {
        actionRunning = flag;
    }

    function isActionRunning()
    {
        console.trace();
        var delayedWidgetActionInProgress = false;
        $.each($(document).data(),
            function( timerName )
            {
                if(timerName.indexOf("delayedControlTimer.")==0)
                {
                    delayedWidgetActionInProgress = true;
                    return false;
                }
            }
        );
        var running = actionRunning || jQuery.active != 0 || delayedWidgetActionInProgress;
        console.info(running);
        return running;
    }

    function clearHoverDelayTimer()
    {
        if (hoverDelayTimer)
        {
            clearTimeout(hoverDelayTimer);
            hoverDelayTimer = null;
        }
    }

    function showHover(id, delay)
    {
        if (delay && delay > 0)
            hoverDelayTimer = setTimeout("webcore.showHover( '" + id + "' )", delay); // recursive
        else
        {
            clearHoverDelayTimer();
            $( "#" + id ).css( "display", "block" );
        }
    }

    function hideHover(id)
    {
        clearHoverDelayTimer ();
        $( "#" + id ).css( "display", "none" );
    }

    function setProgressDisplay( progressDisplay )
    {
        this.progressDisplay = progressDisplay;
    }

    function getProgressDisplay()
    {
        return progressDisplay;
    }

    function getElementIdToFocusAfterLoad() {
        return elementIdToFocusAfterLoad;
    }

    function setElementIdToFocusAfterLoad( id ) {
        elementIdToFocusAfterLoad = id;
    }

    function onError(message, path, line, pos, errorObj )
    {
      try {
          var key = path + line + "_" + pos;
          if ( !sessionStorage[key] || sessionStorage[key] != message )
              ajaxEngine.sendServerCommand("ajaxError", {
                  stack: errorObj ? errorObj.stack : message + "\n " + path + ":" + line + ":" + pos,
                  message: errorObj ? errorObj.message : message
              });
          sessionStorage[key] = message;
      }
      catch(e) {}
    }
    window.onerror = onError;

    function isStorageAvailable()
    {
        return storageAvailable;
    }

    function getSettings() {
        return settings;
    }

    function disableRefocusAfterLoad() {
        refocusAfterLoad = false;
    }

  //public methods
    return {
        init: init,
        getMousePosX: getMousePosX,
        getMousePosY: getMousePosY,
        clickOnce: clickOnce,
        isActionRunning: isActionRunning,
        setActionRunning: setActionRunning,
        clearHoverDelayTimer: clearHoverDelayTimer,
        showHover: showHover,
        hideHover: hideHover,
        setProgressDisplay : setProgressDisplay,
        getProgressDisplay : getProgressDisplay,
        getElementIdToFocusAfterLoad : getElementIdToFocusAfterLoad,
        setElementIdToFocusAfterLoad : setElementIdToFocusAfterLoad,
        isStorageAvailable: isStorageAvailable,
        getSettings: getSettings,
        disableRefocusAfterLoad: disableRefocusAfterLoad,
        pushHistoryState: pushHistoryState
    }
};

// create a webcore-object to get access to the methods
webcore = new WebCore ();
webcore.init();