//this view will handle the form for user login, and also will render itself 
//differently when the user is already logged.

define([
  // Application.
  "app",

  "Mousetrap",

  //templates-loader
  "js/templates-loader"

],

function (app, Mousetrap, T) {

    //we are hardcoding for now just to test
    var defaultURLSHARDCODED = {
        "MESADMIN": "!/meltshop"
        , "LF": "!/processReports/LF"
        , "EAF": "!/processReports/EAF"
        , "CASTER": "!/processReports/CASTER"
    };

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

    User.Model = Backbone.Model.extend({
        defaults: {
            logged: null, 
            username: "",
            roles: null,
            defaultURL: "",
            preferredLanguage: null,
            timezoneCode: null,
            timezoneIsAutomatic: false,
            accountNumber: null,
            maxTags: null,
            maxAgents: null,
            ihServerHost: null,
            userId: null, 
            autorefresh: {
                toid: null
                , delay: 15000
                , enabled: true
            },
            checkComputerTimezone: {
                toid: null
                , delay: 10000
                , offset: null
                , dst: null
                , enabled: false
            }
        },
        initialize: function () {
            _.bindAll(this); 

            /**************************/
            /*MOUSETRAP KEY SHORTCUTS*/
            Mousetrap.bind('ctrl+l', function (e) {
                if (e.preventDefault) {
                    e.preventDefault();
                } else {
                    // internet explorer
                    e.returnValue = false;
                }

                $("#signIn-drop").dropdown('toggle');
                $("#user_username").select();

                return false;
            });
            /**************************/
            /*MOUSETRAP KEY SHORTCUTS*/

            this.options = {}; 
            this.options.checkLoggedTOUT = null;

            this.listenTo(this, "change:timezoneIsAutomatic", function () { this.autoCheckComputerTimezone(this.get("timezoneIsAutomatic")); });
        },
        fetch: function (opt) {
            var that = this; 
            var options = {
                async: true
            }; 

            options = _.extend(options, opt); 

            var auto = this.get("autorefresh");
            if (auto.toid != null) {
                clearTimeout(auto.toid);
                auto.toid = null;
            }

            //overriding fetch method
            //according to our needs.
            var jsonObj = {};
            Core.Object.Extend(this.attributes, jsonObj);

            var keepAutofetch = function () {
                _.defer(that.autofetch);
            };

            var connectionLost = function (resp) {
                try {
                    that.updateNetMonitorSpeed(0); 
                } catch (error) { console.log("Error while trying to handle connection lost. Exception: " + error.toString()); }
                keepAutofetch();
            };

            var parseResp = function (resp) {
                try{
                    var _that = this;
                    jsonObj.roles = SecurityLogin.GetRoles(app.ConnectionStrings.app);

                    if (!_.contains(jsonObj.roles || {}, "FrontEndRole")) {
                        jsonObj.logged = false;
                    }

                    jsonObj.defaultURL = (defaultURLSHARDCODED[jsonObj.username]) ? defaultURLSHARDCODED[jsonObj.username] : "";

                    var setAndReturn = function () {
                        //change method is fired.
                        this.set(this.parse(jsonObj), {});
                        keepAutofetch();
                        return this;
                    }

                    var QP = new Core.Database.QueryParameters();
                    Core.Json.CallProcedure("FrontEnd.GetUserSystemInfo", QP, {
                        onSuccess: function (data) {
                            if (Core.Object.Eval(data, "Table.0")) {
                                jsonObj.preferredLanguage = data.Table[0].PreferredLanguage;
                                jsonObj.maxTags = data.Table[0].MaxTags;
                                jsonObj.maxAgents = data.Table[0].MaxAgents;

                                jsonObj.ihServerHost = data.Table[0].IHServerHost;

                                if (data.Table[0].TimeZoneAbbreviation != null && data.Table[0].TimeZoneAbbreviation != undefined) {
                                    jsonObj.timezoneCode = (data.Table[0].TimeZoneAbbreviation).toString().trim();
                                    jsonObj.timezoneIsAutomatic = false;
                                }
                                else { if (!jsonObj.timezoneIsAutomatic) { jsonObj.timezoneCode = null; jsonObj.timezoneIsAutomatic = true; } }

                                jsonObj.accountNumber = data.Table[0].Number;
                                jsonObj.userId = data.Table[0].UserID;
                            }

                            if (options.async) {
                                setAndReturn.call(_that);
                            }
                        },
                        onError: connectionLost, 
                        Async: options.async,
                        Secured: true,
                        CachePerUser: true, 
                    }, app.ConnectionStrings.app);

                    if (!options.async) {
                        setAndReturn.call(this); 
                    }
                } catch (error) {
                    keepAutofetch(); 
                }
            };
            
            if (options.async) {
                SecurityLogin.GetUserName(function (resp) {
                    jsonObj.username = that.removeDomain((resp) ? resp.toUpperCase() : "");
                    return parseResp.call(that);
                }, connectionLost)
            } else {
                jsonObj.logged = SecurityLogin.IsLogged();
                jsonObj.username = this.removeDomain((SecurityLogin.GetUserName()) ? SecurityLogin.GetUserName().toUpperCase() : "");

                return parseResp.call(that); 
            }
        },
        login: function (username, password) {
            var login = SecurityLogin.Login(username, password);
            var roles = SecurityLogin.GetRoles(app.ConnectionStrings.app);
            if (!_.contains(roles || {}, "FrontEndRole")) {
                SecurityLogin.Logoff();
                login = false; 
            } else {
                this.fetch({ async: false });
            }
            return login; 
        }

        , logout: function () {
            var logout = SecurityLogin.Logoff();
            this.set(this.defaults); 
            this.fetch({ async:false });
        }

        , autofetch: function () {
            var auto = this.get("autorefresh"); 
            if (auto.toid != null) {
                clearTimeout(auto.toid);
                auto.toid = null; 
            }

            if (auto.enabled) auto.toid = setTimeout(this.fetch, auto.delay);
        }

        , stop_autofetch: function () {
            var auto = this.get("autorefresh");
            var loggedTOUT = this.options.checkLoggedTOUT;

            if (loggedTOUT != null) {
                clearTimeout(loggedTOUT);
                loggedTOUT = null; 
            }
            
            auto.enabled = false; 
            if (auto.toid != null) {
                clearTimeout(auto.toid);
                auto.toid = null;
            }
        }
        , updateNetMonitorSpeed: function (speed) {
            app.models.networkMonitor.set("speed", speed); 
        }
        , checkLogged: function () {
            var that = this;
            if (that.options.checkLoggedTOUT) clearTimeout(that.options.checkLoggedTOUT);

            var requestStartMs = new Date();
            SecurityLogin.IsLogged(function (resp) {
                try{
                    var requestEndMs = new Date();
                    var msTaken = requestEndMs - requestStartMs;
                    var duration = msTaken / 1000.0;

                    //The request size is 170 bytes, measured with Chrome Dev Tools.
                    var reqSize = 170;

                    //Convert to bits to do the calculation.
                    var bitsLoaded = reqSize * 8;

                    //Calculate bits per second.
                    var speedBps = (bitsLoaded / duration);

                    //Convert to kilo bits per second.
                    var speedKbps = (speedBps / 1000);

                    that.updateNetMonitorSpeed(speedKbps);

                    that.set("logged", resp);
                } catch (error) {
                } finally {
                    that.options.checkLoggedTOUT = setTimeout(that.checkLogged, 15000); 
                }
            }, function () {
                try{
                    that.updateNetMonitorSpeed(0);
                } catch (error) { } finally {
                    that.options.checkLoggedTOUT = setTimeout(that.checkLogged, 15000); 
                }
            });
        }

        , updateTimezoneFromComputerTimezone: function () {
            var timezoneCode;
            var detectedTimezone = Core.DateTime.GetDateTimeZone();
            var QP = new QueryParameters();
            QP.Add('Offset', 'FLOAT', detectedTimezone.Offset);
            QP.Add('isDST', 'BIT', detectedTimezone.Daylight);

            var computerTimezone = this.get("checkComputerTimezone");
            computerTimezone.offset = detectedTimezone.Offset;
            computerTimezone.dst = detectedTimezone.Daylight;

            Core.Json.CallProcedure(app.DatabaseNames.System + ".FrontEnd.GetAutomaticTimeZone", QP, {
                onSuccess: function (data) {
                    if (Core.Object.Eval(data, 'Table.0')) {
                        var timezoneData = data.Table[0];
                        timezoneCode = (Core.Object.Eval(timezoneData, 'Abbreviation')) ? Core.String.Trim(timezoneData.Abbreviation) : null;
                    }
                },
                onFailure: function (data) {
                    data;
                },
                Async: false,
            }, app.ConnectionStrings.app);
            this.set("timezoneCode", timezoneCode);
        }

        , removeDomain: function (str) {
            return str.substring(str.indexOf("/") + 1);
        }

        //@@overrides
        //overriding get and set method to allow custom getters/setters
        , get: function (attr) {
            // Call the getter if available
            if (_.isFunction(this.getters[attr])) {
                return this.getters[attr].call(this);
            }

            return Backbone.Model.prototype.get.call(this, attr);
        },

        set: function (key, value, options) {
            var attrs, attr;

            // Normalize the key-value into an object
            if (_.isObject(key) || key == null) {
                attrs = key;
                options = value;
            } else {
                attrs = {};
                attrs[key] = value;
            }

            // always pass an options hash around. This allows modifying
            // the options inside the setter
            options = options || {};

            // Go over all the set attributes and call the setter if available
            for (attr in attrs) {
                if (_.isFunction(this.setters[attr])) {
                    attrs[attr] = this.setters[attr].call(this, attrs[attr], options);
                }
            }

            return Backbone.Model.prototype.set.call(this, attrs, options);
        },

        getters: {
            timezoneCode: function () {
                var timezoneCode = this.attributes["timezoneCode"];
                if (timezoneCode == null) {
                    this.updateTimezoneFromComputerTimezone(); 
                    this.set("timezoneIsAutomatic", true);
                }
                return this.attributes["timezoneCode"];
            }
        },
        setters: {
        },

        autoCheckComputerTimezone: function () {
            var auto = this.get("checkComputerTimezone");
            if (auto.toid != null) {
                clearTimeout(auto.toid);
                auto.toid = null;
            }

            if (arguments.length > 0) {
                if (arguments.length == 1) {
                    auto.enabled = arguments[0]; 
                }
            }

            if (auto.enabled) {
                auto.toid = setTimeout(this.checkComputerTimezone, auto.delay); 
            }
        }, 
        checkComputerTimezone: function () {
            var computerTimezone = this.get("checkComputerTimezone");
            if (computerTimezone.toid != null) {
                clearTimeout(computerTimezone.toid);
                computerTimezone.toid = null;
            }

            if (!this.get("timezoneIsAutomatic")) return;

            var detectedTimezone = Core.DateTime.GetDateTimeZone();
            
            if (detectedTimezone.Offset != computerTimezone.offset || detectedTimezone.Daylight != computerTimezone.dst) {
                this.updateTimezoneFromComputerTimezone();
            }

            _.defer(this.autoCheckComputerTimezone);
        }
    });

    User.Views.Login = Backbone.View.extend({
        template: "user/userLogin-notLogged"
        , id: "user-login"
        , el: null
        , initialize: function () {
            this.bindEvents(); 
        },
        // global view variable (seen in this scopy, public to the view, and SHARED BETWEEN OTHER INSTANCES OF THE SAME VIEW)
        // containing all the variables for this view

        //properties that you wanna scope as private variables for each instance of a view should not be placed here
        //the only way i found to maintain the variables between instances of the same view, is either using models,
        // (each view will have its own model so data is not shared between them), or in case you don't want to use a model
        // you can use the Backbone.View.options object, and doing something like
        // this.options.attributes = {}
        // and storing every single variable inside attributes.
        events: {
            "click #signIn_btn": "loginUser",
            "click #signIn_btn_mobile": "loginUser_mobile",
            "click #translation_test_button": "test_translation",
            "click #signIn-drop": "resetSignInForm"
        },
        render: function (container) {
            var that = this;
            var thatContainer = container;

            var logged = this.model.get("logged"); 

            if (logged == true) { this.template = "user/userLogin-logged"; }
            else if (logged == false) { this.template = "user/userLogin-notLogged"; }

            T.render.call(this, this.template, function (tmp) {
                //getInternationalizationData
                if (!that.options.i18n) that.options.i18n = {};
                app.getI18NJed(that, that.template, function (i18nJED) {
                    //storing internationalization data
                    that.options.i18n[that.template] = i18nJED;

                    that.$el.empty();
                    //start: before the view is visible, but the template was already loaded (not instanced nor appended)

                    //end:
                    //loading the view and appeding it to the views's $el.
                    that.$el.html(tmp(that.model.toJSON()));
                    //start: the view was already loaded an is on a div element, but not appended to the main container
                    //here you can perform anything you want DOM related, by getting the dom element via that.$el.find("#id")

                    //:end

                    //appending view to the main container
                    //thatContainer.append(that.$el);
                }, false);
            });

        } 

        , bindEvents: function () {
            this.listenTo(this.model, "change", this.render);
        }

        , loginUser: function (source) {
            var username = $("#user_username", this.$el).val();
            var password = $("#user_password", this.$el).val();

            var status = this.model.login(username, password);
            if (!status) {
                $("#user_controlgroup").addClass("error");
                $("#login_wrong_credentials-help-inline").show();
                $("#user_username").select();
            }

        }
        , loginUser_mobile: function () {
            var username = $("#user_username_mobile", this.$el).val();
            var password = $("#user_password_mobile", this.$el).val();

            var status = this.model.login(username, password);
        }
        , test_translation: function () {
            //alert(app.i18n.translate("I have the %1$s %2$s").fetch(
            //    app.i18n.translate("black").fetch(), app.i18n.translate("shirt").fetch()
            //    )
            //);
        }
        , close: function () {
            this.remove();
            this.unbind();
        }
        , show: function () {
            this.bindEvents(); 
            this.$el.show();
        }
        , hide: function () {
            this.$el.hide();
            this.unbind();
            this.stopListening(); 
        }

        //extra
        , resetSignInForm: function () {
            $("#user_controlgroup").removeClass("error");
            $("#login_wrong_credentials-help-inline").hide();
            $("#user_login_form")[0].reset();

            setTimeout(function () {
                if ($('#user_login_form').css("display") != "none")
                    $("#user_username").focus();
            }, 200);
        }
    });

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

});
