(function(console)
{
    "use strict";
    var nop = function() {};
    var ops = ["log", "info", "error", "warn", "time", "timeEnd", "group", "groupEnd", "timeline", "timelineEnd", "timeStamp"];
    for(var x = 0; x < ops.length; x++)
    {
        if(!console[ops[x]]) { console[ops[x]] = nop; }
    }
}(window.console = window.console || { $replaced: true }));

(function()
{
    "use strict";
    window.pageLoad = new Date().getTime();
    window.lastLog = new Date().getTime();
    console.$log = function $log()
    {
        try
        {
            if(typeof(arguments[0]) === "string")
            {
                var message = "(@%d +%d) " + arguments[0];
                var newArgs = [];

                newArgs.push(message, new Date().getTime() - window.pageLoad, new Date().getTime() - window.lastLog);
                for(var i = 1; i < arguments.length; i++)
                {
                    newArgs.push(arguments[i]);
                }
                return console.log.apply(console, newArgs);
            }
            else
            {
                console.log.apply(console, arguments); //Log timings to the console
                if(console.timeStamp) { console.timeStamp.apply(console, arguments); } //Mark timing on the timeline
            }
        }
        catch(ex) { console.error(ex); }
        finally
        {
            window.lastLog = new Date().getTime();
        }
    };

    console.timeline("Page Cycle"); //Start Timing
}());

(function()
{
    "use strict";
    
    var App = window.App = window.App || angular.module("App", []);

    App.updateStatus = function updateStatus(status)
    {
        if(status) { console.$log('Status change: %s', status); }
        var root = App && App.$root;
        if(root) { root.$emit('mad-status', status); }
        document.documentElement[status ? 'setAttribute' : 'removeAttribute']('data-status', status);
    };

    App.factory('ajaxTrackerService',
    ['$timeout',
    function($timeout)
    {
        var stack = 0, timeout;

        var fn = function()
        {
            if(stack === 0)
            {
                App.updateStatus('ready');
            }
        };

        return {
            inc: function()
            {
                App.updateStatus();
                ++stack;
                $timeout.cancel(timeout);
            },
            dec: function()
            {
                if(stack > 0)
                {
                    --stack;
                }
                if(stack === 0)
                {
                    timeout = $timeout(fn, 50);
                }
            }
        };
    }]);

    App.config(['$httpProvider', function($httpProvider)
    {
        $httpProvider.responseInterceptors.push(['ajaxTrackerService', function(ajaxTrackerService)
        {
            return function(promise)
            {
                var start = new Date().getTime();
                ajaxTrackerService.inc();
                var cntd = function(r)
                {
                    var now = new Date().getTime();
                    var elapsed = now - start;
                    console.$log("Request %s took %d ms to complete", r.config.url, elapsed);
                    ajaxTrackerService.dec(r);
                    return r;
                };
                return promise.then(cntd, cntd);
            };
        }]);
    }]);

    App.run(['$rootScope', '$window', function($rootScope, $window)
    {
        $rootScope.$on('routeChangeStart', function()
        {
            $window.pageLoad = new Date().getTime();
            (console.timeline || function() {})('Page Cycle'); //Restart timing on angular navigation
        });

        $rootScope.$on('mad-status', function(e, status)
        {
            if(status === 'ready')
            {
                (console.timelineEnd || function() {})('Page Cycle');
            }
        });
    }]);

}());