//SCREEN-BOILERPLATE

//this boilerplate builds screens that are gonna be shown in the <div class="content"> tag of our main HTML.
//do not build app components with this boilerplate, only screens (reports)

define([
  // Application variable, always include it to have access to app methods.
  "app",

  //templates-loader: this loads templates async.
  "js/templates-loader",
  'backgrid',
  "modules/modal",

  "Mousetrap",

  "js/jstree/jstree",
  "js/backgrid-0.3.5/extensions/select-integer-cell/backgrid-select-integer-cell",

],

function (app, T, Backgrid, Modal,  Mousetrap) {

    var TREE_NODE_ROOT_ID = -1;

    //replace all "Screen" with your view's name.
    var Screen = { Models: {}, Collections: {}, Views: {} }

    Screen.Models.Main = Backbone.Epoxy.Model.extend({
        defaults: {
            typeId: 0,
            search: '',

            procedure: '',

            types: [],

            statusCode: null,
            statusCodes: [],

            name: '',
            equipmentId: null,
            comments: null,

            mode: 'entry',
            id: null,

            isLoading: null,
        },
        computeds: {
            hasTypes: {
                deps: ['types'],
                get: function (types) {
                    return types.length != 0;
                },
            },
        },
        fetchEquipmentLog: function (options) {
            var that = this,
                qp = null;

            var opt = _.extend(
                { error: function () { }, success: function () { }, },
                options
            );

            if (opt.params) {
                //Check if params is a query parameters instance or not.
                if (opt.params.GetQueryParameter) {
                    qp = opt.params;
                }
                else {
                    qp = new QueryParameters();
                    qp.Add('id', 'VARCHAR', opt.params['id']);
                }
            }

            //qp.Add('@onlyEnabled', 'BIT', 1);

            Core.Json.CallProcedure(
                app.DatabaseNames.MES + ".EQUIP.GetEquipmentLogs",
                qp,
                {
                    onSuccess: function (resp) {
                        try {
                            if ((resp) && (resp.Table)) {
                                var records = resp.Table;
                                opt.success(records);
                            }
                            else {
                                if ((resp) && (resp.Message))
                                    console.error(resp.Message);
                                else
                                    console.error("Server response not valid.");
                            }
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },

                    onFailure: function (resp) {
                        console.error(resp);
                    },
                    Secured: true,
                    Async: false,
                },
                app.ConnectionStrings.app
            );

            return this;
        },
        fetchEquipmentLogsStatus: function () {
            var that = this,
                qp = new Core.Database.QueryParameters();

            //qp.Add('@onlyEnabled', 'BIT', 1);

            Core.Json.CallProcedure(
                app.DatabaseNames.MES + ".CAT.GetEquipmentLogsStatus",
                qp,
                {
                    onSuccess: function (resp) {
                        try {
                            if ((resp) && (resp.Table)) {
                                var records = resp.Table;

                                var newItems = _.map(records, function (obj) {
                                    return { value: obj.Code, label: obj.Name, };
                                });

                                that.set("statusCodes", newItems);
                            }
                            else {
                                if ((resp) && (resp.Message))
                                    console.error(resp.Message);
                                else
                                    console.error("Server response not valid.");
                            }
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    onFailure: function (resp) {
                        console.error(resp);
                    },
                    Secured: true,
                    Async: false,
                },
                app.ConnectionStrings.app
            );

            return this;
        },
        fetchTypes: function () {
            var that = this,
                qp = new Core.Database.QueryParameters();

            //qp.Add('@onlyEnabled', 'BIT', 1);

            Core.Json.CallProcedure(
                app.DatabaseNames.System + ".EQUIP.GetEquipmentTypes",
                qp,
                {
                    onSuccess: function (resp) {
                        try {
                            if ((resp) && (resp.Table)) {
                                var records = resp.Table;

                                var newItems = _.map(records, function (obj) { return { value: obj.Id, label: obj.Name, }; });

                                that.set("types", newItems);
                            }
                            else {
                                if ((resp) && (resp.Message))
                                    console.error(resp.Message);
                                else
                                    console.error("Server response not valid.");
                            }
                        }
                        catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                    },
                    onFailure: function (resp) {
                        console.error(resp);
                    },
                    Secured: true,
                    Async: false,
                },
                app.ConnectionStrings.app
            );

            return this;
        },
        initialize: function () {
        },
    });

    //the generate id method is called everytime a view is going to be shown by the router and returns and id that
    //is used by the router to store in cache (if it is cacheable) and to know the current shown view.
    //this is useful in case your view is reusable, and displays different data depending on url parameters 
    //(such as a catalog view, or a report that doesnt change in terms of UI but it does change in terms of data)
    //so you can always use the same view on the router but the cache can tell which view is which by using differents ids.
    Screen.generateID = function (viewParams) {
        try {
            //if the viewparams change the view id, then evaluate the viewparams here
            //and return the appropiate id.
            return "equipment-logs";
        } catch (Error) { }
    }

    Screen.Views.Main = Backbone.Epoxy.View.extend({
        template: "equipment-logs"
        , id: "equipment-logs"
        , title: "Equipment Logs"
        //default not cacheable, change this if you want the view to be cacheable
        // if the view is set as cacheable should also have a refresh method to reset the view without erasing the DOM.
        , isCacheable: false
        , events: function() {
            return {
                "click .btn-save": this.saveBtn,
                "click .btn-cancel": this.cancelBtn,
            }
        }

        , items: null
        , subviews: null
        , viewParams: null

        , initialize: function () {
            _.extend(this, this.options);

            this.state = app.view_states.loading;
            this.onappend = (_.isFunction(this.onappend)) ? this.onappend : function () { };

            var that = this;

            this.tree = null;

            var model = new Screen.Models.Main();
            
            this.model = model;
            this.model.fetchTypes();
            this.model.fetchEquipmentLogsStatus();
            
            this.items = new Screen.Models.Items();

            //this.equipmentLogs = new (EquipmentLog.Collections.EquipmentLogs)();

            this.autoRefresh = {
                    enabled: false
                    , toid: null
                    , every: 30 * 1000
                };

            this.subviews = {
                subnavbarControls: new Screen.Views.SubnavBarControls({
                    model: this.model,
                    parent: this,
                    container: app.views.subnavbar.getSectionContainer(1, 12),
                }),
            };

            if (this.viewParams.typeId) {
                this.model.set('typeId', this.viewParams.typeId)
            }

            this.bindEvents();
        }

        
        
        , bindEvents: function () {
            //this function should be in every view that uses listenTo anywhere
            //all the model bindings or view-model binding should be here, to manage
            //the show/hide view easily
            this.listenTo(this.items, "add", this.itemsChanged);
            this.listenTo(this.items, "remove", this.itemsChanged);
            this.listenTo(this.items, "change", this.itemsChanged);
            this.listenTo(this.model, "change:typeId", this.search_filters_changed);
            this.listenTo(this.model, "change:search", _.debounce(this._search_changed, 800));
        }

        , _refresh: function (opt) {
            try {
                //console.log('autorefresh: ' + new Date().toString()); 
                if (this.autoRefresh.toid != null) {
                    clearTimeout(this.autoRefresh.toid);
                    this.autoRefresh.toid = null;
                }


                this.refreshItemsColl(opt);

                if (this.autoRefresh.enabled == true) {
                    this.autoRefresh.toid = setTimeout(
                        _.bind(this._refresh, this),
                        this.autoRefresh.every
                    );
                }
            } catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
        },
        refresh: function (viewParams) {
            try {

                if (viewParams.id)
                    fixedParams.id = (viewParams.id == null) ? null : parseInt(viewParams.id, 10);
                if (viewParams.mode)
                    fixedParams.mode = (viewParams.mode == null || viewParams.mode == '') ? null : viewParams.mode;
                if (viewParams.search)
                    fixedParams.search = (viewParams.search == null || viewParams.search == '') ? null : viewParams.search;
                if (viewParams.typeId)
                    fixedParams.typeId = (viewParams.typeId == 0) ? null : parseInt(viewParams.typeId, 10);

                this.model.set(fixedParams);

                this._refresh({
                    reset: true,
                    params: _.extend({}, fixedParams, {}),
                });
            } catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
        },
        refreshItemsColl: function (options) {
            try {
                var that = this,
                    attrs = this.model.toJSON(),
                    opt = _.extend({}, { params: {}, refresh: true, }, options);

                var fetched1 = false;
                var fetched2 = false;

                if (opt && opt.showLoading) {
                    setTimeout(function () {
                        if (!fetched1 && (attrs.mode == 'edit' && !fetched2)) that.showLoading(true);
                    }, 500);
                }

                this.items.fetch(_.extend(
                    opt,
                    {
                        params: {
                            typeIds: (attrs.typeId > 0) ? attrs.typeId : null,
                            search: attrs.search,
                        },
                        codesText: app.translate(that, "root_tree_text"),
                        callback: function () {
                            //that.tree.refresh(); 

                            //Force to set loading state to false if action is MOVE because the refresh after
                            //this transaction does not modify the collection. So callback of tree changes is not
                            //fired and laoding state and jstree objects are not refreshed. Due to that it is necessary
                            //do it here.
                            if (opt.action == 'MOVE') {
                                that.setTreeLoadingState(false);

                                that.tree.refresh(true);

                                fetched1 = true;
                            }
                        },
                    })
                );

                if (options && options.params) {
                    if ((options.params.id && options.params.id != null) && (options.params.mode && options.params.mode == 'edit')) {
                        this.model.fetchEquipmentLog(_.extend(
                            {},
                            {
                                params: {
                                    id: options.params.id
                                },
                                success: function (resp) {
                                    var data = resp[0];
                                    that.model.set({
                                        name: data.EquipmentName,
                                        equipmentId: data.EquipmentId,
                                        statusCode: data.StatusCode,
                                        comments: data.Comment,
                                    });


                                    fetched2 = true;
                                }
                            },
                        ));
                    }
                }
            }
            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        },

        render: function (container, viewParams) {
            var that = this;
            var thatContainer = (container != null && container != undefined) ? container : this.container;

            //the screens have a custompath, so it has to be specified in the customPath variable that is
            //then sent to the template loader.
            var customPath = "/app/custom-screens/equipment-logs/";

            T.render.call(this, this.template, function (tmp) {
                if (!that.i18n) that.i18n = {};
                app.getI18NJed(that, that.template, function (i18nJED) {
                    //storing internationalization data
                    that.i18n[that.template] = i18nJED;
                    //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.applyBindings();

                    that.bindViewScopedEvents();

                    that.subviews.subnavbarControls.render();

                    //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")
                    //or this.$("#id")
                    //end

                    $.jstree.defaults.core.themes.variant = "large";
                    var times = 0;
                    that.$el.find(".tree").jstree({
                        core: {
                            check_callback: true,
                            data: function (obj, cb) {
                                var data = that.items.toJSON();
                                //setting disabled nodes
                                _.each(data, function (t) { t.li_attr = { "class": (t.enabled) ? "" : "node-disabled" } });
                                
                                cb.call(this, data);
                            },
                        },
                        types: {
                            //"root": {
                            //    icon: 'data:image/gif;base64, ',
                            //},
                            //"#": {
                            //    valid_children: ['root', 'area', 'line'],
                            //    //max_children: 1,
                            //},
                            //"root": {
                            //    icon: "fa fa-building",
                            //    valid_children: ['area', 'line'],
                            //},
                            //"area": {
                            //    icon: "fa fa-th-large",
                            //    valid_children: ['line']
                            //},
                            //"line": {
                            //    "icon": "fa fa-sitemap",
                            //    valid_children: ['machine'],
                            //},
                            //"machine": {
                            //    "icon": "fa fa-cog",
                            //    max_children: 0
                            //},
                            //"loading": {
                            //    "icon": "fa fa-spinner fa-spin",
                            //    valid_children: ['area', 'line', 'machine'],
                            //},
                        },
                        //contextmenu: {
                        //    items: _.bind(that.customTreeCtxMenu, that),
                        //},
                        sort: function (a, b) {
                            var nodea = this.get_node(a);
                            var nodeb = this.get_node(b);

                            var collection = that.items;
                            var model_a = collection.get(nodea.id);
                            var model_b = collection.get(nodeb.id);

                            if (model_a && model_b)
                                return model_a.get("order") > model_b.get("order") ? 1 : -1;
                            else if (model_a) return -1;
                            else if (model_b) return 1;
                            else return -1;
                        },
                        plugins: [
                            //"contextmenu",
                            "dnd", //Drag and drop
                            "wholerow",
                            "types",
                            "sort",
                        ],
                    })

                    
                    that.tree = that.$el.find(".tree").jstree(true);

                    that.$el.find(".tree").bind({
                        //"rename_node.jstree": _.bind(that.onRenameNode, that),
                        //"create_node.jstree": _.bind(that.onCreateNode, that),
                        //"delete_node.jstree": _.bind(that.onDeleteNode, that),
                        //"enable_node.jstree": _.bind(that.onEnableNode, that), 
                        //"move_node.jstree": _.bind(that.onMoveNode, that),
                        "select_node.jstree": _.bind(that.onSelectNode, that),
                        "deselect_node.jstree": _.bind(that.onDeselectNode, that),
                        "deselect_all.jstree": _.bind(that.onDeselectNode, that),
                        //"ready.jstree": _.bind(that.onReadyTree, that),
                        "refresh.jstree": _.once(function () {
                            //that.$el.find(".tree").jstree("open_all");
                            that.onReadyTree();
                        }),
                    });

                    //that.subviews.machineConfiguration.view = new Screen.Views.MachineConfiguration({
                    //    container: that.$el.find(".machine-configuration-container"),
                    //    model: new Screen.Models.MachineConfiguration(), 
                    //}); 

                    //that.subviews.machineConfiguration.view.render(); 

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

                    if (viewParams.id)
                        viewParams.id = (viewParams.id == null) ? null : parseInt(viewParams.id, 10);
                    if (viewParams.mode)
                        viewParams.mode = (viewParams.mode == null || viewParams.mode == '') ? null : viewParams.mode;
                    if (viewParams.search)
                        viewParams.search = (viewParams.search == null || viewParams.search == '') ? null : viewParams.search;
                    if (viewParams.typeId)
                        viewParams.typeId = (viewParams.typeId == 0) ? null : parseInt(viewParams.typeId, 10);

                    that.model.set(viewParams);

                    var params = that.model.toJSON();

                    that._refresh({
                        reset: true,
                        params: _.extend(
                            {},
                            params,
                            {
                            }
                        ),
                        showLoading: true,
                    });

                    that.startAutoRefresh();
                }, true, customPath);
            }, customPath, "main_template");
        },
        search_filters_changed: function () {
            try {
                var params = this.model.toJSON();

                app.router.navigate(
                    app.router.resolveURL(
                        app.router.currentModule,
                        _.extend(
                            {},
                            params,
                            {
                                section: app.router.currentParameters.section,
                                sectionParam1: params.typeId,
                            }
                        ),
                        false
                    ),
                    { trigger: false, }
                );

                this._refresh({ reset: true, });
            } catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        },
        cancelBtn: function () {
            if (this.model.get('mode') == 'entry') {
                this.model.set({
                    comments: null,
                    statusCode: null,
                    name: '',
                    equipmentId: null,
                });
            } else {
                window.history.back();
            }
            
        },
        saveBtn: function () {
            var that = this;

            this.upsertEquipmentLog(
                this.model.get('id'),
                [
                    { name: "equipmentId", type: "INT", value: this.model.get('equipmentId') },
                    { name: "statusCode", type: "VARCHAR", value: this.model.get('statusCode') },
                    { name: "comments", type: "VARCHAR", value: this.model.get('comments') },
                    { name: "timeZoneCode", type: "VARCHAR", values: app.models.user.get("timezoneCode") },

                ], function (coll, msg) {
                    that.model.set({
                        comments: null,
                        statusCode: null,
                        name: '',
                        equipmentId: null,
                    });
                    if (that.model.get('mode') == 'entry') {
                        app.views.topMessages.showMessage(app.translate(app, msg), { stay: 5 * 1000, });
                        that._refresh();
                    } else {
                        window.history.back();
                    }
                }, function (coll, msg) {
                    app.views.topMessages.showMessage(app.translate(app, msg), { stay: 5 * 1000, });
                    that._refresh();
                }
            );
        },
        upsertEquipmentLog: function (id, params, success, error) {

            var that = this;
            var QP = new QueryParameters();
            QP.Add("id", "INT", id);


            for (var q in params) {
                QP.Add(params[q].name, params[q].type, params[q].value);
            }

            Core.Json.CallProcedure(app.DatabaseNames.MES + ".EQUIP.UpsertEquipmentLog", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var data = data.Table;
                        //var ids = [];

                        if (!data[0].Message) {
                            var ids = _.pluck(data, 'Id');

                            if (success != null && _.isFunction(success))
                                success.call(this, that, 'SAVED_CHANGES_SUCCESSFUL');
                        }
                        else {
                            error.call(this, that, data[0].Message);
                        }
                    } else {
                        if (data.Message)
                            error.call(this, that, data.Message);
                        else
                            error.call(this, that);
                    }
                },
                onError: function (data) {
                    if (error != null && _.isFunction(error))
                        error.call(this, that);
                },
                Async: true,
                Secured: true,
            }, app.ConnectionStrings.app);
        },
        _search_changed: function () {
            try {
                this.doSearch.call(this); 
            } catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        },
        doSearch: function () {
            var search = this.model.get("search");
            
            this.model.set('search', search);

            this._refresh({ reset: true, });
        },

        onSelectNode: function (e, obj) {
            this.model.set('name', obj.node.text);
            this.model.set('equipmentId', parseInt(obj.node.id, 10));

        },
        onDeselectNode: function (e, obj) {
            var that = this;
            var node = obj.node;
            var instance = obj.instance;

        },
        onReadyTree: function () {
            var that = this;
            if (that.model.get('equipmentId')) {
                var id = 
                that.$el.find('.tree').jstree('open_node', [id]);
                that.$el.find('.tree').jstree('select_node', [id]);
                that.$el.find('.tree').jstree(true).get_node(id, true).children('.jstree-anchor').focus();           
            }
        },
        

        checkAddLineMachineButtons: function (e, data) {
            var btnAddArea = this.$el.find(".btn-add-area"),
                btnAddLine = this.$el.find(".btn-add-line"),
                btnAddMachine = this.$el.find(".btn-add-machine");

            switch (data.node.type.toUpperCase()) {
                case "AREA":
                    btnAddArea.prop("disabled", true);
                    btnAddLine.prop("disabled", false);
                    btnAddMachine.prop("disabled", true);
                    break;
                case "LINE":
                    btnAddArea.prop("disabled", true);
                    btnAddLine.prop("disabled", true);
                    btnAddMachine.prop("disabled", false);
                    break;
                case "MACHINE":
                    btnAddArea.prop("disabled", true);
                    btnAddLine.prop("disabled", true);
                    btnAddMachine.prop("disabled", true);
                    break;
                default:
                    btnAddArea.prop("disabled", false);
                    btnAddLine.prop("disabled", false);
                    btnAddMachine.prop("disabled", true);
                    break;
            }

            //if (data.node.type == "line") {
            //    btnAddMachine.prop("disabled", false);
            //} else {
            //    btnAddMachine.prop("disabled", true);
            //}
        },
        customTreeCtxMenu: function (node) {
            var that = this;

            //Return empty if node is disabled (disabled here means the jstree disabled, not the production item disabled status).
            if (node.state.disabled == true)
                return [];

            // The default set of all items
            var items = {
                createItem: {
                    label: "Add Item",
                    action: function (obj) {
                        that.addItem();
                    },
                    //this.addItem(),
                },
                renameItem: {
                    label: "Rename",
                    action: function (obj) {
                        that.renameNode(node);
                    },
                },
                deleteItem: {
                    label: "Delete",
                    action: function (obj) {
                        that.currentModal = new Modal.Views.Main({
                            focusOk: false,
                            focusSelector: '#btn-cancel',
                            title: app.translate([that, app], "delete_item_confirm_title"),
                            message: app.translate([that, app], "delete_item_message"),
                            buttons_type: "CONTINUE-CANCEL",
                        });

                        that.listenToOnce(that.currentModal, "continue", function (modal) {
                            try {
                                that.deleteNode(node);
                                that.currentModal = null;
                            }
                            catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
                        });

                        that.currentModal.show();

                        //that.deleteNode(node);
                    },
                },
                enableItem: {
                    label: "Enable",
                    action: function (obj) {
                        that.enableNode(node);
                    }
                }
            };

            switch (node.type.toUpperCase()) {
                //case "AREA":
                //    break;
                //case "LINE":
                //    break;
                case "MACHINE":
                    delete items["createAreaItem"];
                    break;
                case "ROOT":
                    delete items["createMachineItem"];
                    delete items["deleteItem"];
                    delete items["enableItem"];
                    delete items["renameItem"];
                    break;
            }

            //if (node.type != "line") {
            //    delete items["createItem"]; 
            //}

            if (node && node.data && !node.data.enabled) {
                delete items["createAreaItem"];
                delete items["createLineItem"];
                delete items["createMachineItem"];
                delete items["deleteItem"];
            } else {
                delete items["enableItem"];
            }

            return items;
        },
        setTreeLoadingState: function (isLoading) {
            var that = this;
            var tree = this.tree;

            var rootNode = tree.get_node(TREE_NODE_ROOT_ID);

            if (isLoading == true) {
                tree.set_type(rootNode, 'loading');

                $('.tree li').each(function () {
                    tree.disable_node(this.id);
                });
            }
            else {
                tree.set_type(rootNode, 'root');

                $('.tree li').each(function () {
                    tree.enable_node(this.id);
                });
            }
        },
        itemsChanged: function (a, b, c) {
            var fromFetch = (
                            (c && c.from && c.from == "fetch") ||
                            (!c && b && b.from == "fetch")
                            ) ? true : false;

            if (fromFetch) {
                this.debounced_refreshTree();
            }
        },
        debounced_refreshTree: _.debounce(function () {
            var that = this;
            var types = [];
            var iconedItems = [];

            //Force to set loading state to false. Maybe it is not necessary all the times
            //but some transactions do not set loading state to false because they call for a refresh.
            this.setTreeLoadingState(false);

            iconedItems = _.filter(this.items.models, function (data) {
                return data.attributes.iconId
            });

            //refresh tree icons
            for (var i = 0; i < iconedItems.length; i++) {
                if (_.indexOf(types, iconedItems[i].attributes.type.toLowerCase()) == -1 && iconedItems[i].attributes.iconId) {
                    this.tree.settings.types[iconedItems[i].attributes.type.toLowerCase()] =
                        {
                            icon: 'data:image/png;base64,' + iconedItems[i].attributes.iconData,
                            //_.findWhere(
                            //    that.model.get('icons'),
                            //    { id: that.model.get('types')[i].iconId }
                            //).data
                        };
                    types.push(iconedItems[i].attributes.type.toLowerCase());
                }
            }

            this.tree.refresh(true);
            that.showLoading(false);
        }, 500),
        showLoading: function (val) {
            var loadingPoster = this.$el.find(".loading-poster");
            var treeContainer = this.$el.find(".equipment-tree");
            var formContainer = this.$el.find(".log-form-container");

            if (val) {
                treeContainer.addClass("hide");
                formContainer.addClass("hide");
                loadingPoster.removeClass("hide");
            } else {
                loadingPoster.addClass("hide");
                treeContainer.removeClass("hide");
                formContainer.removeClass("hide");
            }
        },
        append: function (container, el) {
            el = (el != null && el != undefined) ? el : this.$el;

            if (this.state == app.view_states.loading
                || this.state == app.view_states.shown) {
                //appending view to the main container and set state to shown

                this.state = app.view_states.shown;
                container.append(el);

                this.onappend(this);
            }

            if (this.state == app.view_states.hidden) {
                //append and remain hidden
                container.append(el);
            }

            if (this.state == app.view_states.closed) {
                //return without appending.
                return;
            }
        },
        _autoRefresh: function (opt) {
            if (this.autoRefresh.toid != null) {
                clearTimeout(this.autoRefresh.toid);
                this.autoRefresh.toid = null;
            }

            this.refresh(opt);

            if (this.autoRefresh.enabled == true) {
                this.autoRefresh.toid = setTimeout(_.bind(this._autoRefresh, this), 30 * 1000);
            }
        },
        bindViewScopedEvents: function () {
        },
        close: function () {
            this.state = app.view_states.closed;

            //If currentModal exists, hide it and erase it.
            if (this.currentModal) {
                this.currentModal.hide();
                this.currentModal = null;
            }

            this.stopAutoRefresh();
            this.closeSubviews();
            this.remove();
            this.unbindViewScopedEvents();
            this.unbind();
        },
        closeSubviews: function () {
            _.each(this.subviews, function (sview) {
                if (sview.cid) sview.close();
            });
        },
        hide: function () {
            this.state = app.view_states.hidden;

            this.$el.hide();
            this.unbind();
            this.stopListening();
        },
        preRender: function () {
            app.models.subnavbar.set("dateControl", false);
            app.models.subnavbar.set("notificationBar", false);
            app.models.subnavbar.set("dateTimeScopeControl", false);
            app.models.subnavbar.set("subnavbar", true);
            app.models.subnavbar.set("sections", "12");
        },
        reRender: function (viewParams) {
            try {
                var that = this; 

                this.refresh(viewParams);
            } catch (Error) { }
        },
        show: function () {
            this.state = app.view_states.shown;

            this.bindEvents();
            this.$el.show();
        },
        startAutoRefresh: function () {
            try {
                if (this.autoRefresh.enabled !== true) {
                    var that = this;

                    if (this.autoRefresh.toid != null) {
                        clearTimeout(this.autoRefresh.toid);
                        this.autoRefresh.toid = null;
                    }

                    this.autoRefresh.enabled = true;

                    //use a timeout to execute the first refresh to return the handle to the start function caller.
                    //So when the caller finish it will do the first refresh.
                    this.autoRefresh.toid = setTimeout(
                        _.bind(this._refresh, this),
                        1
                    );
                }
            } catch (error) { console.error((error.stack) ? error.stack : new Error(error).stack); }
        },
        stopAutoRefresh: function () {
            if (this.autoRefresh.toid != null) {
                clearTimeout(this.autoRefresh.toid);
                this.autoRefresh.toid = null;
            }
            this.autoRefresh.enabled = false;
        },
        unbindViewScopedEvents: function () {
        },


    });

    Screen.Models.Item = Backbone.Model.extend({
        initialize: function () {
        }
        , defaults: {
            id: null,
            parent: null,
            type: null,
            text: null,
            order: null,
            iconId: null,
            iconData: null,
            deleted: false,
            enabled: true,
        }
    });

    Screen.Models.Items = Backbone.Collection.extend({
        model: Screen.Models.Item,
        initialize: function () {
            //_.bindAll(this);

            this.bindEvents();
        },
        fetch: function (opt) {
            var options = {
                method: "set",
                async: true,
                callback: null,
                codesText: "",
            };

            options = _.extend(options, (opt) ? opt : {});

            var that = this,
                QP = new Core.Database.QueryParameters();

            if (options.params) {
                QP.Add("@TypeIds", "VARCHAR", options.params.typeIds);
                QP.Add("@Search", "VARCHAR", options.params.search);
            }

            var items = [];
            items.push({
                id: TREE_NODE_ROOT_ID,
                parent: '#',
                type: "root",
                text: options.codesText,
                state: {
                    opened: true,
                },
            });

            Core.Json.CallProcedure(app.DatabaseNames.System + ".EQUIP.GetEquipments", QP, {
                onSuccess: function (data) {
                    if (Core.Object.Eval(data, "Table")) {
                        var icons = data.Table3;
                        var data = data.Table;

                        for (var i = 0; i < data.length; i++) {
                            var itemData = data[i];
                            var equipment = {
                                id: itemData.Id,
                                parent: ((itemData.ParentId != null) && (itemData.ParentId != -1))
                                    ? itemData.ParentId
                                    : TREE_NODE_ROOT_ID,
                                type: itemData.TypeName.toLowerCase(),
                                text: itemData.Name,
                                order: itemData.Order - 1,
                                deleted: itemData.Deleted,
                                enabled: !itemData.Deleted,
                                data: {
                                    enabled: !itemData.Deleted,
                                },
                                iconId: itemData.IconId,
                                iconData: (itemData.IconId)
                                    ?
                                    _.findWhere(
                                        icons,
                                        { Id: itemData.IconId }
                                    ).Data
                                    :
                                    null
                            };

                            items.push(equipment);
                        }
                    }

                    that[options.method](items, { from: "fetch" });

                    if (options.callback != null && _.isFunction(options.callback))
                        options.callback.call(this, that);
                },
                Async: options.async,
                Secured: true,
            }, app.ConnectionStrings.app);

            return this;
        },
        bindEvents: function () {
            //this.listenTo(this, "add", this.syncToDB);
            //this.listenTo(this, "remove", this.syncToDB);
            //this.listenTo(this, "change", this.syncChangeToDB);
        },
        syncChangeToDB: function (a, b, c) {
            var from = (c && c.from) ? c.from : "unknown";
            if (from != "fetch") {
                if (a && a.changed && a.changed["text"]) {
                    this.upsertItem(a.get("id"), [
                        { name: "Name", type: "VARCHAR", value: a.get("text") }
                    ]);
                }
            }
        },
        upsertItem: function (id, props, success, error) {
            var that = this;
            var QP = new QueryParameters();
            QP.Add("Id", "INT", id);

            for (var q in props) {
                QP.Add(props[q].name, props[q].type, props[q].value);
            }

            Core.Json.CallProcedure(app.DatabaseNames.System + ".EQUIP.UpsertEquipmentLog", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var data = data.Table;
                        //var ids = [];

                        if (!data[0].Message) {
                            var ids = _.pluck(data, 'Id');

                            if (success != null && _.isFunction(success))
                                success.call(this, that, ids);
                        }
                        else {
                            error.call(this, that, data[0].Message);
                        }
                    } else {
                        error.call(this, that);
                    }
                },
                onError: function (data) {
                    if (error != null && _.isFunction(error))
                        error.call(this, that);
                },
                Async: true,
                Secured: true,
            }, app.ConnectionStrings.app);
        },
    });

    //subview for the subnavbar controls
    Screen.Views.SubnavBarControls = Backbone.Epoxy.View.extend({
        id: 'equipment-logs-subnavbar-controls',
        title: '',
        template: 'equipment-logs',

        initialize: function () {
            _.extend(this, this.options);

            this.state = app.view_states.loading;
            this.onappend = (_.isFunction(this.onappend)) ? this.onappend : function () { };

            if (this.model == null)
                this.model = new Screen.Models.Main();

            this.bindEvents();
        },
        events: {
        },

        render: function (container, onComplete) {
            var that = this;
            var thatContainer = (container) ? container : (this.container) ? this.container : null;
            var onViewComplete = (onComplete) ? onComplete : function () { };

            //the screens have a custompath, so it has to be specified in the customPath variable that is
            //then sent to the template loader.
            var customPath = "/app/custom-screens/" + this.template + "/";

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

                    var ctx = {
                        editable: (($.inArray('AdminUserRole', app.models.user.get('roles')) != -1
                            || $.inArray('SupervisorUserRole', app.models.user.get('roles')) != -1) ? true : false),
                    };

                    //loading the view and appeding it to the views's $el.
                    that.$el.html(tmp(
                        _.extend({}, ctx, (that.model) ? that.model.toJSON() : {})
                    ));

                    that.applyBindings();

                    //that.$el.find('.clear-search').clearSearch();

                    that.append(thatContainer, that.$el);

                }, true, customPath);
            }, customPath, 'subnavbar_controls');

        },
        bindEvents: function () {
            //this function should be in every view that uses listenTo anywhere
            //all the model bindings or view-model binding should be here, to manage
            //the show/hide view easily
        },

        append: function (container, el) {
            el = (el != null && el != undefined) ? el : this.$el;

            if (this.state == app.view_states.loading
                || this.state == app.view_states.shown) {
                //appending view to the main container and set state to shown

                this.state = app.view_states.shown;
                container.append(el);

                this.onappend(this);
            }

            if (this.state == app.view_states.hidden) {
                //append and remain hidden
                container.append(el);
            }

            if (this.state == app.view_states.closed) {
                //return without appending.
                return;
            }
        },
        close: function () {
            this.state = app.view_states.closed;

            this.remove();
            this.unbind();
        },
        show: function () {
            this.state = app.view_states.shown;

            this.bindEvents();
            this.$el.show();
        },
        hide: function () {
            this.state = app.view_states.hidden;

            this.$el.hide();
            this.unbind();
            this.stopListening();
        },
    });

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

});
