﻿
(function ($) {

    jQuery.fn.maxlen = function (len) {
        return this.each(function () {
            var t = $(this),
                text = t.text(),
                l = parseInt(t.attr('data-maxlen')) || len || 50;
            if (text.length > l - 3) {
                text = text.substring(0, l - 3) + "...";
                t.text(text);
            }
        });
    };


    String.format = function () {
        var s = arguments[0];
        for (var i = 0; i < arguments.length - 1; i++) {
            var reg = new RegExp("\\{" + i + "\\}", "gm");
            s = s.replace(reg, arguments[i + 1]);
        }

        return s;
    }


    function WebApp() {
        this.modules["app"] = this;
        this.modules["jquery"] = jQuery;
        // init on ready
        $(function () {
            App.init();
        });
    }

    WebApp.prototype = {
        init: function () {
            // TODO move services into seperate modules
            this.initFormService();
            this.initActionService();
            this.initOverlayService();
            this.initMenuService();
            this.initTrackingService();
            this.initMultiplayerService();
            this.initAutoLoaderService();
            this.initFlashEmbedService();
            this.initUiCleanupService();
        },


        proxy: function (fn, scope) {
            return function () { fn.apply(scope, arguments); };
        },
        bind: function (event, handler) {
            $("body").bind(event, handler);
        },
        trigger: function (event, args) {
            $("body").trigger(event, args);
        },

        addActions: function (actions) {
            for (var a in actions) {
                App.actions[a.toLowerCase()] = actions[a];
            }
        },
        actions: {},
        log: function (msg) {
            if (!App.isProd && typeof console != 'undefined')
                console.log(msg);
        },
        isProd: window.location.toString().match(/dev|local/) ? false : true,
        error: function (e) {
            if (!App.isProd) {
                throw e;
            }
        },
        modules: {},
        module: function (name, cb) {
            var ns = name.toLowerCase().split('.'),
                 o = App.modules;
            for (var i = 0, len = ns.length; i < len; i++) {
                o = o[ns[i]] = o[ns[i]] || {};
            }
            cb(o, App.require);
        },
        require: function (module) {
            return App.modules[module.toLowerCase()];
        },
        post: function (method, data, cb) {
            $.ajax({
                type: 'POST',
                //TODO: set app base url
                url: App.baseUrl() + 'webservices/ajaxapi.asmx/' + method,
                data: JSON.stringify(data),
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function (res) {
                    res = res.d;
                    if (res.success)
                        cb(null, res.data);
                    else {
                        App.log("app error: " + res.error);
                        cb(res.error, res.data);
                    }
                },
                error: function (res) {
                    App.log("server error");
                    App.log(res);
                    cb("unknown error", null);
                }
            });
        },
        baseUrl: function () {
            if (typeof App._baseUrl != 'undefined')
                return App._baseUrl;

            var b = $("base").attr("href") || "/";

            if (b[b.length - 1] != '/')
                b += "/";

            return App._baseUrl = b;
        },

        isLoggedIn: function () {
            return $("#userprofile").attr('data-profile-loggedin') === "true";
        },

        currentUserId: function () {
            return $("#userprofile").attr('data-profile-id');
        },

        trackUserAction: function (actiondata) {
            App.post("TrackAction", { input: JSON.stringify(actiondata) }, function (error, data) { });
        },

        displayError: function (error, $el) {
            if (typeof $el == 'undefined' || $el.length == 0)
            //jqGrowl.show( error );
                $.jGrowl(error, { header: 'Error' });
            else
                $el.text(error).show();
        },
        displayInfo: function (msg, header) {
            App.log("info:" + msg);
            $.jGrowl(msg, { header: header || "Info" });
        },

        _autoloaders: {},
        addAutoLoaders: function (loaders) {
            for (var l in loaders) {
                var name = l.toLowerCase();
                if (!this._autoloaders[name])
                    this._autoloaders[name] = [];

                this._autoloaders[name].push(loaders[l]);
            }
        },

        initAutoLoaderService: function () {
            $(".autoload").each(function () {
                var name = $(this).attr('data-autoloader'),
                    loaders = App._autoloaders[name.toLowerCase()];
                if (!loaders) return;

                for (var i = 0, l; l = loaders[i]; i++)
                    l();
            });
        },

        /////////////////////////////////////////
        //////// UI SERVICES  //////////////////
        ////////////////////////////////////////

        ///////////////////// ACTION SERVICE /////////////////////////////
        initActionService: function () {
            $("body").delegate('.action', 'click', function () {
                return App.doAction($(this));
            });
        },
        doAction: function ($el, action) {
            try {
                var a = action || $el.attr("data-action") || "";

                a = a.toLowerCase();

                if (!App.isProd) {
                    App.log("executing action: " + a);
                }
                var action = App.actions[a];
                if (typeof action == 'function') {
                    return action($el) || false;
                } else {
                    App.log("action not handled - name: " + a + ", handler:" + (App.actions[a] || "(undefined)"));
                }
            } catch (e) {
                App.log(e);
            }
            return false;
        },

        ///////////////////// ACTION SERVICE /////////////////////////////


        ///////////////////// FORM SERVICE /////////////////////////////
        initFormService: function () {

            /*validator functions return true when validation has passed but when it fails you can return either false or a string error message to be displayed */

            $.tools.validator.fn("[data-equals]", "Value not equal with the $1 field", function (input) {
                var name = input.attr("data-equals"),
		        field = this.getInputs().filter("[name=" + name + "]");
                return input.val() == field.val() ? true : [name];
            });

            $.tools.validator.fn("[minlength]", function (input, value) {
                var min = input.attr("minlength");
                return value.length >= min ? true : "Please provide at least " + min + " character" + (min > 1 ? "s" : "");
            });

            $.tools.validator.fn("select", function (input, value) {

                return input.attr('required') && value == -1 ? false : true;
            });

            $.tools.validator.fn("[data-pattern]", function (input, value) {
                var pattern = new RegExp(input.attr("data-pattern"));
                return pattern.test(value);
            });

            $(".submit").live("click", function (e) {
                App.log("submit");
                var $this = $(this);
                var form = $this.closest(".form");
                var utils = App.require("utils");
                if (!utils.isFormValid(form)) {
                    App.log("form validiation failed: " + $this.attr("className"))
                    e.preventDefault();
                    return false;
                }
            });

            this.contentLoaded($("body"));
        },

        loadContent: function (el, url) {
            var $el = $(el);
            $el.load(url, function () { App.contentLoaded($el); });
        },

        removeContent: function (el) {
            // clean up validators
            var $el = $(el);
            var forms = $(".form", $el);
            forms.each(function () {
                var form = $(this),
                    validator = form.data("validator");
                if (validator)
                    validator.destroy();
            });
        },

        contentLoaded: function ($root) {
            App.log("Content Loaded");
            var forms = $(".form", $root);
            forms.each(function () {
                var form = $(this),
                    validator = form.data("validator");
                if (!validator) {
                    form.validator({
                        position: 'right',
                        offset: [30, 24],
                        //errorInputEvent: 'blur',
                        inputEvent: 'blur',
                        message: '<div><em/></div>' // em element is the arrow
                    });
                    App.log("adding validator to " + form.attr("className"));
                }
            });

            $(".formaction", $root).each(function () {
                var $this = $(this),
                        bound = $this.data("formaction");
                if (bound) return;
                $this.data("bound", true);
                // trigger is the jquery event name, any of these will work: http://api.jquery.com/category/events/form-events/
                var trigger = $this.attr("data-trigger") || "click",
                        action = $this.attr("data-action");

                // this will is the same as doing $this.click( ... )
                $this[trigger](function () {
                    App.doAction($(this));
                    // return false to cancel event
                    return false;
                });
            });

            $(":date", $root).each(function () {
                var date = $(this),
                    bound = date.data("dateinput");

                if (bound) return;

                date.dateinput({
                    format: 'dddd dd, mmmm yyyy',
                    selectors: true, // year/month selectors
                    //min: new Date(1925, 0, 1),                    // min selectable day (100 days backwards)
                    max: 0,
                    speed: 'fast',
                    firstDay: 1, // week starts on mon
                    yearRange: [-101, 1]
                });
            });

            $(".submit", $root).each(function () {
                var el = $(this),
                    bound = el.data("submit");
                if (bound) return;
                el.data("submit", true);
                el.click(function (e) {
                    App.log("submit");
                    var $this = $(this);
                    var form = $this.closest(".form");
                    var utils = App.require("utils");
                    if (!utils.isFormValid(form)) {
                        App.log("form validiation failed: " + $this.attr("className"))
                        e.preventDefault();
                        return false;
                    }
                });
            });

            $('input[data-empty-text], textarea[data-empty-text]')
                .inFieldLabels({
                    attr: 'data-empty-text',
                    labelClass: 'empty-text'
                });
        },

        ///////////////////// FORM SERVICE /////////////////////////////

        ///////////////////// OVERLAY SERVICE /////////////////////////////

        initOverlayService: function () {
            App.addActions({
                overlayContinue: App.overlayContinue
            });

            $("a.overlay").live("click", function (e) {
                e.preventDefault();
                var a = $(this),
                    api = a.data("overlay");

                if (api) {
                    App._overlay = api;
                    api.load();
                    return;
                }

                App._overlay = a.overlay({
                    mask: {
                        color: '#ececff',
                        loadSpeed: 200,
                        opacity: 0.5
                    },
                    target:"#overlay",
                    fixed: false,
                    top: 10,
                    onBeforeLoad: function () {

                        var root,
							trigger = this.getTrigger(),
							url = trigger.attr("href"),
							method = trigger.attr("data-overlay-method") == 'ajax' ? 'ajax' : 'iframe',
                            overlaywidth = trigger.attr("data-overlay-width") || "",
                            overlayheight = trigger.attr("data-overlay-height") || "";

                        this.getOverlay().find(".overlaywrap").remove();

                        if (method == 'iframe') {
                            root = $('<iframe scrolling="no" frameborder="0" class="overlaywrap"/>');

                            if (overlaywidth)
                                root.css("width", overlaywidth + "px");

                            if (overlayheight)
                                root.css("height", overlayheight + "px");

                            root.attr("src", url);

                        } else {
                            root = $('<div class="overlaywrap"></div>');
                            App.loadContent(root, url);
                        }

                        if (typeof trigger.attr("data-overlay-class") !== "undefined") {
                            root.toggleClass(trigger.attr("data-overlay-class"));
                        }

                        this.getOverlay().append(root);
                    },
                    onClose: App.closeOverlay,
                    load: true
                }).data("overlay");
            });
        },

        _overlay: null,

        closeOverlay: function () {
            if (!App._overlay) return;

            var wrap = App._overlay.getOverlay().find(".overlaywrap");
            if (!wrap.is("iframe"))
                App.removeContent(wrap);
            else
                wrap.remove();

            App._overlay.close();
        },

        _overlayActions: {},
        _overlayTrigger: null,
        showOverlay: function (url, type, overlayclass, width, height, overlaycontinue) {
            if (!App._overlayTrigger) {
                App._overlayTrigger = $('<a class="overlay"></a>').appendTo($("body")).hide();
            }

            App._overlayTrigger.attr("href", url);
            App._overlayTrigger.attr("data-overlay-method", type || "ajax");


            if (overlayclass)
                App._overlayTrigger.attr("data-overlay-class", overlayclass);
            else
                App._overlayTrigger.removeAttr("data-overlay-class");

            if (width)
                App._overlayTrigger.attr("data-overlay-width", width);
            else
                App._overlayTrigger.removeAttr("data-overlay-width");

            if (height)
                App._overlayTrigger.attr("data-overlay-height", height);
            else
                App._overlayTrigger.removeAttr("data-overlay-height");

            if (overlaycontinue)
                App._overlayActions['continue'] = overlaycontinue;
            else
                App._overlayActions['continue'] = null;

            if (type == 'fullscreen') {
                window.location = url;
            } else if (type == 'tab') {
                window.open(url);
            } else {
                App._overlayTrigger.click();
            }
        },
        overlayContinue: function () {

            if (typeof App._overlayActions['continue'] == 'function') {

                App.closeOverlay();
                setTimeout(App._overlayActions['continue'], 500);
            }
        },


        ///////////////////// OVERLAY SERVICE /////////////////////////////


        ///////////////////// MENU SERVICE /////////////////////////////

        initMenuService: function () {
            // setup menus
            $("ol.menu a.nav").tooltip({
                position: "bottom center",

                onShow: function () {
                    this.getTrigger().toggleClass("active");
                },
                onHide: function () {
                    this.getTrigger().toggleClass("active");
                }
            });

            // setup search
            $('#searchquery').keypress(function (event) {
                var $this = $(this);
                var form = $this.closest(".search-box");
                if (event.which == '13') {
                    event.preventDefault();
                    document.location = form.attr("data-search-handler") + "?q=" + $this.val();
                }
            });

            $('.search-button').click(function (event) {
                var $this = $(this);
                var form = $this.closest(".search-box");
                var query = form.find("#searchquery");
                document.location = form.attr("data-search-handler") + "?q=" + query.val();
                return false;
            });


            $('.localeselect').change(function () {
                var selected = $('.localeselect option:selected').attr("value");
                $.cookie('GeoLocation', selected);
                if (CountryMappings && CountryMappings[selected]) {

                    document.location = App.baseUrl() + CountryMappings[selected];
                } else {
                    document.location = App.baseUrl();
                }

            });
        },

        ///////////////////// MENU SERVICE /////////////////////////////

        ///////////////////// TRACKING SERVICE /////////////////////////////
        trackGoogleEvent: function (event) {
            try {

                _gaq = window._gaq || [];
                _gaq.push(['_trackEvent'].concat($.isArray(event) ? event : event.split(",")));
            } catch (err) { }
        },

        trackGoogleSocial: function (event) {
            try {
                _gaq = window._gaq || [];
                _gaq.push(['_trackSocial'].concat($.isArray(event) ? event : event.split(",")));
            } catch (err) { }
        },

        trackGooglePageView: function (url) {
            try {
                _gaq = window._gaq || [];
                _gaq.push(['_trackPageview', url]);
            } catch (err) { }
        },

        initTrackingService: function () {

            var gameid = $(".articledetail").attr("data-game-id") || "",
                    category = $(".articledetail").attr("data-game-category") || "",
                    provider = $(".articledetail").attr("data-game-provider") || "",
                    title = $(".articledetail").attr("data-game-title") || $("title").text() || "";

            $("a[data-tracking-event]").live("click", function () {

                var trigger = $(this),
                    event = trigger.attr("data-tracking-event") || "",
					action = (trigger.attr("data-game-action") || "").toLowerCase();

                App.trackGoogleEvent(event);

                if (action) {
                    App.trackUserAction({
                        tags: ["click", action],
                        context: window.location.href,
                        gameid: gameid,
                        category: category
                    });

                    switch (action) {
                        case "play":
                            var trckurl = document.location.href.replace(App.baseUrl(), "") + "/play";

                            if (trckurl.indexOf("/") !== 0) {
                                trckurl = "/" + trckurl;
                            }

                            App.trackGooglePageView(trckurl);
                            break;

                        case "download":
                        case "buy":
                            App.trackGooglePageView("/" + provider + "/download");
                            break;
                    }
                }
            });

            $("a[data-tracking-event-2]").live("click", function () {

                var trigger = $(this),
                    event = trigger.attr("data-tracking-event-2") || "";
                App.trackGoogleEvent(event);
            });

            if (typeof FB != 'undefined' && title) {
                FB.Event.subscribe('edge.create', function (targetUrl) {
                    App.trackGoogleEvent(['game actions', 'like: ' + title]);
                });

                FB.Event.subscribe('edge.remove', function (targetUrl) {
                    App.trackGoogleEvent(['game actions', 'unlike: ' + title]);
                });

                FB.Event.subscribe('message.send', function (targetUrl) {
                    App.trackGoogleEvent(['game actions', 'send: ' + title]);
                });

                FB.Event.subscribe('comment.create', function (targetUrl) {
                    App.trackGoogleEvent(['game actions', 'comment: ' + title]);
                });
            }
        },

        ///////////////////// TRACKING SERVICE /////////////////////////////


        ///////////////////// MULTIPLAYER SERVICE /////////////////////////////

        initMultiplayerService: function () {
            var games = {};
            var ids = [];
            // get all the game ids
            jQuery(".mp-stats").each(function () {
                try {
                    var el = $(this);
                    var id = el.attr("data-gameid");
                    if (id) {
                        games[id] = games[id] || [];
                        el.fadeOut();
                        games[id].push(el);
                        ids.push(id);
                    }
                } catch (e) { App.log(e); }
            });

            if (ids.length < 1) return;

            App.post("GetMultiplayerGameStats", { ids: ids }, function (error, data) {
                if (error)
                    return App.log(error);
                var results = JSON.parse(data).result.games;
                for (var i = 0, g; g = results[i]; i++) {
                    if (games[g.gameID]) {
                        var elements = games[g.gameID];
                        for (var j = 0, el; el = elements[j]; j++) {
                            el.find(".mp-stat-count").text(g.playersOnline);
                            el.find(".mp-stat-avg").text(g.playersPerDay);
                            el.fadeIn();
                        }
                    }
                }
            });
        }

        ///////////////////// MULTIPLAYER SERVICE /////////////////////////////

        ///////////////////// FLASH EMBED SERVICE /////////////////////////////

        , initFlashEmbedService: function () {
            jQuery(".flash-embed").each(function () {
                try {
                    var el = $(this);
                    App.log(el);
                    App.log(el.attr('data-flash-args'));
                    el.flashembed({
                        src: el.attr('data-flash-src'),
                        wmode: 'transparent'
                    },
                        eval("(" + el.attr('data-flash-args') + ")")
                      );
                } catch (e) { App.log(e); }
            });
        }

        ///////////////////// FLASH EMBED /////////////////////////////

        ///////////////////// UI Cleanup Service /////////////////////////////
        , initUiCleanupService: function () {
            $(".maxlen").maxlen(40);
        }
        ///////////////////// UI Cleanup Service /////////////////////////////
    }

    // expose it to the world as a singleton
    window.App = new WebApp();

})(jQuery);
