//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",

  "modules/modal",

  "js/bootstrap-select/bootstrap-select",
  "js/jstree/jstree", 
],

function (app, T, Modal) {

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

    DelayCodes.Models.TreeItem = Backbone.Model.extend({
        initialize: function () {
        }
        , defaults: {
            id: null,
            parent: null,
            type: null,
            text: null,
        }
    });

    DelayCodes.Models.TreeItems = Backbone.Collection.extend({
        model: DelayCodes.Models.TreeItem,
        initialize: function () {
            _.bindAll(this);

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

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

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

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

            Core.Json.CallProcedure(app.DatabaseNames.OEE + ".WebApp.GetDelayCodesTree", QP, {
                onSuccess: function (data) {
                    if (Core.Object.Eval(data, "Table")) {
                        var data = data.Table;

                        for (var i = 0; i < data.length; i++) {
                            var itemData = data[i];
                            var prodItem = {
                                id: itemData.Id,
                                parent: (itemData.ParentId != null) ? itemData.ParentId : -1,
                                type: "code",
                                text: itemData.Code,
                            };

                            items.push(prodItem);
                        }
                    }

                    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 () {
        },
        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.OEE + ".WebApp.UpsertDelayCode", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var data = data.Table;
                        var ids = _.pluck(data, 'Id');

                        if (success != null && _.isFunction(success))
                            success.call(this, that, ids);
                    } else {
                        error.call(this, that); 
                    }
                },
                Async: true,
                Secured: true,
            }, app.ConnectionStrings.app);
        },
        deleteItem: function (id, success, error) {
            var that = this;
            var QP = new QueryParameters();

            QP.Add("@Id", "INT", id);

            Core.Json.CallProcedure(app.DatabaseNames.OEE + ".WebApp.RemoveDelayCode", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var data = data.Table;
                        var ids = _.pluck(data, 'Id');

                        if (success != null && _.isFunction(success))
                            success.call(this, that, ids);
                    } else {
                        error.call(this, that);
                    }
                },
                Async: true,
                Secured: true,
            }, app.ConnectionStrings.app);
        },
        addNode: function (text, parent, success, error) {
            var that = this; 
            this.upsertItem(null, [
                { name: "ParentId", type: "INT", value: (parent == "-1") ? null : parent },
                { name: "Code", type: "VARCHAR", value: text },
            ], function (ref, ids) {
                that.add({
                    id: ids[0],
                    parent: (parent == "#") ? '#' : parseInt(parent),
                    type: "code", 
                    text: text,
                });

                if (success && _.isFunction(success))
                    success.call(this, that, ids); 
            }, 
            function (ref) {
                if (error && _.isFunction(error))
                    error.call(this, that); 
            });
        },
        renameNode: function (id, text, success, error) {
            var that = this;
            var model = this.get(id); 
            if (model){
                this.upsertItem(id, [
                    { name: "Code", type: "VARCHAR", value: text }
                ], function (ref, ids) {
                        if (_.indexOf(ids, parseInt(id)) != -1) {
                            model.set("text", text);

                            if (success && _.isFunction(success))
                                success.call(this, that, ids);
                        } else {
                            if (error && _.isFunction(error))
                                error.call(this, that);
                        }
                }, function (ref) {
                    if (error && _.isFunction(error))
                        error.call(this, that);
                });
            }else{
                if (error && _.isFunction(error))
                    error.call(this, that);
            }
        },
        deleteNode: function (id, success, error) {
            var that = this;
            var model = this.get(id);
            if (model) {
                this.deleteItem(
                    id
                    , function (ref, ids) {
                        //removing from collection; 
                        that.remove(model);

                        if (success && _.isFunction(success))
                            success.call(this, that, ids);
                    },
                    function (ref) {
                        if (error && _.isFunction(error))
                            error.call(this, that);
                    }
                );
            }
        },
    });

    DelayCodes.Models.Main = Backbone.Model.extend({
        defaults: {
            procedure: '',
            delayCodesTreeItems: null, 
        },
        initialize: function () {
            this.set("delayCodesTreeItems", new DelayCodes.Models.TreeItems());
        }, 
    });

    //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.
    DelayCodes.generateID = function (viewParams) {
        try {
            //if the viewparams change the view id, then evaluate the viewparams here
            //and return the appropiate id.
            return "delay-codes"; 
        } catch (Error) { }
    }

    DelayCodes.Views.Main = Backbone.View.extend({
        template: "delay-codes"
        , id: "delay-codes"
        , title: "Delay Codes"
        //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: true
        , initialize: function () {
            this.options.state = app.view_states.loading;
            this.options.onappend = (_.isFunction(this.options.onappend)) ? this.options.onappend : function () { };

            if (this.options.viewParams) {
            }

            this.options.delayCodesTree = null; 

            var model = new DelayCodes.Models.Main({
                procedure: "dbo.procedureName"
            });

            this.model = model;

            this.options.MYREFERENCES = {
                autoRefresh: {
                    enabled: true
                    , toid: null
                }
            };

            this.options.MYREFERENCES.subviews = {
                codeConfiguration: { view: null, model: null }, 
            };

            this.bindEvents();
            _.bindAll(this);
        },

        events: {
            "click .btn-add-code": "addCode",
        }, 

        render: function (container) {
            var that = this;
            var thatContainer = (container != null && container != undefined) ? container : this.options.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.oeeModule.screensPath + "OEEConfiguration/delay-codes/";

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

                    //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.model.get("delayCodesTreeItems").toJSON(); 
                                cb.call(this, data);
                            },
                        },
                        types: {
                            "#": {
                                valid_children: ['root'],
                                max_children: 1, 
                            },
                            "root": {
                                icon: "fa fa-ellipsis-h",
                                valid_children: ['code'],
                            }, 
                            "code": {
                                "icon": "fa fa-circle-thin",
                                valid_children: ['code'],
                                max_depth: 1, 
                            },
                        }, 
                        contextmenu: {
                            items: that.customDelayCodesTreeCtxMenu, 
                        },
                        plugins: [
                            "contextmenu",
                            "wholerow",
                            "types",
                        ], 
                    });

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

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

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

                    that._startAutoRefresh(); 
                }, true, customPath); 
            }, customPath, "main_template");
        }

        , customDelayCodesTreeCtxMenu: function (node) {
            var that = this; 
            // The default set of all items
            var items = {
                createItem: {
                    label: "Add Code",
                    action: that.addCode, 
                }, 
                renameItem: {
                    label: "Rename",
                    action: function (obj) {
                        that.renameNode(node); 
                    }, 
                },
                deleteItem: {
                    label: "Delete",
                    action: function (obj) {
                        that.deleteNode(node); 
                    }, 
                }
            };

            if (node.parent == "#") {
                delete items["renameItem"];
                delete items["deleteItem"];
            }

            if (node.parent != "#" && node.parent != "-1")
                delete items["createItem"]; 

            return items;
        }

        , onCreateNode: function (e, obj) {
            var node = obj.node;
            var instance = obj.instance; 
            var collection = this.model.get("delayCodesTreeItems"); 
            collection.addNode(node.text, node.parent, function (ref, ids) {
                instance.set_id(node, ids[0]);
                instance.edit(node); 
            }, function () {
                instance.refresh(); 
            }); 
        }

        , onRenameNode: function(e, obj){
            var node = obj.node;
            var instance = obj.instance;
            var collection = this.model.get("delayCodesTreeItems");
            collection.renameNode(node.id, node.text, function (ref, ids) {
                instance.set_id(node, ids[0]);
            }, function () {
                instance.refresh();
            });
        }

        , onDeleteNode: function (e, obj) {
            if (this.options.MYREFERENCES.subviews.codeConfiguration.view)
                this.options.MYREFERENCES.subviews.codeConfiguration.view.close();

            var node = obj.node;
            var instance = obj.instance;
            var collection = this.model.get("delayCodesTreeItems");
            collection.deleteNode(node.id, function (ref, ids) {
            }, function () {
                instance.refresh();
            });
        }

        , onSelectNode: function (e, obj) {
            this.checkAddCodeButtons(e, obj);

            var that = this;
            var node = obj.node;
            var instance = obj.instance;
            var collection = this.model.get("delayCodesTreeItems");

            if (this.options.MYREFERENCES.subviews.codeConfiguration.view)
                this.options.MYREFERENCES.subviews.codeConfiguration.view.close(); 

            if (obj.selected.length < 2) {
                if (node.type == "code") {
                    var codeConfigurationContainer = this.$el.find(".code-configuration-container");

                    var model = new DelayCodes.Models.CodeConfiguration();
                    this.options.MYREFERENCES.subviews.codeConfiguration.view = new DelayCodes.Views.CodeConfiguration({
                        container: codeConfigurationContainer,
                        model: model,
                    });

                    model.fetch({
                        data: {
                            id: node.id,
                        }
                    });

                    model.fetchLinesMachines();

                    this.options.MYREFERENCES.subviews.codeConfiguration.view.render();
                }
            }
        }

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

            if (this.options.MYREFERENCES.subviews.codeConfiguration.view)
                this.options.MYREFERENCES.subviews.codeConfiguration.view.close();
        }

        , renameNode: function (data) {
            var tree = this.options.delayCodesTree;
            var selected = tree.get_selected();
            
            if (selected.length > 0)
                data = selected[0]; 

            if (data) {
                tree.edit((data.id) ? data.id : data);
            }
        }

        , deleteNode: function (data) {
            var that = this;

            var modal = new Modal.Views.Main({
                focusOk: false,
                focusSelector: '#btn-cancel',
                title: app.translate([this, app], "delete_item_modal_confirm_title"),
                message: app.translate([this, app], "delete_item_modal_confirm_message"),
                buttons_type: "CONTINUE-CANCEL"
            });

            modal.on("continue", function () {
                try {
                    var tree = that.options.delayCodesTree;
                    var selected = tree.get_selected();

                    if (selected.length > 0)
                        data = selected;

                    tree.delete_node(data);
                }
                catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
            });

            modal.show();
        }

        , addCode: function (e, data) {
            var tree = this.options.delayCodesTree;
            var selected = tree.get_selected(); 

            if (!selected.length) { return false; }
            var sel = selected[0];
            var selected_node = tree.get_node(sel);

            sel = tree.create_node(sel, { "type": "code" }, "last", function (a, b, c) {
                a; 
            });
        }

        , nodeDoubleClick: function (e, data) {
            var node = $(e.target).closest("li");
            var data = this.options.delayCodesTree.get_node(node.prop("id"));

            if (data && data.id) {
                this.options.delayCodesTree.edit(data.id);
            }
        }

        , checkAddCodeButtons: function (e, data) {
            var btnAddCode = this.$el.find(".btn-add-code"); 
            if (data.node.parent == "#" || data.node.parent == "-1") {
                btnAddCode.prop("disabled", false);
            } else {
                btnAddCode.prop("disabled", true);
            }
        }

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

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

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

                this.options.onappend(this);
            }

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

            if (this.options.state == app.view_states.closed) {
                //return without appending.
                return;
            }
        }

        , _startAutoRefresh: function () {
            try {
                if (this.options.MYREFERENCES.autoRefresh.toid != null) {
                    clearTimeout(this.options.MYREFERENCES.autoRefresh.toid);
                    this.options.MYREFERENCES.autoRefresh.toid = null;
                }

                this.options.MYREFERENCES.autoRefresh.enabled = true;

                this._autoRefresh();
            } catch (Error) { }
        }

        , _autoRefresh: function () {
            if (this.options.MYREFERENCES.autoRefresh.toid != null) {
                clearTimeout(this.options.MYREFERENCES.autoRefresh.toid);
                this.options.MYREFERENCES.autoRefresh.toid = null;
            }

            this.refresh();

            if (this.options.MYREFERENCES.autoRefresh.enabled == true) {
                this.options.MYREFERENCES.autoRefresh.toid = setTimeout(this._autoRefresh, 5000);
            }
        }

        , _stopAutoRefresh: function () {
            if (this.options.MYREFERENCES.autoRefresh.toid != null) {
                clearTimeout(this.options.MYREFERENCES.autoRefresh.toid);
                this.options.MYREFERENCES.autoRefresh.toid = null;
            }
            this.options.MYREFERENCES.autoRefresh.enabled = false;
        }

        , refresh: function () {
            try {
                var that = this; 
                this.model.get("delayCodesTreeItems").fetch({
                    codesText: app.translate(that, "codes_tree_text"), 
                    //callback: function () {
                    //    that.options.delayCodesTree.refresh(); 
                    //}, 
                });
            } catch (Error) { }
        }

        , linesTreeItemsChanged: function (a, b, c) {
            var fromFetch = (
                            (c && c.from && c.from == "fetch") ||
                            (!c && b && b.from == "fetch")
                            ) ? true : false;

            if (fromFetch) {
                this.debounced_refreshLinesTree(); 
            }
        }

        , debounced_refreshLinesTree: _.debounce(function(){
            this.options.delayCodesTree.refresh(); 
        }, 500)  

        , 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.model.get("delayCodesTreeItems"), "add", this.linesTreeItemsChanged);
            this.listenTo(this.model.get("delayCodesTreeItems"), "remove", this.linesTreeItemsChanged);
            this.listenTo(this.model.get("delayCodesTreeItems"), "change", this.linesTreeItemsChanged);
        }

        , close: function () {
            this._stopAutoRefresh();
            this.options.state = app.view_states.closed;

            this.remove();
            this.unbind();
        }

        , show: function () {
            this.options.state = app.view_states.shown;

            this.bindEvents();
            this.$el.show();
        }

        , hide: function () {
            this.options.state = app.view_states.hidden;
            this._stopAutoRefresh();

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

        , preRender: function () {
            app.models.subnavbar.set("dateControl", false);
            app.models.subnavbar.set("subnavbar", false);
        }

        , reRender: function () {
            this._startAutoRefresh();
        }
    });

    DelayCodes.Models.CodeConfiguration = Backbone.Epoxy.Model.extend({
        defaults: {
            id: null,
            code: null,

            categoryId: null,
            description: null,
            excludeFromAvailability: null,
            linesId: [],

            useTagToDeclare: null,
            tagToDeclareId: null,

            _configureMaxTimeAllowed: false,
            maxTimeAllowed: null,
            maxTimeAllowedTime: null,
            hasChildren: false,

            //behind the scenes
            categories: [],
            categoriesBinding: [],
            linesCat: [],
            tags: [],
            tagsBinding: [],
            tagsBindingDigital: [],
            tagsBindingReal: [],
        }
        , computeds: {
            category: {
                    get: function () {
                        return this.get("categoryId");
                    },
                    set: function (val) {
                        return { categoryId: (val != -1) ? parseInt(val) : null };
                    }
            },
            categoryColor: function () {
                var categories = this.get("categories");
                var cat = _.findWhere(categories, {
                    Id: this.get("categoryId"), 
                });

                if (cat) return cat["Color"];
                else return "#fff"; 
            },
            configureMaxTimeAllowed: {
                get: function () {
                    var mta = this.get("_configureMaxTimeAllowed") || parseInt(this.get("maxTimeAllowed")); 
                    return mta == true || (mta != null && _.isNumber(mta) && mta > 0); 
                },
                set: function (v) {
                    return {
                        maxTimeAllowed: v ? this.get("maxTimeAllowed") : null, 
                        _configureMaxTimeAllowed: v
                    };
                }
            },
            linesIdString: {
                deps: ['linesId'],
                get: function (items) {
                    return (items)
                            ? items.join(',')
                            : '';
                },
            },
        }

        , initialize: function () {
            var opts = { loaded: false, loadedLinesCat: false, }; 
            this.options = _.extend(this.options ? this.options : {}, opts);
        }
        , fetch: function (options) {
            var that = this; 

            var QP = new QueryParameters();
            if (options.data) {
                if (options.data.id) QP.Add("Id", "INT", options.data.id);
            }

            Core.Json.CallProcedure(app.DatabaseNames.OEE + ".WebApp.GetDelayCodeConfiguration", QP, {
                onSuccess: function (data) {
                    if (Core.Object.Eval(data, "Table.0")) {
                        var codeData = data.Table[0];
                        var categoriesList = data.Table1; 
                        var tagList = data.Table2;
                        var linesList = data.Table3;

                        var categoriesBinding = _.map(categoriesList, function (obj) { return { label: obj.Name, value: obj.Id }; });
                        var tagsBinding = _.map(tagList, function (obj) { return { label: obj.Name, value: obj.Id }; });
                        var tagsBindingReal = _.map(_.where(tagList, { DataType: 'REAL' }), function (obj) { return { label: obj.Name, value: obj.Id }; });
                        var tagsBindingDigital = _.map(_.where(tagList, { DataType: 'DIGITAL' }), function (obj) { return { label: obj.Name, value: obj.Id }; });

                        var codeConfiguration = _.extend({}, that.attributes, {
                            id: codeData.Id,
                            code: codeData.Code,

                            categoryId: codeData.CategoryId,
                            description: codeData.Description,
                            excludeFromAvailability: codeData.ExcludeFromAvailability,
                            linesId: _.pluck(linesList, 'ProductionItemId'),

                            useTagToDeclare: codeData.UseTagToDeclare,
                            tagToDeclareId: codeData.TagToDeclareId,

                            _configureMaxTimeAllowed: codeData.MaxTimeAllowed != null && _.isNumber(codeData.MaxTimeAllowed) && codeData.MaxTimeAllowed > 0, 
                            maxTimeAllowed: codeData.MaxTimeAllowed,
                            maxTimeAllowedTime: codeData.MaxTimeAllowedTime,
                            hasChildren: codeData.HasChildren, 

                            //behind the scenes
                            categories: categoriesList,
                            categoriesBinding: categoriesBinding,
                            tags: tagList,
                            tagsBinding: tagsBinding,
                            tagsBindingDigital: tagsBindingDigital,
                            tagsBindingReal: tagsBindingReal,
                        });

                        that.options.loaded = true;
                        that.set(codeConfiguration, { from: "fetch" });
                    }
                },
                Async: true,
                Secured: true
            }, app.ConnectionStrings.app);
        }
        , fetchLinesMachines: function () {
            var that = this;
            Core.Json.CallProcedure(app.DatabaseNames.OEE + ".WebApp.GetProductionItems", null, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var items = data.Table;

                        that.options.loadedLinesCat = true;

                        that.set(
                            {
                                linesCat: _.map(_.filter(items, function (m) { return m.ProductionItemType.toUpperCase() == "LINE"; }), function (m) {
                                    return { value: m.Id, label: m.Name, };
                                }),
                            },
                            { from: "fetch" }
                        );
                    }
                },
                Async: true,
                Secured: true,
            }, app.ConnectionStrings.app);
        }
        , save: function (opt) {
            var that = this; 
            var options = {
                callback: function () { }
            };

            _.extend(options, opt); 

            var QP = new QueryParameters();

            var params = [
                ["@Id", "INT", "id"],
                ["@Code", "VARCHAR", "code"],
                ["@CategoryId", "INT", "categoryId"],
                ["@Description", "VARCHAR", "description"],
                ["@ExcludeFromAvailability", "BIT", "excludeFromAvailability"],
                ["@UseTagToDeclare", "BIT", "useTagToDeclare"],
                ["@TagToDeclareId", "INT", "tagToDeclareId"],
                ["@MaxTimeAllowed", "INT", "maxTimeAllowed"],
                ["@MaxTimeAllowedTime", "VARCHAR", "maxTimeAllowedTime"],
                ["@LinesId", "VARCHAR", "linesIdString"],
            ]; 

            for (var i = 0, len = params.length; i < len; i++) {
                var param = params[i]; 
                QP.Add(param[0], param[1], this.get(param[2])); 
            }

            Core.Json.CallProcedure(app.DatabaseNames.OEE + ".WebApp.UpdateDelayCode", QP, {
                onSuccess: function (data) {
                    if (Core.Object.Eval(data, "Table.0")) {

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

    DelayCodes.Views.CodeConfiguration = Backbone.Epoxy.View.extend({
        template: "delay-codes"
        , id: "delay-codes"
        , title: "Delay Codes"
        //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
        , bindings: "data-bind"
        , initialize: function () {
            this.options.state = app.view_states.loading;
            this.options.onappend = (_.isFunction(this.options.onappend)) ? this.options.onappend : function () { };

            if (this.options.viewParams) {
            }

            this.options.MYREFERENCES = {
                autoRefresh: {
                    enabled: true
                    , toid: null
                }
            };

            this.options.MYREFERENCES.subviews = {};

            this.bindEvents();
            //_.bindAll(this);
        },

        events: {
            "click .btn-save": "saveCodeConfiguration",
            "click .btn-cancel": "cancelCodeConfiguration", 
        },

        render: function (container, viewParams) {
            var that = this;
            var thatContainer = this.options.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.oeeModule.screensPath + "OEEConfiguration/delay-codes/";

            if ((this.model.options.loaded) && (this.model.options.loadedLinesCat)) {
                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
                        if (!that.options.i18n[that.template])
                            that.options.i18n[that.template] = i18nJED;

                        //loading the view and appeding it to the views's $el.
                        that.$el.html(tmp(that.model.toJSON()));

                        that.applyBindings(); 

                        that.$el.find('.selectpicker').selectpicker();

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

                        //end:

                    }, true, customPath);
                }, customPath, "code_configuration");
            } else {
                setTimeout(function () {
                    if ((!that.model.options.loaded) || (!that.model.options.loadedLinesCat)) {
                        that.$el.html('<div style="text-align:center;margin-top:10px;"><i class="fa fa-5x fa-cog fa-spin"></i><br /></div>');
                        that.append(thatContainer, that.$el);
                    }
                }, 300); 
            }
        }

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

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

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

                this.options.onappend(this);
            }

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

            if (this.options.state == app.view_states.closed) {
                //return without appending.
                return;
            }
        }

        , reRender: function (viewParams) {
            try {
            } catch (Error) { }
        }

        , refresh: function (viewParams) {
        }

        , checkButtonsState: function (a, b, c) {
            var fromFetch = (b && b.from == "fetch") ? true : false;
            if (!fromFetch) {
                this.setSaveCancelButtons(true); 
            }
        }

        , checkRender: function (a, b, c) {
            var fromFetch = (b && b.from == "fetch") ? true : false;
            if (fromFetch) {
                this.render(); 
            }
        }

        , setSaveCancelButtons: function (val) {
            var btnSave = this.$el.find(".btn-save");
            var btnCancel = this.$el.find(".btn-cancel");

            btnSave.prop("disabled", !val);
            btnCancel.prop("disabled", !val);
        }

        , saveCodeConfiguration: function () {
            var that = this; 

            this.setSaveCancelButtons(false);
            this.model.save({
                callback: function () {
                    that.model.fetch({
                        data: {
                            id: that.model.get("id"),
                        }
                    });
                }
            }); 
        }

        , cancelCodeConfiguration: function () {
            this.setSaveCancelButtons(false); 
            this.model.fetch({
                data: {
                    id: this.model.get("id"), 
                }
            }); 
        }

        , 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.model, "change", this.checkRender);
            this.listenTo(this.model, "change:linesIdString", this.checkRender);
            this.listenTo(this.model, "change", this.checkButtonsState); 
        }

        , bindViewScopedEvents: function () {
        }

        , unbindViewScopedEvents: function () {
        }

        , close: function () {
            this.options.state = app.view_states.closed;

            this.closeSubviews();
            this.remove();
            this.unbindViewScopedEvents();
            this.unbind();
        }

        , closeSubviews: function () {
            _.each(this.options.MYREFERENCES.subviews, function (sview) {
                sview.close();
            });
        }

        , show: function () {
            this.options.state = app.view_states.shown;

            this.showSubviews();
            this.bindEvents();
            this.$el.show();
        }

        , showSubviews: function () {
            _.each(this.options.MYREFERENCES.subviews, function (sview) {
                sview.show();
            });
        }

        , resetModel: function () {
            this.model.set(this.model.defaults);
        }

        , hide: function () {
            this.options.state = app.view_states.hidden;

            this.resetModel();
            this.hideSubviews();

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

        , hideSubviews: function () {
            _.each(this.options.MYREFERENCES.subviews, function (sview) {
                sview.hide();
            });
        }

        , preRender: function () {
            app.models.subnavbar.set("dateControl", false);
            app.models.subnavbar.set("dateTimeScopeControl", false);
            app.models.subnavbar.set("sections", "4-4-4");
            app.models.subnavbar.set("subnavbar", true);
        }
    });

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

});
