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

    'moment',
    'modules/modal-select-equipment-list/modal-select-equipment-list',
    "js/jstree/jstree", 
    'backgrid/infinator',
    'backgrid/moment-cell',
    'backgrid/grouped-columns',

    "js/jquery.floatThead/jquery.floatThead",

],

    function (app, T, Backgrid, Modal,moment,EQPModal) {
    //replace all "Screen" with your view's name.
        var Screen = { Models: {}, Views: {}, Collections: {} }



    Screen.Models.Tree = Backbone.Model.extend({
        defaults: {
            id: null,
            parent: null,
            type: null,
            text: null,
            state: null,
            data: null,
        },

        parse: function (item) {
            var nodeText = '';
            nodeText = item.L1PositionName ? item.L1PartTypeName + ' ' +  item.L1PositionName + (item.L2PartName ? ' | ' + item.L2PartName : '') :
                item.L1PartTypeName + (item.L2PartName ? ' | ' + item.L2PartName : '');

            nodeText = nodeText + (item.PartialValue ? ' | ' + item.PartialValue : '');
            var result = {
                id: item.Id,
                parent: item.ParentId ? item.ParentId : "#",
                type: item.StatusCode === 'O' ? "status-ok" : (item.StatusCode === 'W' ? "status-warning" : (item.StatusCode === 'B' ? 'status-empty' : "status-alert")),
                text: nodeText,
                state: { "opened": item.ExpandTree === 1 ? true : false, "type": item.L1PartTypeId, "nodeData": item },
                data: item,
                IAccept: item.IAccept,
                IAm: item.IAm,
                treeType: item.ExpandTree === 1 ? 'Online' : 'Offline'
            };

            return result;
        }
    });
    Screen.Models.Main = Backbone.Model.extend({
        defaults: {
            treeItemsOffline: null,
            treeItemsOnline: null,

            dndSource: null,
            dndTarget: null,
            dndAllowed: false,

            treeDataLoading: false,
        },
        initialize: function () {
            this.set("treeItemsOnline", new Screen.Collections.Tree());
            this.set("treeItemsOffline", new Screen.Collections.Tree());

            this.fetchTrees();
        },
        callDatabaseFailed: function () {
            this.get('treeItemsOnline').setDataColl([]);
            this.get('treeItemsOffline').setDataColl([]);
            this.fetchTrees();
        },
        fetchTrees: function () {
            var that = this,
                qp = new Core.Database.QueryParameters();

       

            that.set({ treeDataLoading: true });
            Core.Json.CallProcedure(
                app.DatabaseNames.MES + ".EQP.GetCurrentPartsTreeWeb",
                qp,
                {
                    onSuccess: function (resp) {
                        try {
                            if ((resp) && (resp.Table) && (resp.Table1)) {
                                that.get('treeItemsOnline').setDataColl(resp.Table);
                                that.get('treeItemsOffline').setDataColl(resp.Table1);
                                that.trigger('trees-ready');
                            }
                            else {
                                if ((resp) && (resp.Message)) {
                                    console.error(new Error(resp.Message).stack);
                                    app.views.topMessages.showMessage('CALL TO DATABASE FAILED', { stay: 5000, });
                                }
                                else {
                                    app.views.topMessages.showMessage('SERVER RESPONSE NOT VALID', { stay: 5000, });
                                    console.error(new Error('SERVER_RESPONSE_NOT_VALID').stack);
                                }
                                that.set({ treeDataLoading: false });
                            }
                        }
                        catch (e) {
                            console.error((e.stack) ? e.stack : new Error(e).stack);
                            that.set({ treeDataLoading: false });
                        }
                    },
                    onFailure: function (resp) {
                        console.error(resp);
                        that.set({ treeDataLoading: false });
                    },
                    Secured: true,
                    Async: true,
                },
                app.ConnectionStrings.app
            );
            return this;
        },
        

        movePart: function (params) {
            var that = this,
                qp = new Core.Database.QueryParameters();

            //var part = null;
            //if (isNaN(params.partId) && params.partId.includes('-')) {
            //    part = params.partId.split('-');
            //    part = parseInt(part[0]);
            //} else {
            //    part = parseInt(params.partId)
            //}
  
            //qp.Add('@PartId', 'INT', part);
            //qp.Add('@ParentPartId', 'INT', params.parentPartId === '#' ? null : params.parentPartId);
            //qp.Add('@PositionId', 'INT', null);


            qp.Add('@PartId', 'INT', params.partId);
            qp.Add('@ParentPartId', 'INT', params.parentPartId === '#' ? null : params.parentPartId);
            qp.Add('@PositionId', 'INT', null);


            Core.Json.CallProcedure(
                app.DatabaseNames.MES + ".EQP.MovePart",
                qp,
                {
                    onSuccess: function (resp) {
                        try {

                            if ((resp) && (resp.Table)) {
                                app.views.topMessages.showMessage('Part Moved Successfully', { stay: 5000, });                               
                                that.trigger('tree-changed');
                            } else {

                                that.trigger('tree-changed');

                                that.callDatabaseFailed();
                                if ((resp) && (resp.Message)) {
                                    console.error(new Error(resp.Message).stack);
                                    app.views.topMessages.showMessage(resp.Message, { stay: 5000, });
                                } else {
                                    app.views.topMessages.showMessage('SERVER RESPONSE NOT VALID', { stay: 5000, });
                                    console.error(new Error('SERVER_RESPONSE_NOT_VALID').stack);
                                };
                            }
                        }
                        catch (e) {
                            that.trigger('tree-changed');

                            that.callDatabaseFailed();
                            console.error((e.stack) ? e.stack : new Error(e).stack);
                        }
                    },
                    onFailure: function (resp) {
                        that.trigger('tree-changed');

                        that.callDatabaseFailed();
                        console.error(resp);
                    },
                    Secured: true,
                    Async: true,
                },
                app.ConnectionStrings.app
            );
            return this;
        },
        fixPartialMetric: function (params) {
            var that = this,
                qp = new Core.Database.QueryParameters();

            qp.Add('@PartId', 'INT', params.partId);
            qp.Add('@MetricTypeId', 'INT', params.metricTypeId);
            qp.Add('@NewPartialValue', 'FLOAT', params.newPartialValue);
            Core.Json.CallProcedure(
                app.DatabaseNames.MES + ".EQP.FixPartialMetric",
                qp,
                {
                    onSuccess: function (resp) {
                        try {

                            if ((resp) && (resp.Table)) {
                                app.views.topMessages.showMessage('Metric changed successfully', { stay: 5000, });
                                that.trigger('tree-changed');
                            } else {

                                that.callDatabaseFailed();
                                if ((resp) && (resp.Message)) {
                                    console.error(new Error(resp.Message).stack);
                                    app.views.topMessages.showMessage(resp.Message, { stay: 5000, });
                                } else {
                                    app.views.topMessages.showMessage('SERVER RESPONSE NOT VALID', { stay: 5000, });
                                    console.error(new Error('SERVER_RESPONSE_NOT_VALID').stack);
                                };
                                that.trigger('tree-changed');
                            }
                        }
                        catch (e) {

                            that.callDatabaseFailed();
                            console.error((e.stack) ? e.stack : new Error(e).stack);
                        }
                    },
                    onFailure: function (resp) {

                        that.callDatabaseFailed();
                        console.error(resp);
                    },
                    Secured: true,
                    Async: true,
                },
                app.ConnectionStrings.app
            );
            return this;
        },
        createNewPart: function (params) {
            var that = this,
                qp = new Core.Database.QueryParameters();

            qp.Add('@PartTypeId', 'INT', params.partTypeId);
            qp.Add('@PartName', 'VARCHAR', params.partName);
            qp.Add('@ParentPartId', 'INT', params.parentPartId); 

            Core.Json.CallProcedure(
                app.DatabaseNames.MES + ".EQP.CreatePartWeb",
                qp,
                {
                    onSuccess: function (resp) {
                        try {

                            if ((resp) && (resp.Table)) {
                                app.views.topMessages.showMessage('Part created successfully', { stay: 5000, });
                                that.trigger('tree-changed');
                            } else {

                                that.callDatabaseFailed();
                                if ((resp) && (resp.Message)) {
                                    console.error(new Error(resp.Message).stack);
                                    app.views.topMessages.showMessage(resp.Message, { stay: 5000, });
                                } else {
                                    app.views.topMessages.showMessage('SERVER RESPONSE NOT VALID', { stay: 5000, });
                                    console.error(new Error('SERVER_RESPONSE_NOT_VALID').stack);
                                };
                                that.trigger('tree-changed');
                            }
                        }
                        catch (e) {

                            that.callDatabaseFailed();
                            console.error((e.stack) ? e.stack : new Error(e).stack);
                        }
                    },
                    onFailure: function (resp) {
                        console.error(resp);
                    },
                    Secured: true,
                    Async: true,
                },
                app.ConnectionStrings.app
            );
            return this;
        },
        createNewSpare: function (params) {
            var that = this,
                qp = new Core.Database.QueryParameters();
		
            qp.Add('@PartTypeId', 'INT', params.partTypeId);
            qp.Add('@PartName', 'VARCHAR', params.partName);
            qp.Add('@ParentPartId', 'INT', params.parentPartId);
            Core.Json.CallProcedure(
                app.DatabaseNames.MES + ".EQP.CreatePartWeb",
                qp,
                {
                    onSuccess: function (resp) {
                        try {

                            if ((resp) && (resp.Table)) {
                                app.views.topMessages.showMessage('Part created successfully', { stay: 5000, });
                                that.trigger('tree-changed');
                            } else {

                                that.callDatabaseFailed();
                                if ((resp) && (resp.Message)) {
                                    console.error(new Error(resp.Message).stack);
                                    app.views.topMessages.showMessage(resp.Message, { stay: 5000, });
                                } else {
                                    app.views.topMessages.showMessage('SERVER RESPONSE NOT VALID', { stay: 5000, });
                                    console.error(new Error('SERVER_RESPONSE_NOT_VALID').stack);
                                };
                                that.trigger('tree-changed');
                            }
                        }
                        catch (e) {

                            that.callDatabaseFailed();
                            console.error((e.stack) ? e.stack : new Error(e).stack);
                        }
                    },
                    onFailure: function (resp) {
                        console.error(resp);
                    },
                    Secured: true,
                    Async: true,
                },
                app.ConnectionStrings.app
            );
            return this;
        },
        resetEquipment: function (node) {
            var L2PartId = node.data.L2PartId;
            var that = this,
                qp = new Core.Database.QueryParameters();
            qp.Add('@PartId', 'INT', L2PartId);
            Core.Json.CallProcedure(
                app.DatabaseNames.MES + ".EQP.ResetPart",
                qp,
                {
                    onSuccess: function (resp) {
                        try {
                            if ((resp) && (resp.Table)) {
                                app.views.topMessages.showMessage('Part Reseted  Successfully', { stay: 5000, });
                                that.trigger('tree-changed');
                            } else {

                                that.callDatabaseFailed();
                                if ((resp) && (resp.Message)) {
                                    console.error(new Error(resp.Message).stack);
                                    app.views.topMessages.showMessage(resp.Message, { stay: 5000, });
                                } else {
                                    app.views.topMessages.showMessage('SERVER RESPONSE NOT VALID', { stay: 5000, });
                                    console.error(new Error('SERVER_RESPONSE_NOT_VALID').stack);
                                };
                                that.trigger('tree-changed');
                            }
                        }
                        catch (e) {
                            that.callDatabaseFailed();
                            console.error((e.stack) ? e.stack : new Error(e).stack);
                        }
                    },
                    onFailure: function (resp) {
                        that.callDatabaseFailed();
                        console.error(resp);
                        that.trigger('tree-changed');
                    },
                    Secured: true,
                    Async: true,
                },
                app.ConnectionStrings.app
            );
            return this;
        },

        removeEquipment: function (node) {
            var L2PartId = node.data.L2PartId;
            var that = this,
                qp = new Core.Database.QueryParameters();
            qp.Add('@PartId', 'INT', L2PartId);
            Core.Json.CallProcedure(
                app.DatabaseNames.MES + ".EQP.RemovePart",
                qp,
                {
                    onSuccess: function (resp) {
                        try {
                            if ((resp) && (resp.Table)) {
                                app.views.topMessages.showMessage('Part Removed Successfully', { stay: 5000, });                            
                                that.trigger('tree-changed');
                            } else {

                                if ((resp) && (resp.Message)) {
                                    console.error(new Error(resp.Message).stack);
                                    app.views.topMessages.showMessage(resp.Message, { stay: 5000, });
                                } else {
                                    app.views.topMessages.showMessage('SERVER RESPONSE NOT VALID', { stay: 5000, });
                                    console.error(new Error('SERVER_RESPONSE_NOT_VALID').stack);
                                };
                                that.trigger('tree-changed');
                            }
                        }
                        catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                    },
                    onFailure: function (resp) {
                        console.error(resp);
                        that.trigger('tree-changed');
                    },
                    Secured: true,
                    Async: true,
                },
                app.ConnectionStrings.app
            );
            return this;


        },
    });



    //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 "caster-equipments-tree";
        } catch (Error) { }
    }

    Screen.Views.Main = Backbone.View.extend({
        template: "caster-equipments-tree"
        , id: "caster-equipments-tree"
        , title: "Caster Equipments Tree"
        //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
        , popup: null  
        , initialize: function () {
            this.options.state = app.view_states.loading;
            this.options.onappend = (_.isFunction(this.options.onappend)) ? this.options.onappend : function () { };

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

            this.options.screensTree = null;
            this.options.screensTreeOffline = null;
            this.options.MYREFERENCES = {};

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

            this.bindEvents();
        },
     


        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/custom-screens/caster-equipments-tree/";

            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;
        

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

                        // --------------------
                        // -- Online Tree
                        // --------------------
                        $.jstree.defaults.core.themes.variant = "large";                  
                        that.$el.find(".onlineTree").jstree({
                            core: {
                                expand_selected_onload: false,
                               // check_callback: true,
                                check_callback: function (operation, node, node_parent, node_position, more) {
                                    // operation can be 'create_node', 'rename_node', 'delete_node', 'move_node' or 'copy_node'

                                    if (operation === "move_node") {

                                        var source = node.original;
                                        var target = node_parent.original;
                                        var isAllowed = that.dndIsAllowed(source, target);

                                        that.model.set({
                                            dndSource: source,
                                            dndTarget: target,
                                            dndAllowed: isAllowed,
                                        })
                                        if (!isAllowed) return false;
                                        else return true;
                                    } else {

                                        return true;  //allow all other operations
                                    }
                                },
                                data: function (obj, cb) {
                                    var data = that.model.get("treeItemsOnline").toJSON();                               
                                    cb.call(this, data);
                                },
                                multiple: false,
                            },
                            types: {
                                "#": {
                                    valid_children: ['root'],
                                    max_children: 1,
                                },
                                "status-ok": {
                                    icon: "status-ok glyphicon glyphicon-flash",     
                                    //max_children:1,
                                },
                                "status-warning": {
                                    icon: "status-warning",
                                },
                                "status-alert": {
                                    icon: "status-alert",
                                },
                                "status-empty": {
                                    icon: "status-empty",
                                }
                            },
                            contextmenu: {
                                items: that.customCtxMenu,
                                select_node: false,
                            },                       
                            plugins: [
                                "contextmenu",
                                "wholerow",
                                "types",
                                "dnd",
                            ],
                            dnd: {
                                is_draggable: true,
                                check_while_dragging: true,
                            },
                     
                        });
                        that.options.screensTree = that.$el.find(".onlineTree").jstree(true);
                        that.$el.find(".onlineTree").bind({
                            "select_node.jstree": that.onSelectNodeTreeOnline,
                            "deselect_node.jstree": that.onDeselectNode,
                            "deselect_all.jstree": that.onDeselectNode,
                            "load_node.jstree": that.customizeNodeMarkup,
                            "before_open.jstree": that.customizeNodeMarkup,
                            "close_all.jstree": that.customizeNodeMarkup,
                            "refresh.jstree": _.once(function (el) {
                                that.options.screensTree.select_node(that.options.screensTree.get_node("-1"));
                            }),
                   
                        });

                        // --------------------
                        // -- Offline Tree
                        // --------------------
                        that.$el.find(".offlineTree").jstree({
                            core: {
                                expand_selected_onload: false,
                                // check_callback: true,
                                check_callback: function (operation, node, node_parent, node_position, more) {
                                    // operation can be 'create_node', 'rename_node', 'delete_node', 'move_node' or 'copy_node'                              

                                    if (operation === "move_node") {
                                        var source = node.original;
                                        var target = node_parent.original;

                                        var isAllowed = that.dndIsAllowed(source, target);

                                        that.model.set({
                                            dndSource: source,
                                            dndTarget: target,
                                            dndAllowed: isAllowed,
                                        })

                                        if (!isAllowed) return false;
                                        else return true;
                                    } else {
                                        return true;  //allow all other operations
                                    }
                                },
                                data: function (obj, cb) {
                                    var data = that.model.get("treeItemsOffline").toJSON();
                                    cb.call(this, data);
                                },
                                multiple: false,
                            },
                            types: {
                                "status-ok": {
                                    icon: "status-ok glyphicon glyphicon-flash",
                                    //max_children:1,
                                },
                                "status-warning": {
                                    icon: "status-warning",
                                },
                                "status-alert": {
                                    icon: "status-alert",
                                },
                                "status-empty": {
                                    icon: "status-empty",
                                }
                            },
                            contextmenu: {
                                items: that.customCtxMenu,
                                select_node:false,
                            },
                            plugins: [
                                "contextmenu",
                                "wholerow",
                                "types",
                                "dnd",
                            ],
                            dnd: {
                                is_draggable: true,
                                check_while_dragging: true,
                            },
                       

                        }); 
                        that.options.screensTreeOffline = that.$el.find(".offlineTree").jstree(true);
                        that.$el.find(".offlineTree").bind({
                            "select_node.jstree": that.onSelectNodeTreeOffline,
                            "deselect_node.jstree": that.onDeselectNode,
                            "deselect_all.jstree": that.onDeselectNode,
                            "load_node.jstree": that.customizeNodeMarkup,
                            "before_open.jstree": that.customizeNodeMarkup,
                            "close_all.jstree": that.customizeNodeMarkup,
                            "refresh.jstree": _.once(function () {
                                that.options.screensTreeOffline.select_node(that.options.screensTree.get_node("-1"));

                            }),


                        });

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

                        that.onLoadingScript();
                    },
                    true,
                    customPath);
                }, customPath
            );
        }

        , dndIsAllowed: function (source, target) {

            var found = false;

            if (!target || !source) return false;
            var IAcceptArray = target.IAccept ? target.IAccept : null;
            var IAmArray = source.IAm ? source.IAm : null;
            //if (source && target && source.treeType && target.treeType && source.treeType === 'Online' && target.treeType === 'Offline') return true;
            //if (source && target && source.treeType && target.treeType && source.treeType === 'Offline' && target.treeType === 'Online') return true; return true;

            if (target && source && target.parent && source.parent && target.id === source.parent) return false;
            if (target && source && target.parent && source.parent && target.parent === source.parent) return false;
            if (!IAcceptArray || !IAmArray) return false;

            _.each(IAmArray.split(','), function (obj) {
                if (IAcceptArray.split(',').indexOf(obj) > -1)  found = true;
            })
            if (IAcceptArray.split(',').indexOf(IAmArray) > -1 || found === true) return true;
            else return false;
        }
        // Refresh + refresh when the trees change
        , refresh: function () {
            try {
                this.onLoadingScript();
                this.model.fetchTrees();

                this.onDeselectNodeTreeOnline();
                this.onDeselectNodeTreeOffline();

            } catch (Error) { }
        }
        , tree_changed: function () {
            this.refresh();
        }

        , trees_ready: function () {
            var that = this;
            try {
                setTimeout(
                    function () {
                        that.model.set({
                            treeDataLoading: false,
                        });
                        that.onCloseLoadingScript();
                    },
                    500
                );
            }
            catch (e) {
                console.error((e.stack) ? e.stack : new Error(e).stack);
                that.model.set({
                    treeDataLoading: false,
                })
            }
        }

        , bindEvents: function () {
            var that = this;
            this.listenTo(this.model, 'trees-ready', this.trees_ready);
            this.listenTo(this.model, 'tree-changed', this.tree_changed);
            this.listenTo(this.model.get("treeItemsOnline"), "add", this.treeItemsChanged);
            this.listenTo(this.model.get("treeItemsOnline"), "remove", this.treeItemsChanged);
            this.listenTo(this.model.get("treeItemsOnline"), "change", this.treeItemsChanged);

            this.listenTo(this.model.get("treeItemsOffline"), "add", this.treeItemsOfflineChanged);
            this.listenTo(this.model.get("treeItemsOffline"), "remove", this.treeItemsOfflineChanged);
            this.listenTo(this.model.get("treeItemsOffline"), "change", this.treeItemsOfflineChanged);

            $(document).on('dnd_stop.vakata', function (e, data) {
                var dndSource = that.model.get('dndSource');
                var dndTarget = that.model.get('dndTarget');
                var dndAllowed = that.model.get('dndAllowed');
                if (dndAllowed) {
                    var sourceData = dndSource.state.nodeData;
                    var targetData = dndTarget.state.nodeData;
                    that.model.movePart({
                        partId: sourceData.L2PartId,
                        parentPartId: targetData.L2PartId,
                        positionId: targetData.L1PositionId,
                    });
                }
            });
            _.bindAll(this);
        }


        // Context menu + pop-up
        , customCtxMenu: function (node) {
            var that = this;

            var items = {};
            this.onDeselectNodeAllTreeOffline();
            this.onDeselectNodeTreeOnline();
            const { IAccept, L2PartId, L2PartName, L1PartName, L1PartTypeName } = node.data
           
            // L1 --> Parent
            // L2 --> Current Node
            // IAccept means that the current node allows children
            // L2PartId means that is something already installed on that node.

            if (L2PartId !== null && node.data.IsReplaceable) { 
                items.remove = {
                    label: `Uninstall ${L2PartName} from ${L1PartName}`,
                    action: function (obj) {
                        that.openModal(node, 'REMOVE');
                    },
                    icon: "fa fa-times",
                    disabled: true,

                };
            
            }
            if (L2PartId === null) {
                items.selectEquipment = {
                    label: `Install Part ${L1PartTypeName} in ${L1PartName}`,
                    action: function (obj) {
                        that.openModal(node, 'SELECT');
                    },
                    icon: "fa fa-navicon",
                };               
            }
            if (IAccept !== null) {
                items.installSubPart = {
                    label: `Install Sub Part in ${L2PartName}`,
                    action: function (obj) {
                        that.openModal(node, 'SUB-PART');
                    },
                    icon: "fa fa-code-fork",
                };
            }
            if (L2PartId !== null) {
                items.reset = {
                    label: `Reset ${L2PartName}`,
                    action: function (obj) {
                        that.openModal(node, 'RESET');
                    },
                    icon: "fa fa-refresh",
                };
            }
            if (IAccept !== null && node.data.IsReplaceable) {
                items.addEquipment = {
                    label: `Create New ${L1PartTypeName}`,
                    action: function (obj) {
                        that.openModal(node, 'ADD');
                    },
                    icon: "fa fa-plus",
                    separator_after: true,
                    separator_before: true,
                };
            }
            if (IAccept !== null && node.data.IsArray) {
                items.addEquipment = {
                    label: `Create New Spare ${L1PartTypeName}`,
                    action: function (obj) {
                        that.openModal(node, 'ADD-SPARE');
                    },
                    icon: "fa fa-plus",
                    separator_after: true,
                    separator_before: true,
                };
            }
            if (L2PartId !== null) {
                items.fixPartialMetric = {
                    label: `Fix Partial Metric on ${L2PartName}`,
                    action: function (obj) {
                        that.openModal(node, 'FIX');
                    },
                    icon: "fa fa-wrench",
                };
            }
                
            return items;

        }
        , openModal: function (node, mode) {
            var that = this;
            var data = node.data;
            that.popup = null;
            if ($('.modal.in').length == 0) {
                that.popup = new EQPModal.Views.ModalSelectItem({
                    parent: this,
                    data: data,
                    mode: mode,
                    bus: null,
                });
                this.listenTo(that.popup, 'close', function () {
                    try {
                        that.popup = null;
                    }
                    catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                });
                this.listenTo(that.popup, 'accept', function (params) {
                    try {
                        if (mode === 'REMOVE') {
                            that.model.removeEquipment(node);
                        }
                        if (mode === 'RESET') {
                            that.model.resetEquipment(node);
                        }
                        if (mode === 'SELECT') {
                            that.model.movePart(params);
                        }
                        if (mode === 'ADD') {
                            that.model.createNewPart(params);
                        }
                        if (mode === 'ADD-SPARE') {
                            that.model.createNewSpare(params);
                        }
                        if (mode === 'FIX') {
                            that.model.fixPartialMetric(params);
                        }
                        if (mode === 'SUB-PART') {
                            that.model.movePart(params);
                        }

                    }
                    catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                });
                try {
                    if ($('.modal.in').length == 0) { //Check again if there is another modal of any kind displayed to prevent issues.

                        that.popup.show();
                    }
                    else {
                        that.popup.close();
                        that.popup = null;


                        that.refresh();
                    }
                }
                catch (e) {
                    if (that.popup != null) {
                        that.popup.close();
                        that.popup = null;

                        that.refresh();
                    }
                    app.views.topMessages.showMessage(app.translate([that, app], 'MODAL_DISPLAY_ERROR'), { stay: 5 * 1000, });
                    console.error((e.stack) ? e.stack : new Error(e).stack);
                }


            }
        }

        // Customize Tree
        // OPTIMIZED: Skip close_all events (no visible nodes need markup),
        // scope DOM queries to the opened node's subtree for before_open,
        // use DocumentFragment to batch DOM insertions (reduces reflows).
        , customizeNodeMarkup: function (event, data) {
            // close_all: all nodes collapsed, no customization needed
            if (event.type === 'close_all') return;

            var container;
            // For before_open, scope to the node being opened instead of scanning entire tree
            if (data && data.node && data.node.id && event.type === 'before_open') {
                container = document.getElementById(data.node.id);
            } else {
                if (event.target.id === 'online')
                    container = document.getElementsByClassName('onlineTree')[0];
                else
                    container = document.getElementsByClassName('offlineTree')[0];
            }

            if (!container) return;

            var aElements = container.getElementsByTagName('a');
            if (!aElements || aElements.length === 0) return;

            var styles = [
                'font-style:normal',
                'color: #077be5;font-weight:bold; font-style:normal',
                null, // determined per element
                'color: black;'
            ];

            for (var i = 0; i < aElements.length; i++) {
                if (aElements[i].childNodes.length !== 2) continue;

                var textElement = aElements[i].childNodes[1];
                var textSplitted = aElements[i].textContent.split('|');

                // Use DocumentFragment to batch all DOM insertions (single reflow)
                var fragment = document.createDocumentFragment();
                for (var j = 0; j < textSplitted.length && j < 4; j++) {
                    if (textSplitted[j]) {
                        var tag = document.createElement("i");
                        tag.appendChild(document.createTextNode(textSplitted[j]));
                        var style = styles[j];
                        if (j === 2) {
                            style = textSplitted[j].indexOf("(") > -1 ? 'color: black;' : 'font-weight:bold; font-style:normal';
                        }
                        tag.setAttribute('style', style);
                        fragment.appendChild(tag);
                    }
                }

                aElements[i].removeChild(textElement);
                aElements[i].appendChild(fragment);
            }
        }


        , onLoadingScript: function () {
            if (this.options.MYREFERENCES.subviews.loadingScript.view)
                this.options.MYREFERENCES.subviews.loadingScript.view.close();


            var codeConfigurationContainer = this.$el.find(".loading-script-container");

            this.options.MYREFERENCES.subviews.loadingScript.view = new Screen.Views.LoadingScript({
                container: codeConfigurationContainer
            });

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

        , onCloseLoadingScript: function () {
            if (this.options.MYREFERENCES.subviews.loadingScript.view)
               this.options.MYREFERENCES.subviews.loadingScript.view.close();
        }

        // Select and Deselect nodes
        , onSelectNodeTreeOnline: function (e, obj) {
            var that = this;
            this.onDeselectNodeAllTreeOffline();
            if (this.options.MYREFERENCES.subviews.equipmentDetails.view)
                this.options.MYREFERENCES.subviews.equipmentDetails.view.close();


            var codeConfigurationContainer = this.$el.find(".equipment-details-container");
            this.options.MYREFERENCES.subviews.equipmentDetails.view = new Screen.Views.EquipmentDetails({
                container: codeConfigurationContainer,
                parent: that,
                node: obj.node.data,
            });

            this.options.MYREFERENCES.subviews.equipmentDetails.view.render();

        }
        , onSelectNodeTreeOffline: function (e, obj) {
            var that = this;
            this.onDeselectNodeTreeOnline();
            if (this.options.MYREFERENCES.subviews.equipmentDetails.view)
                this.options.MYREFERENCES.subviews.equipmentDetails.view.close();
            var codeConfigurationContainer = this.$el.find(".equipment-details-container");
            this.options.MYREFERENCES.subviews.equipmentDetails.view = new Screen.Views.EquipmentDetails({
                container: codeConfigurationContainer,
                parent: that,
                node: obj.node.data,
            });


            this.options.MYREFERENCES.subviews.equipmentDetails.view.render();

        }
        , onDeselectNodeTreeOnline: function (e, obj) {
            if (this.$el.find(".onlineTree")) this.$el.find(".onlineTree").jstree().deselect_all(true);
        }
        , onDeselectNodeAllTreeOffline: function (e, obj) {
            if (this.$el.find(".offlineTree")) this.$el.find(".offlineTree").jstree().deselect_all(true);
        }
        , onDeselectNode: function (e, obj) {
            if (this.options.MYREFERENCES.subviews.equipmentDetails.view)
                this.options.MYREFERENCES.subviews.equipmentDetails.view.close();
        }


        // debounce when fetch the trees
        , treeItemsChanged: 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.screensTree.refresh();
        }, 500)
        , treeItemsOfflineChanged: function (a, b, c) {
            var fromFetch = (
                (c && c.from && c.from == "fetch") ||
                (!c && b && b.from == "fetch")
            ) ? true : false;

            if (fromFetch) {
                this.debounced_refreshLinesTreeOffline();
            }
        }
        , debounced_refreshLinesTreeOffline: _.debounce(function () {
            this.options.screensTreeOffline.refresh();
        }, 500)


        //Common functions
        , 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;
            }
        }
        , close: function () {
            this.options.state = app.view_states.closed;

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

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

            this.$el.hide();
            this.unbind();
            this.stopListening();
        }
        , preRender: function () {
            app.models.subnavbar.set("dateControl", false);
            app.models.subnavbar.set("subnavbar", false);
        }
        , reRender: function () {
        }       

    });

    Screen.Models.LoadingScript = Backbone.Epoxy.Model.extend({
        defaults: {
            treeDataLoading:true,
        },
        initialize: function (opt) {
            var opts = { loaded: false, };
            this.options = _.extend(this.options ? this.options : {}, opts);
            this.options.loaded = true;
        }
    });
    Screen.Views.LoadingScript = Backbone.Epoxy.View.extend({
        template: "caster-equipments-tree"
        , id: "caster-equipments-tree-details"
        , title: "Caster Equipments Tree Details"
        //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.model)
                this.model = new Screen.Models.LoadingScript();

            this.bindEvents();
        },

        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/custom-screens/caster-equipments-tree/";

            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();
                    //appending view to the main container
                    that.append(thatContainer, that.$el);

                    //end:

                }, true, customPath);
            }, customPath, "loading_script");
        }


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

        , 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);
        }

        , 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) { }
        }

        , bindViewScopedEvents: function () {
        }

        , unbindViewScopedEvents: function () {
        }

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

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

        , closeSubviews: function () {
        }

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

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

        , showSubviews: function () {
        }

        , 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 () {
        }

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

    Screen.Collections.Items = Backbone.Collection.extend({
        setDataColl: function (data) {
            var newColl,
                that = this;
            newColl = data;
            that.set(newColl).trigger('fetch', that, data);
        },

    });
    Screen.Collections.Tree = Backbone.Collection.extend({
        model: Screen.Models.Tree,
        setDataColl: function (data) {
            var that = this;
            var tree = _.map(data, that.model.prototype.parse);
            that.set(tree, { from: "fetch" });
        },
    });


    Screen.Models.EquipmentDetails = Backbone.Epoxy.Model.extend({
        defaults: {
            enabled: null,
            title: '',
            PartName : '',
            PartTypeName: '',
            ParentPartName: '',
            InstalledOn : '',
            InstalledBy : '',
            ResetOn: '',
            ResetBy: '',
            hasL2PartId: false,
            isLoading: true, //  isLoading: false,
            hasData: false,

            showStatusOk:       false,
            showStatusEmpty:    false,
            showStatusWarning:  false,
            showStatusAlert:    false,

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

            this.itemsCollHeader = new Screen.Collections.Items();
            this.itemsCollValues = new Screen.Collections.Items();
            this.itemsCollHistory = new Screen.Collections.Items();


            this.metricsDetailsColl = new Screen.Collections.MetricsDetailsColl();
        }             
        , fetchPartDetails: function (params) {
            var that = this,
                qp = new Core.Database.QueryParameters();

            qp.Add('@PartId', 'INT', params.partId);
            Core.Json.CallProcedure(
                app.DatabaseNames.MES + ".EQP.GetPartDetails",
                qp,
                {
                    onSuccess: function (resp) {
                        try {

                            if ((resp) && (resp.Table)) {
                                if (resp.Table) that.itemsCollHeader.setDataColl(resp.Table);
                                if (resp.Table1) that.itemsCollValues.setDataColl(resp.Table1);
                                if (resp.Table1) that.metricsDetailsColl.setDataColl(resp.Table1);
                                if (resp.Table2) that.itemsCollHistory.setDataColl(resp.Table2);
                                that.trigger('fetch', resp);
                            }
                            else {
                                if ((resp) && (resp.Message)) {
                                    console.error(new Error(resp.Message).stack);
                                    app.views.topMessages.showMessage('CALL TO DATABASE FAILED', { stay: 5000, });
                                }
                                else {
                                    app.views.topMessages.showMessage('SERVER RESPONSE NOT VALID', { stay: 5000, });
                                    console.error(new Error('SERVER_RESPONSE_NOT_VALID').stack);
                                }
                            }
                        }
                        catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
                    },
                    onFailure: function (resp) {
                        console.error(resp);
                    },
                    Secured: true,
                    Async: true,
                },
                app.ConnectionStrings.app
            );
            return this;
        },

    });
    Screen.Views.EquipmentDetails = Backbone.Epoxy.View.extend({
        template: "caster-equipments-tree"
        , id: "caster-equipments-tree-details"
        , title: "Caster Equipments Tree Details"
        //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"
        , metricsTableView: null
        , initialize: function () {
            this.options.state = app.view_states.loading;
            this.options.onappend = (_.isFunction(this.options.onappend)) ? this.options.onappend : function () { };

            var that = this;
            if (!this.model)
                this.model = new Screen.Models.EquipmentDetails();
   
            var { node } = this.options;
            if (node && node.StatusCode) {
                this.model.set({
                    showStatusOk:         node.StatusCode === 'O' ? true : false,
                    showStatusEmpty:      node.StatusCode === 'B' ? true : false,
                    showStatusWarning:    node.StatusCode === 'W' ? true : false,
                    showStatusAlert:      node.StatusCode === 'A' ? true : false,
                })
            }
            if (node && node.L2PartId) {
                this.model.fetchPartDetails({
                    partId: node.L2PartId,
                });
            } else if (node && node.L1PartId) {
                var dataArray = [];

                dataArray.push({
                    InstalledBy: '-'
                    , InstalledOn: '-'
                    , ParentPartName: node.L1PartName
                    , PartName: '-'
                    , PartTypeName: '-'
                    , ResetBy: '-'
                    , ResetOn: '-'
                });

                this.model.itemsCollHeader.setDataColl(dataArray);
                this.model.set({
                    title: node.L1PositionName ? node.L1PartTypeName + ' - ' + node.L1PositionName : node.L1PartTypeName,
                    hasL2PartId: false,
                    isLoading: false, 
                    hasData: true,
                });
            } else {
                this.model.set({
                    hasL2PartId: false,
                    isLoading: false, 
                    hasData: false,
                })
            }

            this.bindingSources = {
                metricsTableColl: that.model.metricsDetailsColl,
            };

            this.bindEvents();


        },



        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/custom-screens/caster-equipments-tree/";

            if (this.model.options.loaded) {
                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.metricsTableView = Screen.Views.MetricsTable.extend({
                            template: Handlebars.compile(that.$el.find('#metricsTableViewTemplate').html()),
                        });

                        that.applyBindings();



                       

                        var grid = new Backgrid.Grid({
                            className: 'backgrid table table-hover table-condensed production-table',                           
                            columns: [
                                {
                                    name: 'MetricTypeName',
                                    label: app.translate([that, app], 'Metric'),
                                    cell: Backgrid.StringCell.extend({
                                        className: 'string-cell align-center-cell',
                                    }),
                                    editable: false,
                                },
                                {
                                    name: 'PartialValue',
                                    label: app.translate([that, app], 'Partial'),
                                    cell: Backgrid.StringCell.extend({
                                        className: function () {
                                            var model = this.model.toJSON();
                                            if (model.PartialValueStatus === 'O') return 'number-cell align-center-cell'; //'number-cell align-center-cell metric-status-ok';
                                            if (model.PartialValueStatus === 'A') return 'number-cell align-center-cell metric-status-alert';
                                            if (model.PartialValueStatus === 'W') return 'number-cell align-center-cell metric-status-warning';
                                            else return 'number-cell align-center-cell';
                                        },
                                        decimals: 2,
                                    }),
                                    editable: false,
                                },
                                {
                                    name: 'TotalValue',
                                    label: app.translate([that, app], 'Total'),
                                    cell: Backgrid.StringCell.extend({
                                        className: function () {
                                            var model = this.model.toJSON();
                                            if (model.TotalValueStatus === 'O') return 'number-cell align-center-cell'; //'number-cell align-center-cell metric-status-ok';
                                            if (model.TotalValueStatus === 'A') return 'number-cell align-center-cell metric-status-alert';
                                            if (model.TotalValueStatus === 'W') return 'number-cell align-center-cell metric-status-warning';
                                            else return 'number-cell align-center-cell';
                                        },
                                        decimals: 2,
                                    }),
                                    editable: false,
                                },
                            ],
                            collection: that.model.itemsCollValues,
                           

                        });
                        //container.append(grid.render().el);
                        that.$el.find('.metrics-grid-container').append(grid.render().el);
                        var grid2 = new Backgrid.Grid({
                            className: 'backgrid table table-hover table-condensed production-table',
                            columns: [
                                {
                                    name: 'Timestamp',
                                    label: app.translate([that, app], 'Datetime'),
                                    cell: Backgrid.StringCell.extend({
                                        className: 'string-cell align-center-cell',
                                    }),
                                    editable: false,
                                },
                                {
                                    name: 'Action',
                                    label: app.translate([that, app], 'Action'),
                                    cell: Backgrid.StringCell.extend({
                                        className: 'string-cell align-center-cell',
                                    }),
                                    editable: false,
                                },
                                {
                                    name: 'Parent',
                                    label: app.translate([that, app], 'Parent'),
                                    cell: Backgrid.StringCell.extend({
                                        className: 'string-cell align-center-cell',
                                    }),
                                    editable: false,
                                },
                                {
                                    name: 'Position',
                                    label: app.translate([that, app], 'Tons'),
                                    cell: Backgrid.StringCell.extend({
                                        className: 'string-cell align-center-cell',
                                    }),
                                    editable: false,
                                },
                                {
                                    name: 'User',
                                    label: app.translate([that, app], 'User'),
                                    cell: Backgrid.StringCell.extend({
                                        className: 'string-cell align-center-cell',
                                    }),
                                    editable: false,
                                },
                                {
                                    name: 'Branch',
                                    label: app.translate([that, app], 'Branch'),
                                    cell: Backgrid.StringCell.extend({
                                        className: 'string-cell align-center-cell',
                                    }),
                                    editable: false,
                                },
                            ],
                            collection: that.model.itemsCollHistory,


                        });
                        //container.append(grid.render().el);
                        that.$el.find('.metrics-history-grid-container').append(grid2.render().el);
                        var grid3 = new Backgrid.Grid({
                            className: 'backgrid table table-hover table-condensed production-table',
                            columns: [
                                {
                                    name: 'ParentPartName',
                                    label: app.translate([that, app], 'Parent'),
                                    cell: Backgrid.StringCell.extend({
                                        className: 'string-cell align-center-cell',
                                    }),
                                    editable: false,
                                },
                                {
                                    name: 'InstalledOn',
                                    label: app.translate([that, app], 'Installed On'),
                                    cell: Backgrid.StringCell.extend({
                                        className: 'string-cell align-center-cell',
                                    }),
                                    editable: false,
                                },
                                {
                                    name: 'InstalledBy',
                                    label: app.translate([that, app], 'Installed By'),
                                    cell: Backgrid.StringCell.extend({
                                        className: 'string-cell align-center-cell',
                                    }),
                                    editable: false,
                                },
                                {
                                    name: 'ResetOn',
                                    label: app.translate([that, app], 'Reset On'),
                                    cell: Backgrid.StringCell.extend({
                                        className: 'string-cell align-center-cell',
                                    }),
                                    editable: false,
                                },
                                {
                                    name: 'ResetBy',
                                    label: app.translate([that, app], 'Reset By'),
                                    cell: Backgrid.StringCell.extend({
                                        className: 'string-cell align-center-cell',
                                    }),
                                    editable: false,
                                },
                              
                            ],
                            collection: that.model.itemsCollHeader,


                        });
                        //container.append(grid.render().el);
                        that.$el.find('.main-info-grid-container').append(grid3.render().el);

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

                        //end:

                    }, true, customPath);
                }, customPath, "equipment_details");
            } else {
                setTimeout(function () {
                    if (!that.model.options.loaded) {
                        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);
            }
        }
        , metricsDetailsColl_fetched: function () {
            try {
                var that = this;
                if (that.model.metricsDetailsColl.length > 0)
                    this.spanMetricsTableRows();

            }
            catch (e) { console.error((e.stack) ? e.stack : new Error(e).stack); }
        }
        
        ,spanMetricsTableRows: function () {
            var that = this,
                coll = that.model.metricsDetailsColl.toJSON(),
                count = 1,
                prev = null,
                curr = null;


            var element = {},
                cart = [],
                rowDelete = null,
                IAcceptArrayrowSpan = null;


            var classes = [
                'spanrow1',
                'spanrow2',
                'spanrow3',
                'spanrow4',
            ]


            _.each(coll, function (obj, i) {
                element = {};
                curr = obj.metricType;

                if (curr != prev) {
                    if (count > 1) {
                        element.metricType = prev;
                        element.rowSpan = count;
                        element.startPos = i - count;
                        cart.push(element);
                    };
                    count = 1;
                } else {
                    count += 1;
                }

                prev = curr;
                if (coll.length - 1 == i) {

                    if (count > 1) {
                        element.metricType = prev;
                        element.rowSpan = count;
                        element.startPos = i + 1 - count;
                        cart.push(element);
                    }
                }
            });

            _.each(cart, function (obj) {
                _.each(classes, function (obj2) {
                    IAcceptArrayrowSpan = document.getElementsByClassName(obj2)[obj.startPos];
                    IAcceptArrayrowSpan.rowSpan = obj.rowSpan;

                })
            });


            _.each(cart, function (obj) {
                _.each(classes, function (obj2) {
                    for (var i = obj.startPos + 1; i < obj.startPos + obj.rowSpan; i++) {
                        rowDelete = document.getElementsByClassName(obj2)[i];
                        rowDelete.style.display = 'none';
                    }

                })
            });

        }
       

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

        , 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, 'fetch', this.details_ready);

            this.listenTo(this.model.metricsDetailsColl, 'fetch', this.metricsDetailsColl_fetched);
        }
        , details_ready: function (resp) {
            var { Table } = resp;
            this.model.set({
                hasData: true,
                isLoading: false,
                hasL2PartId: true,
                title: Table[0].PartTypeName + ' - ' + Table[0].PartName 
            });

        }


        , 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) { }
        }

        , bindViewScopedEvents: function () {
        }

        , unbindViewScopedEvents: function () {
        }

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

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

        , closeSubviews: function () {
        }

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

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

        , showSubviews: function () {
        }

        , 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 () {
        }

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

    Screen.Collections.MetricsDetailsColl = Backbone.Collection.extend({
        setDataColl: function (details) {
            var newColl,
                that = this;
            newColl = [];
            _.each(details, function (det) {
                // Max Limit
                newColl.push({                  
                    metricType: det.MetricTypeName === 'Heats' ? 'H' : (det.MetricTypeName === 'Tons' ? 'T' : (det.MetricTypeName === 'Contact' ? 'C' : 'L')),
                    metric: det.MetricTypeName,


                    campaignStatusAlert: det.CampaignValueStatus === 'A' ? true : false,
                    campaignStatusWarning: det.CampaignValueStatus === 'W' ? true : false,
                    partialStatusAlert: det.PartialValueStatus === 'A' ? true : false,
                    partialStatusWarning: det.PartialValueStatus === 'W' ? true : false,
                    totalStatusAlert: det.TotalValueStatus === 'A' ? true : false,
                    totalStatusWarning: det.TotalValueStatus === 'W' ? true : false,

                    campaignCurrent: det.CampaignValue ? det.CampaignValue : '',
                    partialCurrent: det.PartialValue ? det.PartialValue : '',
                    totalCurrent: det.TotalValue ? det.TotalValue : '',


                    campaignLimit: det.CampaignAlertLimit ? det.CampaignAlertLimit : '',
                    totalLimit: det.TotalAlertLimit ? det.TotalAlertLimit : '',
                    partialLimit: det.PartialAlertLimit ? det.PartialAlertLimit : '',

                    limitMax: true,
                    limitMin: false,

                });


                // Min Limit
                newColl.push({

                    metricType: det.MetricTypeName === 'Heats' ? 'H' : (det.MetricTypeName === 'Tons' ? 'T' : (det.MetricTypeName === 'Contact' ? 'C' : 'L')),
                    metric: det.MetricTypeName,

                    campaignStatusAlert: det.CampaignValueStatus === 'A' ? true : false,
                    campaignStatusWarning: det.CampaignValueStatus === 'W' ? true : false,
                    partialStatusAlert: det.PartialValueStatus === 'A' ? true : false,
                    partialStatusWarning: det.PartialValueStatus === 'W' ? true : false,
                    totalStatusAlert: det.TotalValueStatus === 'A' ? true : false,
                    totalStatusWarning: det.TotalValueStatus === 'W' ? true : false,


                    campaignCurrent: det.CampaignValue ? det.CampaignValue : '',
                    partialCurrent: det.PartialValue ? det.PartialValue : '',
                    totalCurrent:   det.TotalValue   ? det.TotalValue : '',


                    campaignLimit: det.CampaignWarningLimit ? det.CampaignWarningLimit : '',
                    totalLimit:   det.TotalWarningLimit   ? det.TotalWarningLimit   : '',
                    partialLimit: det.PartialWarningLimit ? det.PartialWarningLimit : '',  

                    limitMax: false,
                    limitMin: true,

                });
            });

            that.set(newColl).trigger('fetch', that);
        },
    });

    Screen.Views.MetricsTable = Backbone.Epoxy.View.extend({
        tagName: 'tr',
        template: null,
        initialize: function () {
            this.render();
        },
        render: function () {
            this.$el.html(this.template(this.model.toJSON()));
            return this;
        },
    });

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

});
