﻿/*
*  Date: 6/16/2010
*  
*  some common util functions
*/

var goCachedAppInfo = null;
var goCachedAccountInfo = null;
(function () {

    // eventRegistry [Array]:
    // the internal list of all registered event handlers. Each entry in $eventRegistry is itself an array of
    // objects detailing the element, name and callback of events all bound to a single element.

    var eventRegistry = [];

    // Util [Namespace]:
    // a collection of common functions.
    window.Util = {

        // create namespace [Function]:
        // creates a namespace
        createNamespace: function (ns) {
            // First split the namespace string separating each level of the namespace object.
            var splitNs = ns.split(".");
            // Define a string, which will hold the name of the object 
            // we are currently working with. Initialize to the first part.
            var builtNs = splitNs[0];
            var i, base = window;
            for (i = 0; i < splitNs.length; i++) {
                if (typeof (base[splitNs[i]]) == "undefined") base[splitNs[i]] = {};
                base = base[splitNs[i]];
            }
            return base; // Return the namespace as an object.
        },

        // addEvent [Function]:
        // binds an event handler function to a certain DOM element so that it is triggered by the desired event.
        // This uses reflection to defer the event handling to either 'addEventListener' or 'attachEvent', and if neither
        // are available, the 'onevent' property of the bound element is used.
        // Arguments:
        //
        // - elem [Element]:      the DOM element to which the event is bound, or its string ID.
        // - name [String]:       the name of the event, without the 'on' prefix.
        // - callback [Function]: the function to be executed when the event is triggered.

        addEvent: function (elem, name, callback) {

            if (typeof (elem) === 'string' || (elem instanceof String))
                elem = document.getElementById(elem);

            if (elem.addEventListener) elem.addEventListener(name, callback, false);
            else if (elem.attachEvent) elem.attachEvent('on' + name, callback);
            else elem['on' + name] = callback;

            if (typeof (elem.__eventRegistryIndex) !== 'number') {

                elem.__eventRegistryIndex = eventRegistry.length;
                eventRegistry.push([]);
            }

            eventRegistry[elem.__eventRegistryIndex].push({ elem: elem, name: name, callback: callback });
        },

        // flushEvents [Function]:
        // removes all event handlers bound by addEvent().

        flushEvents: function () {

            for (var i = eventRegistry.length - 1; i >= 0; i--) {

                var record = eventRegistry[i];
                if (record && record.elem)
                    Util.removeEvent(record.elem);
            }
        },

        // getCookie [Function]:
        // reads the value of a cooke with the given name.
        // Arguments:
        //
        // - name [String]: the name of the cookie to get the value of.
        //
        // Return [String]: the value of the named cookie.

        getCookie: function (name) {

            var value = null;
            var index = document.cookie.indexOf(name + '=');
            if (index >= 0) {

                value = document.cookie.substring(index + name.length + 1);
                var endIndex = value.indexOf(';');
                if (endIndex >= 0)
                    value = value.substring(0, endIndex);
            }

            return value;
        },

        // nothingEvent [Function]:
        // acts to stop any further actions being taken on a DOM event. Returning this from a custom event handler
        // will stop default events (such as the appearance of a context menu) occurring.
        // Arguments:
        //
        // - e [Event]: the parameters for the event.
        //
        // Return [Boolean]: true, to signify that the event has completed.

        nothingEvent: function (e) {

            if (e) {

                if (e.preventDefault) e.preventDefault();
                e.returnValue = false;
            }
            return false;
        },

        // removeEvent [Function]:
        // removes an event handler previously bound by a call to addEvent() from a given DOM element. Depending on the number
        // of parameters passed, all events may be removed from $elem, or all events of a certain type, or only a 
        // single callback.
        // Arguments:
        //
        // - elem [Element]:      the DOM element to remove events from, or its string ID.
        // - name [String]:       the name of the event to remove callbacks for. If not supplied, callbacks for all event
        //                        types are removed.
        // - callback [Function]: the exact event callback function to remove. If not supplied, all callbacks for the given
        //                        event type are removed.

        removeEvent: function (elem, name, callback) {

            if (typeof (elem) === 'string' || (elem instanceof String))
                elem = document.getElementById(elem);

            var entry = eventRegistry[elem.__eventRegistryIndex];
            if (entry) {

                for (var i = entry.length - 1; i >= 0; i--) {

                    var item = entry[i];

                    if (name && name !== item.name) continue;
                    if (callback && callback !== item.callback) continue;

                    if (item.elem.removeEventListener) item.elem.removeEventListener(item.name, item.callback, false);
                    if (item.name.substring(0, 2) !== 'on') item.name = 'on' + item.name;
                    if (item.elem.detachEvent) item.elem.detachEvent(item.name, item.callback);
                    if (item.elem[item.name]) item.elem[item.name] = null;

                    entry.splice(i, 1);
                }

                if (entry.length === 0) {

                    eventRegistry.splice(elem.__eventRegistryIndex, 1);
                    elem.__eventRegistryIndex = null;
                }
            }
        },

        // setCookie [Function]:
        // sets the value of the cookie with the specified name.
        // Arguments:
        //
        // - name [String]:   the name of the cookie to set.
        // - value [String]:  the value to set the cookie to.
        // - expiry [Number]: the optional time, in milliseconds, until the cookie should expire.

        setCookie: function (name, value, expiry) {

            var cookie = name + '=' + value;
            if (expiry) {

                var date = new Date();
                date.setTime(date.getTime() + expiry);
                cookie += '; expires=' + date;
            }

            cookie += '; path=/';
            document.cookie = cookie;
        },

        // terminateEvent [Function]:
        // stops an event from bubbling any further up the DOM tree.
        // Arguments:
        // 
        // - e [Event]: the event to prevent further propagation of.

        terminateEvent: function (e) {

            if (e.stopPropagation) e.stopPropagation();
            else e.cancelBubble = true;
        },

        // suspend the execution in millis seconds [Function]
        // remarks: not recommended in most cases as js is single threaded.
        wait: function (millis) {
            var date = new Date();
            var curDate = null;

            do { curDate = new Date(); }
            while (curDate - date < millis);
        },

        // fire event
        fireEvent: function (type, id) {
            var evt = document.createEvent("HTMLEvents");
            evt.initEvent(type, true, true);
            document.getElementById(id).dispatchEvent(evt);
        },

        // hit test
        hitTest: function (o, l) {
            function getOffset(o) {
                for (var r = { l: o.offsetLeft, t: o.offsetTop, r: o.offsetWidth, b: o.offsetHeight };
			        o = o.offsetParent; r.l += o.offsetLeft, r.t += o.offsetTop);
                return r.r += r.l, r.b += r.t, r;
            }
            var a = arguments, j = a.length;
            j > 2 && (o = { offsetLeft: o, offsetTop: l, offsetWidth: j == 5 ? a[2] : 0,
                offsetHeight: j == 5 ? a[3] : 0, offsetParent: null
            }, l = a[j - 1]);
            for (var b, s, r = [], a = getOffset(o), j = isNaN(l.length), i = (j ? l = [l] : l).length; i;
		        b = getOffset(l[--i]), (a.l == b.l || (a.l > b.l ? a.l <= b.r : b.l <= a.r))
		        && (a.t == b.t || (a.t > b.t ? a.t <= b.b : b.t <= a.b)) && (r[r.length] = l[i]));
            return j ? !!r.length : r;
        },

        // get element innerHTML and remove the source one
        getElmentHtml: function (id) {
            var s = $('#' + id).html();
            $('#' + id).remove();
            return s;
        },

        // get query string param by name
        getQueryStringValue: function (name) {
            name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
            var regexS = "[\\?&]" + name + "=([^&#]*)";
            var regex = new RegExp(regexS);
            var results = regex.exec(window.location.href);
            if (results == null)
                return "";
            else
                return results[1];
        },

        // get google analytics account
        getGoogleAnalyticsAccount: function () {
            var account = '';
            $.ajax({
                type: 'GET',
                cache: false,
                async: false,
                url: '/Account/GetGAAccount',
                success: function (data) {
                    account = data;
                },
                error: function () {
                    account = '';
                }
            });
            return account;
        },
        trackEventAction : function(category, description, logType) {
            Util.trackAction(category, 'Event', null, description, logType);
        },
        trackSimpleAction : function(category, description, logType) {
            Util.trackAction(category, 'Click', null, description, logType);
        },
         trackPageVisitAction : function(category, description, logType) {
            Util.trackAction(category, 'Page Visit', null, description, logType);
        },
        // track action using GA
        trackAction: function (category, action, callback, description, logType) {
            var logTypeEnum = {
                GOOGLE: 1,
                STATISTICS: 2,
                BOTH: 3
            };

            var logType = logType || logTypeEnum.BOTH;

            try {

                var myTracker = _gat._getTrackerByName();

                switch (logType) {
                    case logTypeEnum.GOOGLE:
                        //base syntax
                        //_gaq.push(['_trackEvent', 'category', 'action', 'opt_label', opt_value])
                        _gaq.push(['_trackEvent', category, action, description]);
                        //temp code
                        //_gaq.push('_setDomainName', 'none');
                        //possibly _gaq._getAsyncTracker()._trackEvent("SampleCategory", "SampleAction", "optLabel", "optValue")
                        //TODO: check GA account to see if above worked.
                        break;
                    case logTypeEnum.STATISTICS:
                        Util.logStat(category, action);
                        break;
                    case logTypeEnum.BOTH:
                        _gaq.push(['_trackEvent', category, action, description]);
                        Util.logStat(category, description);
                        break;
                    default: break;

                }

                if (callback != null) {
                    callback();
                }

            } catch (err) { }
        },
        trackAndClick: function (url, category, description, openNewWin, logType) {
            var callback = function () {
                if(!url)return;
                if (openNewWin) 
                        var newWin = (window.open(url, '', '', false));
                    else
                        window.location = url;
                
            };
            Util.trackAction(category, "Click", callback, description, logType);
        },
        logStat: function (category, action) {
            try {
                var params = $.format("name={0}&value={1}", category, action);

                // save stat to server
                $.ajax({
                    type: 'POST',
                    cache: false,
                    async: true,
                    url: '/Base/LogStat',
                    data: params,
                    success: function (data) {

                    },
                    error: function () {

                    }
                });
            } catch (err) { }
        },
        getAppInfo: function () {
            var info = goCachedAppInfo;
            if (!info) {
                $.ajax({
                    type: 'POST',
                    cache: true,
                    async: false,
                    url: '/Account/GetAppInfo',
                    success: function (data) {
                        goCachedAppInfo = info = data;
                    },
                    error: function () {
                        info = null;
                    }
                });
            }
            return info;
        },
        getAccountInfo: function () {
            var info = goCachedAccountInfo;
            if (!info) {
                $.ajax({
                    type: 'POST',
                    cache: true,
                    async: false,
                    url: '/Account/GetAccountInfo',
                    success: function (data) {
                        goCachedAccountInfo = info = data.data;
                    },
                    error: function () {
                        info = null;
                    }
                });
            }
            return info;
        },


        // append time stamp to url
        appendTimeStamp: function (url) {
            var ts = Math.round(new Date().getTime() / 1000);
            return /\?/.test(url) ? url + '&time=' + ts : url + '?time=' + ts;
        },

        getWindowTop: function () {
            var y = 0;
            if ($.browser.msie) {
                y = window.screenTop;
            } else {
                y = window.screenY;
            }
            return y;
        },
        getWindowLeft: function () {
            var x = 0;
            if ($.browser.msie) {
                x = window.screenLeft;
            } else {
                x = window.screenX;
            }
            return x;
        },
		guid: function() {
		   function S4() {
			   return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
			}
		   return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
		}
    };

    // register an event that will cause all registered events to be cleaned up properly when the page unloads.

    if (typeof window !== 'undefined') Util.addEvent(window, 'unload', Util.flushEvents);

})();




