/// <reference path="http://localhost/IHBOX/IndustrialDashboard/Scripts/IndustrialDashboard-debug.js" />
define([
  // Application.
  "app",  

  "modules/user",
  "modules/menu",
  "modules/dateControl",
  "modules/subnavbar",
  "modules/navbar-clock",
  "modules/navbar-ladle-positions",
  "modules/topMessagesControl",
  "modules/server-audit",
  "modules/network-monitor",
  "modules/ihdatasources-dropdown/ihdatasources-dropdown",

  //templates-loader
  "js/templates-loader",
  "js/detect-zoom/detect-zoom",
],

    function (app, User, Menu, DateControl, SubNavBar, NavBarClock, NavBarLadlePositions, TopMessagesControl, ServerAudit, NetworkMonitor,IHDataSourcesDropdown, T, detectZoom) {

    var AppController = { Model: {}, Views: {} }

    AppController.Model = Backbone.Model.extend({
        defaults: {
            menuChanged: false, 
        }
    });

    AppController.Views.Main = Backbone.View.extend({
        id: "app-controller"
        , isCacheable: false
        , initialize: function () {
            var that = this; 
            var callback = this.options.callback;
            this.options.MYREFERENCES = {
                screenLoading: {
                    toid: null
                },
            }; 

            this.options.lastUser = null; 

            _.bindAll(this);

            //attaching to the local storage value changing
            //addEventListener('storage', this.storageChanged, false);
            $(window).bind("storage", this.storageChanged); //multibrowser

            app.language = this.getCookie("siteLanguage").toUpperCase(); 

            //creating models
            app.models.user = new User.Model();
            app.models.navBarClock = new NavBarClock.Model();
            app.models.navBarLadlePositions = new NavBarLadlePositions.Model();
            app.models.subnavbar = new SubNavBar.Model(); 
            app.views.subnavbar = new SubNavBar.Views.Main({ model: app.models.subnavbar });
            app.views.topMessages = new TopMessagesControl.Views.Main({ el: $("#top_messages_bar_container") });
            app.models.serverAudit = new ServerAudit.Models.Main(); 
            app.models.networkMonitor = new NetworkMonitor.Models.Main();
	    app.models.ihDataSources = new IHDataSourcesDropdown.Models.Main();

            app.models.menu = new Menu.ItemsCollection(null, { userModel: app.models.user });

            //creating views
            app.views.userLogin = new User.Views.Login({ model: app.models.user, el: $("#loginView_holder") });
            app.views.menu = new Menu.Views.Main({ collection: app.models.menu, el: $("#menu_holder") });
            app.views.navBarClock = new NavBarClock.Views.Main({ el: $("#clockView_holder"), model: app.models.navBarClock });
            app.views.navBarLadlePositions = new NavBarLadlePositions.Views.Main({ el: $("#ladlePositionView_holder"), model: app.models.navBarLadlePositions });
            app.views.networkMonitor = new NetworkMonitor.Views.Main({
                //el: $(".no-connection-poster"),
                model: app.models.networkMonitor, 
            });

            //rendering
            app.views.subnavbar.render($("#subnavbar_holder"), function () {
                callback.call(that); 
            });

            app.views.topMessages.render(); 
            app.views.navBarClock.render();
            app.views.navBarLadlePositions.render();


            //fetching
            app.models.navBarClock.startAutoFetch();
            app.models.navBarLadlePositions.fetch();


            //custom-modules.
            this.loadCustomModels(function (ctx) {
            });

            //binding model-view events (all models and views should be created BEFORE calling to this function
            this.bindEvents();

            //fetching from user
            app.models.user.fetch({ async: false });
            app.models.user.checkLogged(); 

            //setting up zoom notice
            $(".dismiss-zoomed-browser-notice").click(this.dismiss_zoom_notice);
            $(".dismiss-menu-changed-notice").click(this.dismiss_menu_changed_notice);

            $(window).bind("resize", this.zoom_check);
            this.zoom_check(); 

            //start version checker
            console.log(app.name + " ver: " + ((window && window["webapp_version"]) ? webapp_version : "") + " ");
            this.version_check();
        },
        loadCustomModels: function (callback) {
            var that = this;
            var customModules = app.customModules; 

            if (customModules && _.isArray(customModules)) {
                if ((_.indexOf(customModules, '*')) != -1) {
                    customModules = _.without(customModules, '*');
                    customModules = _.union(customModules, (window && window["custom_modules_paths"]) ? custom_modules_paths : []); 
                }
            }

            var cmcount = (_.isArray(customModules)) ? customModules.length : 0;
            var exec_callback = _.after(cmcount, callback);
            if (cmcount > 0) {
                _.forEach(customModules, function (path) {
                    try {
                        require(["custom-modules/" + path], function (module) {
                            if (module && module.init) {
                                var ref = module.init.call(that, ctx = that, module, app);
                                if (module.getModuleName && _.isFunction(module.getModuleName)
                                    && ref) {
                                    app.custom_modules[module.getModuleName().toString()] = ref; 
                                }
                            }
                            exec_callback.call(that);
                        });
                    } catch (error) {
                        console.log("Error while loading custom module: [" + error.toString() + "] " +
                            " ModulePath:[ " + path + " ]");

                        exec_callback.call(that);
                    }
                });
            } else {
                callback.call(that); 
            }
        }, 
        render: function (container) {
            this.updateDisplayDbConflictsIcon();
        }
        , bindEvents: function () {
            this.listenTo(app.models.user, "change:logged", this.loggedStatusChanged);
            this.listenTo(app.models.user, "change:preferredLanguage", this.preferredLanguageChanged);
            this.listenTo(app.models.user, "change:accountNumber", this.accountNumberChanged); 
            this.listenTo(app.router, "route", this.checkURI);
            this.listenTo(app.models.dateControl, "change:date", this.updateURIdateParameter);
            this.listenTo(this.model, "change:menuChanged", this.menuChanged); 
        }
        , checkURI: function (route, arr) {
            var found = false; 
            for (var i = 0; i < arr.length ; i++) {
                //checking for date parameter present on URL
                var paramNames = (app.router.routeIDs[route]) ? app.router.routeIDs[route].Route.match(/([^/:]*):/g) : []; 

                if (Core.Object.Validate(paramNames[i]) && paramNames[i].indexOf("D_") != -1) {
                    if (app.models.dateControl) {
                        if (arr[i]) {
                            var dateFromParameter = arr[i].replace(/\$/g, ":");
                            dateFromParameter = (!dateFromParameter) ? app.models.dateControl.defaults.date : dateFromParameter;

                            app.models.dateControl.set("date", dateFromParameter);

                            found = true;
                        }
                    }
                }

            }

            //if (!found) app.models.dateControl.set("date", app.models.dateControl.defaults.date, {changeURI:false}); 
        }

        , updateURIdateParameter: function (a, b, c) {
            if (app.models.dateControl.get("updateURI") == false) return; 
            if (c && c.changeURI == false) return;

            var currentFragment = Backbone.history.fragment;
            var newFragment = "";
            //var dateEncoded = app.models.dateControl.get("date").toJSON().replace(/\:/g, "$");
            var dateEncoded = escape(app.models.dateControl.get("date").replace(/\:/g, "$")); 
            
            newFragment = currentFragment.replace(/\/D_([^/]+)/, "") + "/D_" + dateEncoded; 
            //newFragment = app.router.resolveURL(app.router.currentModule, { date: dateEncoded }, false);
            
            if (newFragment != currentFragment && newFragment != "") {
                //keep currentRoute updated cause the beforeRouted method is not going
                //to be executed becuase of the silent option.
                app.router.currentRoute = newFragment;
                app.router.navigate(newFragment, {silent: true});
            }
        }
        , preferredLanguageChanged: function (model) {
            if (model.get("preferredLanguage")) {
                var prefLang = model.get("preferredLanguage").toUpperCase();
                if (prefLang != app.language) {
                    this.changeLanguage(prefLang);
                }
            }
        }
        , loggedStatusChanged: function (model) {
            this.options.lastUser = (_.isString(model.get("username")) && model.get("username").length > 0) ? model.get("username") : this.options.lastUser; 

            var status = model.get("logged");
            var previousStatus = model.previous("logged"); 
            if (status == true && previousStatus == false) {
                if (app.router.currentView) {
                    app.router.currentView.close();
                    app.router.currentView = null;
                }
                app.router.navigate(model.get("defaultURL"), true);
            } else if (status == false && previousStatus == true) {
                app.router.navigate("!/user/logout", true); 
            }
            if (localStorage) localStorage.setItem(app.name + "_localstorage", status);

            //showing/hiding configuration if not logged.
            if (status == true) $("#configuration_icon").css("visibility", "visible");
            else $("#configuration_icon").css("visibility", "hidden");

            if (status == false) {
                try {
                    if (_.isString(this.options.lastUser) && this.options.lastUser.length > 0) {
                        var QP = new Core.Database.QueryParameters();
                        QP.Add("Username", "VARCHAR", this.options.lastUser);
                        Core.Json.CallProcedure(app.DatabaseNames.System + ".SYSTEM.UserLoggedOut", QP, {
                            onSuccess: function (data) {
                                data;
                            },
                            Async: false,
                        }, app.ConnectionStrings.app);
                    }
                } catch (error) { console.log("Error while auditing user logout."); }

                //logic to calculate whether the next parameter should be appended or not
                var backToLoginURL =
                    (app.returnURL != null && app.returnURL != undefined && app.returnURL.length > 0) ? app.returnURL :
                    app.foldersRoot + "/landing/login/login.aspx";

                var currentFragment = window.location.pathname.toUpperCase().replace(app.root.toUpperCase(), "");

                var appendNext = (app.returnURLAppendNext != null && app.returnURLAppendNext != undefined && _.isBoolean(app.returnURLAppendNext)) ? app.returnURLAppendNext : true; 
                if (appendNext) {
                    if (currentFragment.indexOf("LOGOUT") == -1 && currentFragment.length > 0) {
                        //appending next parameter to specify which page to go after logging in.
                        if ((currentFragment.charAt(0) == '/' && currentFragment.length > 1) ||
                            currentFragment.charAt(0) != '/') {
                            backToLoginURL += "?next=" + currentFragment;
                        }
                    }
                }

                //redirecting user to login page.
                window.location.replace(backToLoginURL);
            }
        }
        , accountNumberChanged: function (model) {
            app.DatabaseNames.IH = "IH_" + model.get("accountNumber"); 
        }
        , storageChanged: function () {
            var logged = (localStorage) ? localStorage.getItem(app.name + "_localstorage") : null;
            if (logged == "false") {
                //app.router.navigate("!/user/logout", true);
            }
        }
        , changeLanguage: function (lang) {
            window.location.href = app.foldersRoot + "/setLanguage.aspx?lang=" + lang; 
        }
        , getCookie: function (c_name) {
            var default_value = ""; 
            var i, x, y, ARRcookies = document.cookie.split(";");
            for (i = 0; i < ARRcookies.length; i++) {
                x = ARRcookies[i].substr(0, ARRcookies[i].indexOf("="));
                y = ARRcookies[i].substr(ARRcookies[i].indexOf("=") + 1);
                x = x.replace(/^\s+|\s+$/g, "");
                if (x == c_name) {
                    return unescape(y);
                }
            }

            return default_value; 
        }
        , updateDisplayDbConflictsIcon: function() {
            var hasConflicts = app.models.datablocksConflicts.get('hasConflicts'),
                icon = $("#configuration_error_icon");

            if (hasConflicts) {
                icon.css("display", "block")
                    .addClass("animated dur-3s bounceInDown")
                    .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function () {
                        icon
                            .removeClass("bounceInDown")
                            .addClass("infinite bounce");
                    });
            }
            else if (icon.hasClass("animated")) {
                icon.one('webkitAnimationIteration mozAnimationIteration MSAnimationIteration oanimationiteration animationiteration', function () {
                    icon.removeClass("infinite bounce")
                        .addClass("bounceOutUp")
                        .one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function () {
                            icon.css("display", "none")
                                .removeClass("animated dur-3s bounceOutUp");
                        });
                });
            }
        }

        , screenLoading: function (isLoading, opt) {
            var options = {
                showImmediate: false
                , delay: 500
            }; 


            if (this.options.MYREFERENCES.screenLoading.toid != null) {
                clearTimeout(this.options.MYREFERENCES.screenLoading.toid);
                this.options.MYREFERENCES.screenLoading.toid = null;
            }

            var that = this; 
            _.extend(options, opt); 

            var spinner = $("#top_nav_spinner");
            var title = $("#screen_title"); 
            if (isLoading == true) {
                if (!spinner.hasClass("show-spinner")) {
                    title.removeClass("show-title").addClass("hide-title");
                    if (options.showImmediate != true) {
                        this.options.MYREFERENCES.screenLoading.toid = setTimeout(function () {
                            spinner.removeClass("hide-spinner").addClass("show-spinner");
                        }, options.delay);
                    } else {
                        spinner.removeClass("hide-spinner").addClass("show-spinner");
                    }
                }
            } else {
                if (!title.hasClass("show-title")) {
                    spinner.removeClass("show-spinner").addClass("hide-spinner");
                    title.removeClass("hide-title").addClass("show-title"); 
                }
            }
        }

        , get_app_info: function (callback) {
            Core.Json.CallProcedure(app.DatabaseNames.System + ".FrontEnd.GetAppInfo", null,
                {
                    onSuccess: function (data) {
                        if (data && data.Table && data.Table.length > 0) {
                            if (_.isFunction(callback)) callback(data.Table[0]); 
                        }
                    }
                },
            app.ConnectionStrings.app); 
        }
        , version_check: function () {
            var that = this;
            var check_tout = setTimeout(that.version_check, 30 * 1000);
            this.get_app_info(function (data) {
                var lastest_version = data.Version;                
                if (that.compare_version(lastest_version, webapp_version) == 1) {
                    clearTimeout(check_tout);
                    $(".update-available").show();
                    $("body").css("padding-top", (parseInt($("body").css("padding-top")) + 40) + "px");
                    $(".fixed-subnavbar").css("top", (parseInt($(".fixed-subnavbar").css("top")) + 40) + "px");
                }
            }); 
        }
        , zoom_check: function () {
            var that = this;
            var device = detectZoom.device();
            var zoom = detectZoom.zoom();
            var noticeShown = !($(".zoomed-browser-notice").hasClass("hide")); 

            if (!(device == 1 || zoom == 1)) {
                if (!noticeShown) {
                    $(".zoomed-browser-notice").removeClass("hide");
                    $("body").css("padding-top", (parseInt($("body").css("padding-top")) + 40) + "px");
                    $(".fixed-subnavbar").css("top", (parseInt($(".fixed-subnavbar").css("top")) + 40) + "px");
                }
            } else {
                if (noticeShown) {
                    this.dismiss_zoom_notice(); 
                }
            }
        }
        , dismiss_zoom_notice: function () {
            var noticeShown = !($(".zoomed-browser-notice").hasClass("hide"));
            if (noticeShown) {
                $(".zoomed-browser-notice").addClass("hide");
                $("body").css("padding-top", (parseInt($("body").css("padding-top")) - 40) + "px");
                $(".fixed-subnavbar").css("top", (parseInt($(".fixed-subnavbar").css("top")) - 40) + "px");
            }
        }
        , menuChanged: function () {
            var menuChanged = this.model.get("menuChanged");

            if (menuChanged == true) {
                var noticeShown = !($(".menu-changed-notice").hasClass("hide"));
                if (!noticeShown) {
                    $(".menu-changed-notice").removeClass("hide");
                    $("body").css("padding-top", (parseInt($("body").css("padding-top")) + 40) + "px");
                    $(".fixed-subnavbar").css("top", (parseInt($(".fixed-subnavbar").css("top")) + 40) + "px");
                }
            }
        }
        , dismiss_menu_changed_notice: function () {
            var noticeShown = !($(".menu-changed-notice").hasClass("hide"));
            if (noticeShown) {
                this.model.set("menuChanged", false);
                $(".menu-changed-notice").addClass("hide");
                $("body").css("padding-top", (parseInt($("body").css("padding-top")) - 40) + "px");
                $(".fixed-subnavbar").css("top", (parseInt($(".fixed-subnavbar").css("top")) - 40) + "px");
            }
        }

        /**
         * Simply compares two string version values.
         * 
         * Example:
         * versionCompare('1.1', '1.2') => -1
         * versionCompare('1.1', '1.1') =>  0
         * versionCompare('1.2', '1.1') =>  1
         * versionCompare('2.23.3', '2.22.3') => 1
         * 
         * Returns:
         * -1 = left is LOWER than right
         *  0 = they are equal
         *  1 = left is GREATER = right is LOWER
         *  And FALSE if one of input versions are not valid
         *
         * @function
         * @param {String} left  Version #1
         * @param {String} right Version #2
         * @return {Integer|Boolean}
         * @author Alexey Bass (albass)
         * @since 2011-07-14
         */
        //, compare_version: function (left, right) {
        //    if (typeof left + typeof right != 'stringstring')
        //        return false;

        //    var a = left.split('.')
        //    , b = right.split('.')
        //    , i = 0, len = Math.max(a.length, b.length);

        //    for (; i < len; i++) {
        //        if ((a[i] && !b[i] && parseInt(a[i]) > 0) || (parseInt(a[i]) > parseInt(b[i]))) {
        //            return 1;
        //        } else if ((b[i] && !a[i] && parseInt(b[i]) > 0) || (parseInt(a[i]) < parseInt(b[i]))) {
        //            return -1;
        //        }
        //    }

        //    return 0;
        //}
        , compare_version: function (left, right) {
            if (left === right) return 0
            else return 1;
        }
    });

    // Required, return the module for AMD compliance.
    return AppController;

});
