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

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

  "js/bootstrap-select/bootstrap-select",
  "js/bootstrap-select/FormSelectBootstrap",

  //"backbone.paginator", 
  "backgrid/infinator",
  "bootstrap/colorpicker", 

],

function (app, T, Modal, Handlebars) {

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

    TagsConfiguration.Models.Main = Backbone.Model.extend({
        defaults: {
            procedure: '',
            tags: null,
            searchedTags: null, 
        }
    });    

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

    TagsConfiguration.enums = {};
    TagsConfiguration.enums.sources = { UI: "ui", FETCH: "fetch", UNKNOWN: "unknown", INTERNAL: "internal" }; 

    TagsConfiguration.Models.Tag = Backbone.Model.extend({
        defaults: {
            id: null,
            agentId: null, 
            rownum: null, 
            agentType: null,
            internal: null,
            agentName: null,
            name: null,
            alias: null,
            lineColor: null,
            scanRate: null,
            dataType: null,
            stringLength: null,
            unit: null,
            minUnit: null,
            maxUnit: null,
            enabled: null,
            lastValue: null,

            grid_status: null,
            grid_message: null,
            grid_can_commit: true,
            lock_set: null, 

            changedAttrs: [],
        },
    });

    TagsConfiguration.Collections.ChangedTags = Backbone.Collection.extend({
        model: TagsConfiguration.Models.Tag,
        initialize: function () {
            this.listenTo(this, "change", this._tagChanged);
            this.listenTo(this, "add", this._tagAdded);
        },
        _tagChanged: function (model) {
            var changed = [];
            for (var i in model.changed) changed.push(i);
            model.set("changedAttrs", _.union(model.get("changedAttrs"), changed), { silent: true });
        },
        _tagAdded: function (model) {
            var changed = [];
            for (var i in model.changed) changed.push(i);
            model.set("changedAttrs", _.union(model.get("changedAttrs"), changed), { silent: true });
        }, 
    }); 

    //TagsConfiguration.Collections.Tags = Backbone.PageableCollection.extend({
    //    model: TagsConfiguration.Models.Tag,
    //    url: function () { return "-"; },
    //    parseLinks: function (resp) {
    //        return { next: "-" + (this.state.currentPage + 1) };
    //    }, 
    //    BBColProto: Backbone.Collection.extend({
    //        fetch: function (options) {
    //            options = options ? _.clone(options) : {};
    //            if (options.parse === void 0) options.parse = true;
    //            var success = options.success;
    //            var collection = this;

    //            var that = this;
    //            var QP = new Core.Database.QueryParameters();
    //            QP.Add('@AgentID', 'INT', options.agentId);
    //            QP.Add('@AdquiringID', 'INT', options.adquiringId);
    //            QP.Add('@FromRow', 'INT', (options.data.page - 1) * options.data.per_page);
    //            QP.Add('@RowsToFetch', 'INT', options.data.per_page); 

    //            Core.Json.CallProcedure(app.DatabaseNames.IH + ".WEB.GetTagsCatalog", QP, {
    //                onSuccess: function (data) {
    //                    if (data && data.Table) {
    //                        data = data.Table;

    //                        var resp = []; 
    //                        for (var i = 0, len = data.length; i < len; i++) {
    //                            var d = data[i];
    //                            var obj = _.clone(TagsConfiguration.Models.Tag.prototype.defaults);

    //                            _.extend(obj, {
    //                                id: d.TagID,
    //                                rownum: d.RowNum, 
    //                                agentType: d.AgentType,
    //                                internal: d.Internal,
    //                                agentName: d.AgentName,
    //                                name: d.Name,
    //                                alias: d.Alias,
    //                                lineColor: d.LineColor,
    //                                scanRate: d.ScanRate,
    //                                dataType: d.DataType,
    //                                stringLength: d.StringLength,
    //                                unit: d.Unit,
    //                                minUnit: d.MinUnit,
    //                                maxUnit: d.MaxUnit,
    //                                enabled: d.Enabled,
    //                                lastValue: d.LastValue,
    //                            });

    //                            resp.push(obj);
    //                        }

    //                        delete options.agentId;
    //                        delete options.adquiringId;

    //                        that.sync("read", that, {
    //                            success: function () {
    //                                var method = options.reset ? 'reset' : 'set';
    //                                //collection[method](resp, options);
    //                                collection.add(resp, _.extend(options, { silent: false })); 
    //                                if (success) success(collection, resp, options);
    //                                collection.trigger('sync', collection, resp, options);
    //                            }
    //                        });
    //                    }
    //                }
    //            }, app.ConnectionStrings.app);
    //        },
    //        sync: function (method, model, options) {
    //            if (options.success) options.success(null, null, null); 
    //        }, 
    //    }).prototype,
    //    state: {
    //        pageSize: 50, 
    //    },
    //    mode: "infinite",
    //}); 

    TagsConfiguration.Collections.Tags = Backbone.Collection.extend({
        model: TagsConfiguration.Models.Tag,
        initialize: function (opt) {
            this.options = this.options || {};
            _.extend(this.options, {
                isFetching: false,
                currentPage: 1,
                pageSize: 50,
                fixedParameters: [],

                transaction_timestamp: null, 
            }, opt);

            _.bindAll(this); 
        }, 
        resetPagination: function(force){
            if (!this.options.isFetching || force == true){
                this.options.currentPage = 1; 
            }else{
                _.delay(this.resetPagination, 100); 
            }
        },
        getNextPage: function (options) {
            if (!this.options.isFetching) {
                this.options.currentPage++;
                options = (_.isObject(options)) ? options : {}; 
                this.fetch(_.extend(options, {
                    preprocessResponse: (this.options.preprocessResponseGetNextPage) ? this.options.preprocessResponseGetNextPage : null
                }));
            }
        },
        setFixedParameters: function (params) {
            var fixedParams = this.options.fixedParameters; 

            for (var i = 0, len = params.length; i < len; i++) {
                fixedParams = _.without(fixedParams, _.findWhere(fixedParams, { Name: params[i].Name }));
                fixedParams.push(params[i]); 
            }

            this.options.fixedParameters = fixedParams; 
        }, 
        fetch: function (options) {
            var ttimestamp = this.options.transaction_timestamp = new Date().getTime(); 
            this.options.isFetching = true;

            options = options ? _.clone(options) : {};
            if (options.parse === void 0) options.parse = true;
            var success = options.success;
            var collection = this;

            if (options.resetPagination) this.resetPagination(true);
            //options["showOnlyEnabledTags"] = (_.isBoolean(options["showOnlyEnabledTags"])) ? options["showOnlyEnabledTags"] : false; 

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

            if (_.has(options, "agentId")) QP.Add('@AgentID', 'INT', options.agentId);
            if (_.has(options, "adquiringId")) QP.Add('@AdquiringID', 'INT', options.adquiringId);
            if (_.has(options, "showOnlyEnabledTags")) QP.Add('@OnlyEnabledTags', 'BIT', options.showOnlyEnabledTags);

            if (!options.refresh) {
                QP.Add('@FromRow', 'INT', (this.options.currentPage - 1) * this.options.pageSize);
                QP.Add('@RowsToFetch', 'INT', this.options.pageSize);
            } else {
                QP.Add('@FromRow', 'INT', 0);
                QP.Add('@ToRow', 'INT', this.options.currentPage * this.options.pageSize);
            }

            if (_.isArray(options.qps) || this.options.fixedParameters.length > 0) {
                var params = (_.isArray(options.qps)) ? options.qps : [];
                params = params.concat(this.options.fixedParameters); 

                _.each(params, function (qp) {
                    if (_.has(qp, 'Name') && _.has(qp, 'Type') && _.has(qp, 'Value'))
                        QP.Add(qp.Name, qp.Type, qp.Value); 
                }); 
            }

            Core.Json.CallProcedure(app.DatabaseNames.IH + ".WEB.GetTagsCatalog", QP, {
                onSuccess: function (data) {
                    //checking transaction timestamp
                    if (ttimestamp != that.options.transaction_timestamp)
                        return;

                    if (data && data.Table) {
                        data = data.Table;

                        var resp = []; 
                        for (var i = 0, len = data.length; i < len; i++) {
                            var d = data[i];
                            var obj = _.clone(TagsConfiguration.Models.Tag.prototype.defaults);

                            _.extend(obj, {
                                id: d.TagID,
                                rownum: d.RowNum, 
                                agentId: d.AgentId, 
                                agentType: d.AgentType,
                                internal: d.Internal,
                                agentName: d.AgentName,
                                name: d.Name,
                                alias: (d.Alias == null) ? "" : d.Alias,
                                lineColor: (d.LineColor == null) ? "" : d.LineColor,
                                scanRate: (d.ScanRate == null) ? null : d.ScanRate,
                                dataType: (d.DataType == null) ? "" : d.DataType,
                                stringLength: (d.StringLength == null) ? "" : d.StringLength,
                                unit: (d.Unit == null) ? "" : d.Unit,
                                minUnit: (d.MinUnit == null) ? null : d.MinUnit,
                                maxUnit: (d.MaxUnit == null) ? null : d.MaxUnit,
                                enabled: d.Enabled,
                                lastValue: d.LastValue,
                            });

                            resp.push(obj);
                        }

                        delete options.agentId;
                        delete options.adquiringId;

                        //default is add, then if reset or set is found then setting to the correct method.
                        var method = 'add';
                        method = (options.reset) ? 'reset' : method;
                        method = (options.set) ? 'set' : method;

                        //checking transaction timestamp
                        if (ttimestamp != that.options.transaction_timestamp)
                            return;

                        if (!options.beforeAlteringCollection || options.beforeAlteringCollection() == true) {
                            resp = (options.preprocessResponse) ? options.preprocessResponse(resp) : resp;

                            collection[method](resp, _.extend(options, { silent: false, source: TagsConfiguration.enums.sources.FETCH }));

                            //decreasing page since we couldn't get any data on this page.
                            if (resp.length == 0 && method == "add")
                                that.options.currentPage--;
                        }
                        
                        that.options.isFetching = false;

                        if (success) success(collection, resp, options); 
                    }
                }
            }, app.ConnectionStrings.app);

        }
    }); 

    TagsConfiguration.Collections.SearchedTags = TagsConfiguration.Collections.Tags.extend({
        search: function (searchQuery, options) {
            options = options ? _.clone(options) : {};
            this.resetPagination();
            
            this.options.fixedParameters = _.without(this.options.fixedParameters, _.findWhere(this.options.fixedParameters, { Name: "@SearchQuery" })); 

            var searchQueryQP = { Name: "@SearchQuery", Type: "VARCHAR", Value: searchQuery };
            this.options.fixedParameters.push(searchQueryQP);

            this.fetch(_.extend(options, {
                reset: true, 
            }));
        }, 
    }); 

    TagsConfiguration.Views.Main = Backbone.View.extend({
        template: "tags-configuration"
        , id: "tags-configuration"
        , title: "Configuración de Tags"
        //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
        , askBeforeCloseOpt: {
            title: null,
            message: null,
        }
        , beforeClose: function () {
            if (!this.askBeforeCloseOpt.title || !this.askBeforeCloseOpt.message) {
                this.askBeforeCloseOpt.title = this.options.i18n[this.template].translate("unsaved_changes_modal_title").fetch();
                this.askBeforeCloseOpt.message = this.options.i18n[this.template].translate("unsaved_changes_modal_message").fetch();
            }

            var changedTags = this.model.get("changedTags");
            if (changedTags.length > 0) return false;
            else return true; 
        }
        , initialize: function () {
            this.options.state = app.view_states.loading;
            this.options.onappend = (_.isFunction(this.options.onappend)) ? this.options.onappend : function () { };

            _.bindAll(this);

            if (this.options.viewParams) {
            }

            var model = new TagsConfiguration.Models.Main({
                procedure: "dbo.procedureName",
                tags: new TagsConfiguration.Collections.Tags({ preprocessResponseGetNextPage: this.preprocessResponse_keepChanges }),
                searchedTags: new TagsConfiguration.Collections.SearchedTags(),
                changedTags: new TagsConfiguration.Collections.ChangedTags(), 
            });

            this.model = model;

            this.options.MYREFERENCES = {
                autoRefresh: {
                    enabled: false
                    , toid: null
                }
                , subviews: {

                }
                , grid_instance: null
                , grids: {
                    "TAGS": { instance: null, el: null },
                    "SEARCHEDTAGS": { instance: null, el: null }, 
                }
                , isSearching: false
                , searchMode: false
                , isRefreshing: false
                , searchTerm: null

                , requireLockColumns: ["enabled", "scanRate"]
            };

            this.options.MYREFERENCES.subviews.subnavbarControlsLeft = new TagsConfiguration.Views.SubnavBarControlsLeft({
                parent: this
                , container: app.views.subnavbar.getSectionContainer(1, 6)
            });
            this.options.MYREFERENCES.subviews.subnavbarControlsLeft.render();

            this.options.MYREFERENCES.subviews.subnavbarControlsRight = new TagsConfiguration.Views.SubnavBarButtons({
                container: app.views.subnavbar.getSectionContainer(2, 6)
                , parent: this
            });

            this.bindEvents();  
        },

        events: {
        }, 

        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/IHConfiguration/tags-configuration-v2/";

            T.render.call(this, this.template, function (tmp) {

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

                    //start: before the view is visible, but the template was already loaded (not instanced nor appended)

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

                    var ctx = {
                        editable: app.models.securityManager.getModuleActionValue("ihconfiguration_tags_configuration", "write"),
                    };
                    //end:

                    //if (ctx.editable == false) app.views.topMessages.showMessage("Solo lectura.", { stay: 5000 }); 

                    //loading the view and appeding it to the views's $el.
                    that.$el.html(tmp(ctx));
                    
                    //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")

                    var stringCell_highlightChanges = Backgrid.StringCell.extend({
                        className: "string-cell align-center-cell",
                        initialize: function () {
                            Backgrid.StringCell.prototype.initialize.apply(this, arguments);
                        }, 
                        render: function () {
                            Backgrid.StringCell.prototype.render.apply(this, arguments);
                            this.highlightIfChanged(); 
                            return this;
                        },
                        highlightIfChanged: function () {
                            if (_.indexOf(this.model.get("changedAttrs"), this.column.get("name")) != -1
                                || (this.model.changed && this.model.changed[this.column.get("name")] == true)) {
                                this.$el.css("background-color", "#fefed0");
                            } else {
                                this.$el.css("background-color", "");
                            }
                        },
                    });

                    var numberCell_highlightChanges = Backgrid.NumberCell.extend({
                        className: "number-cell align-center-cell",
                        orderSeparator: '',
                        initialize: function () {
                            Backgrid.NumberCell.prototype.initialize.apply(this, arguments);
                        },
                        render: function () {
                            Backgrid.NumberCell.prototype.render.apply(this, arguments);
                            this.highlightIfChanged();
                            return this;
                        },
                        highlightIfChanged: function () {
                            if (_.indexOf(this.model.get("changedAttrs"), this.column.get("name")) != -1
                                || (this.model.changed && this.model.changed[this.column.get("name")] == true)) {
                                this.$el.css("background-color", "#fefed0");
                            } else {
                                this.$el.css("background-color", "");
                            }
                        },
                    });

                    var integerCell_highlightChanges = Backgrid.IntegerCell.extend({
                        className: "number-cell align-center-cell",
                        orderSeparator: '',
                        initialize: function () {
                            Backgrid.IntegerCell.prototype.initialize.apply(this, arguments);
                        },
                        render: function () {
                            Backgrid.IntegerCell.prototype.render.apply(this, arguments);
                            this.highlightIfChanged();
                            return this;
                        },
                        highlightIfChanged: function () {
                            if (_.indexOf(this.model.get("changedAttrs"), this.column.get("name")) != -1
                                || (this.model.changed && this.model.changed[this.column.get("name")] == true)) {
                                this.$el.css("background-color", "#fefed0");
                            } else {
                                this.$el.css("background-color", "");
                            }
                        },
                    });

                    var editable_fn = function (model) {
                        var column = this; 
                        var can_be_editable = (_.isFunction(column.get("can_be_editable"))) ? column.get("can_be_editable").call(this, column, model) :
                            (_.isBoolean(column.get("can_be_editable"))) ? column.get("can_be_editable") : true;
                        if (can_be_editable) {
                            if (model.get("grid_can_commit")) return true;
                            else return false;
                        } else return false; 
                    }; 

                    var can_be_editable_only_real_fn = function (column, model) {
                        var dataType = model.get("dataType"); 
                        if (_.isString(dataType) && dataType.toUpperCase() == "REAL" && ctx.editable) {
                            return true;
                        } else return false; 
                    }; 

                    var columns = [
                    {
                        name: "agentName",
                        label: "Agent",
                        editable: false,
                        sortable: false, 
                        cell: Backgrid.StringCell.extend({
                            orderSeparator: '',
                            className: "string-cell align-center-cell agentName",
                            formatter: _.extend({}, Backgrid.CellFormatter.prototype, {
                                fromRaw: function (rawValue, model) {
                                    var formatted = rawValue; 
                                    if (formatted.length > 8) {
                                        formatted = "..." + formatted.substring(formatted.length - 8);
                                    }
                                    return formatted;
                                }
                            }),
                        })
                    },
                    {
                        name: "name",
                        label: "Name",
                        editable: false,
                        sortable: false,
                        cell: Backgrid.StringCell.extend({
                            className: "string-cell align-center-cell name", 
                        })
                    }
                    //, {
                    //    name: "rownum",
                    //    label: "rowNum",
                    //    editable: false,
                    //    cell: Backgrid.StringCell.extend({
                    //        className: "string-cell align-center-cell"
                    //    })
                    //}
                    , {
                        name: "alias",
                        editable: editable_fn,
                        can_be_editable: ctx.editable,
                        sortable: false,
                        label: "Alias",
                        cell: stringCell_highlightChanges.extend({
                            className: stringCell_highlightChanges.prototype.className + " alias", 
                        }),
                    }
                    , {
                        name: "lineColor",
                        label: "Color",
                        editable: false,
                        sortable: false,
                        cell: Backgrid.Cell.extend({
                            template: _.template('<div class="input-group color-picker-cell text-center"><input style="display:none" type="text" value="" class="form-control" /><span class="input-group-addon span-color-picker-cell"><i></i></span></div>'),
                            initialize: function () {
                                Backgrid.Cell.prototype.initialize.apply(this, arguments);
                            },
                            events: {
                                "hidePicker .color-picker-cell": "colorPickerHidden",
                            },
                            colorPickerHidden: function (ev) {
                                if (ctx.editable && this.model.get("grid_can_commit"))
                                    this.model.set("lineColor", ev.color.toHex().replace("#", "")); 
                            }, 
                            render: function () {
                                this.$el.html(this.template());
                                this.$el.find(".color-picker-cell").colorpicker();

                                if (!ctx.editable || !this.model.get("grid_can_commit")) this.$el.find(".color-picker-cell").colorpicker('disable');

                                var lineColor = this.model.get("lineColor"); 
                                var color = (_.isString(lineColor) && lineColor.length > 0) ? ("#" + lineColor.trim().replace("#", "")) : '#ffffff';

                                this.$el.find(".color-picker-cell").colorpicker('setValue', color); 

                                this.highlightIfChanged(); 

                                this.delegateEvents();
                                return this;
                            },
                            className: "align-center-cell lineColor",
                            highlightIfChanged: function () {
                                if (_.indexOf(this.model.get("changedAttrs"), this.column.get("name")) != -1
                                    || (this.model.changed && this.model.changed[this.column.get("name")] == true)) {
                                    this.$el.css("background-color", "#fefed0");
                                } else {
                                    this.$el.css("background-color", "");
                                }
                            },
                        }),
                    }
                    , {
                        name: "scanRate",
                        editable: editable_fn,
                        can_be_editable: ctx.editable,
                        sortable: false,
                        label: "Scan Rate [ms]",
                        cell: integerCell_highlightChanges.extend({
                            className: integerCell_highlightChanges.prototype.className + " scanRate",
                        })
                    }
                    , {
                        name: "dataType",
                        editable: false,
                        sortable: false,
                        label: "Type",
                        cell: Backgrid.StringCell.extend({
                            className: "string-cell align-center-cell dataType"
                        })
                    }
                    //, {
                    //    name: "stringLength",
                    //    label: "String Length",
                    //    editable: false,
                    //    sortable: false,
                    //    cell: Backgrid.StringCell.extend({
                    //        orderSeparator: '',
                    //        className: "string-cell align-center-cell",
                    //    })
                    //}
                    , {
                        name: "unit",
                        label: "Unit",
                        editable: editable_fn, 
                        can_be_editable: can_be_editable_only_real_fn, 
                        sortable: false,
                        cell: stringCell_highlightChanges.extend({
                            className: stringCell_highlightChanges.prototype.className + " unit"
                        }), 
                    }
                    , {
                        name: "minUnit",
                        label: "Min Unit",
                        editable: editable_fn,
                        can_be_editable: can_be_editable_only_real_fn,
                        sortable: false,
                        cell: numberCell_highlightChanges.extend({
                            render: function(){
                                numberCell_highlightChanges.prototype.render.apply(this, arguments);
                                var val = this.model.get(this.options.column.get("name"));
                                var valIsNullOrEmpty = (val == null || $.trim(val) == ''); 

                                var enabled = this.model.get("enabled"); 
                                
                                var column = this.options.column;
                                var model = this.model; 
                                var can_be_editable = (_.isFunction(column.get("can_be_editable"))) ? column.get("can_be_editable").call(this, column, model) :
                                    (_.isBoolean(column.get("can_be_editable"))) ? column.get("can_be_editable") : true;

                                if (valIsNullOrEmpty && enabled && can_be_editable) {
                                    this.$el.text("-Inf");
                                    this.$el.prop("title", "- Infinite");
                                } else {
                                    this.$el.prop("title", "");
                                }

                                return this; 
                            },
                            className: numberCell_highlightChanges.prototype.className + " minUnit",
                        })
                    }
                    , {
                        name: "maxUnit",
                        label: "Max Unit",
                        editable: editable_fn,
                        can_be_editable: can_be_editable_only_real_fn,
                        sortable: false,
                        cell: numberCell_highlightChanges.extend({
                            render: function () {
                                numberCell_highlightChanges.prototype.render.apply(this, arguments);
                                var val = this.model.get(this.options.column.get("name"));
                                var valIsNullOrEmpty = (val == null || $.trim(val) == '');

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

                                var column = this.options.column;
                                var model = this.model;
                                var can_be_editable = (_.isFunction(column.get("can_be_editable"))) ? column.get("can_be_editable").call(this, column, model) :
                                    (_.isBoolean(column.get("can_be_editable"))) ? column.get("can_be_editable") : true;

                                if (valIsNullOrEmpty && enabled && can_be_editable) {
                                    this.$el.text("+Inf");
                                    this.$el.prop("title", "+ Infinite");
                                } else {
                                    this.$el.prop("title", "");
                                }

                                return this;
                            },
                            className: numberCell_highlightChanges.prototype.className + " maxUnit",
                        })
                    }
                    , {
                        name: "enabled",
                        label: "Enabled",
                        editable: false,
                        sortable: false,
                        cell: Backgrid.Cell.extend({
                            template: _.template("<input class='enable-tag-checkbox' tabindex='-1' type='checkbox' />"),
                            initialize: function () {
                                Backgrid.Cell.prototype.initialize.apply(this, arguments);
                            },
                            events: {
                                "change .enable-tag-checkbox": "chkboxChanged",
                            },
                            chkboxChanged: function (e) {
                                if (ctx.editable && this.model.get("grid_can_commit"))
                                    this.model.set("enabled", $(e.target).is(":checked"));
                            }, 
                            render: function () {
                                this.$el.html(this.template());
                                if (!ctx.editable || !this.model.get("grid_can_commit")) this.$el.find(".enable-tag-checkbox").prop("disabled", true);

                                if (this.model.get("enabled")) this.$el.find(".enable-tag-checkbox").attr("checked", "checked");
                                this.highlightIfChanged(); 
                                this.delegateEvents();
                                return this;
                            },
                            className: "align-center-cell enabled",
                            highlightIfChanged: function () {
                                if (_.indexOf(this.model.get("changedAttrs"), this.column.get("name")) != -1
                                    || (this.model.changed && this.model.changed[this.column.get("name")] == true)) {
                                    this.$el.css("background-color", "#fefed0");
                                } else {
                                    this.$el.css("background-color", "");
                                }
                            },
                        }), 
                    }
                    , {
                        name: "lastValue",
                        label: "Last Value",
                        editable: false,
                        sortable: false,
                        cell: Backgrid.StringCell.extend({
                            className: "string-cell align-center-cell status-cell lastValue",
                            initialize: function () {
                                Backgrid.StringCell.prototype.initialize.apply(this, arguments);
                            }, 
                            render: function () {
                                var template = null;
                                var popover_message = null; 
                                var row_error_template = _.template('<div class="warning-icon-popover popover-on-icon" style="height:31px;cursor:pointer;"><span class="fa-stack fa-lg"><i style="color: #ff0000;" class="fa fa-circle-o fa-stack-2x"></i><i style="color: #ff0000;" class="fa fa-exclamation fa-stack-1x"></i></span></div>');
                                var row_locked_loading_template = _.template('<div class="popover-on-icon" style="height:31px;cursor:default;"><img style="width:30px;height:30px;" src="' + app.foldersRoot + '/assets/img/spinner22.gif" /></div>');
                                var row_locked_agent_disconnected = _.template('<div class="not-checked-icon-popover popover-on-icon" style="height:31px;cursor:pointer;"><i style="color: #333;font-size:30px;" class="fa fa-circle-o"></i></div>');

                                var popover_message_key = null; 
                                if (!this.model.get("grid_can_commit")) {
                                    template = row_locked_loading_template;
                                    var locks = app.models.locksManager.getCategoryLocks(
                                        ["AGENTDISCONNECTED", "TAGSCONFIGCHANGE", "SETPLCADDRESS", "DBSTARTMON", "DBSTOPMON", "DBFIXCONFLICTS", "ENABLE", "DISABLE", "UNREGISTER"],
                                        this.model.get("agentId"), true
                                    );

                                    var lock = (locks.length > 0) ? locks.at(0) : null;
                                    if (lock != null) {
                                        var lockName = lock.get("name");
                                        switch (lockName) {
                                            case "AGENTDISCONNECTED":
                                                template = row_locked_agent_disconnected;
                                                break;
                                            default:
                                                template = row_locked_loading_template;
                                                break;
                                        }
                                        popover_message_key = lockName;
                                    }
                                } else if (this.model.get("grid_status") == "error") {
                                    template = row_error_template;
                                    popover_message_key = this.model.get("grid_message");
                                }

                                this.template = (template != null) ? template : this.template; 

                                if (!template) {
                                    Backgrid.StringCell.prototype.render.apply(this, arguments);
                                } else {
                                    this.$el.html(this.template()); 
                                }

                                if (popover_message_key) popover_message = that.options.i18n[that.template].translate("popover_row_status_icon_" + popover_message_key).fetch()
                                if (popover_message != null) {
                                    this.$el.find(".popover-on-icon").popover({
                                        trigger: "hover",
                                        html: true,
                                        content: popover_message,
                                        placement: "left",
                                    });
                                }

                                this.highlightIfChanged(); 
                                return this;
                            },
                            highlightIfChanged: function () {
                                if (_.indexOf(this.model.get("changedAttrs"), this.column.get("name")) != -1
                                    || (this.model.changed && this.model.changed[this.column.get("name")] == true)) {
                                    this.$el.css("background-color", "#fefed0");
                                } else {
                                    this.$el.css("background-color", "");
                                }
                            },
                        })
                    }
                    ];

                    var CustomRow = Backgrid.Row.extend({
                        initialize: function () {
                            Backgrid.Row.prototype.initialize.apply(this, arguments);

                            this.listenTo(this.model, "change:lock_set", this.canCommitChanged); 
                        }, 
                        render: function () {
                            CustomRow.__super__.render.apply(this, arguments);

                            var status = this.model.get("grid_status");

                            if (status == "error") {
                                this.$el.addClass("error");
                                this.$el.prop("title", this.model.get("grid_message")); 
                            }else {
                                this.$el.removeClass("error");
                                this.$el.prop("title", ""); 
                            }

                            var grid_can_commit = this.model.get("grid_can_commit");
                            if (!grid_can_commit) {
                                this.$el.addClass("lock");
                                this.$el.prop("title", "Row temporaly locked.");
                            } else {
                                this.$el.removeClass("lock");
                                this.$el.prop("title", "");
                            }

                            return this;
                        },
                        canCommitChanged: function () {
                            this.render(); 
                        }, 
                    });

                    // Initialize a new Grid instance
                    var grid;
                    that.options.MYREFERENCES.grids["TAGS"].instance = grid = new Backgrid.Grid({
                        row: CustomRow,
                        header: Backgrid.Header.extend({
                            render: function () {
                                Backgrid.Header.prototype.render.apply(this, arguments);
                                //this.$el.affix({ offset: 10 });
                                return this; 
                            },
                            //className: "affix-theader", 
                        }),
                        className: "backgrid table table-hover tags-configuration-backgrid-table",
                        columns: columns,
                        collection: that.model.get("tags"),
                        footer: Backgrid.Extension.Infinator.extend({
                            scrollToTop: false
                        }), 
                    });

                    that.options.MYREFERENCES.grids["SEARCHEDTAGS"].instance = new Backgrid.Grid({
                        row: CustomRow,
                        className: "backgrid table table-hover tags-configuration-backgrid-table",
                        columns: columns,
                        collection: that.model.get("searchedTags"),
                        footer: Backgrid.Extension.Infinator.extend({
                            scrollToTop: false,
                            enabled: false, 
                        }),
                    }); 

                    // Render the grid and attach the root to your HTML document
                    //that.$el.find(".tags-grid-container").append(grid.render().el);
                    //that.show_backgrid("TAGS"); 

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

                    that.options.MYREFERENCES.subviews.subnavbarControlsRight.render(null, function () {
                        that._startAutoRefresh({ forceRedraw: true });
                        //that._autoRefresh({ forceRedraw: true }); 
                    });

                    //end
                }, true, customPath); 

            }, customPath);
        }

        , show_backgrid: function (opt) {
            var options = {
                name: "TAGS", 
            };

            options = _.extend(options, opt);

            var container = this.$el.find(".tags-grid-container");
            //container.find(".tags-configuration-backgrid-table").floatThead('destroy');

            container.empty();

            var loading_poster = this.$el.find(".loading-poster");
            if (options.loading) {
                var loading_text = loading_poster.find(".loading-text").css("display", "none");
                var searching_text = loading_poster.find(".searching-text").css("display", "none");

                if (options.searching) searching_text.css("display", "block");
                else loading_text.css("display", "block"); 

                loading_poster.css("display", "block");
                return;
            } else {
                loading_poster.css("display", "none");
            }

            for (var g in this.options.MYREFERENCES.grids) this.options.MYREFERENCES.grids[g].instance.footer.setEnabled((g == options.name));

            //if (!this.options.MYREFERENCES.grids[options.name].el) {
            //    this.options.MYREFERENCES.grids[options.name].el = $("<div></div>");
            //    this.options.MYREFERENCES.grids[options.name].el.append(this.options.MYREFERENCES.grids[options.name].instance.render().el); 
            //}

            //container.append(this.options.MYREFERENCES.grids[options.name].el);
            container.append(this.options.MYREFERENCES.grids[options.name].instance.render().el);

            container.find(".tags-configuration-backgrid-table").floatThead({
                scrollingTop: function () {
                    try{
                        return $("#subnavbar-inner").height() + $("header").height(); 
                    } catch (error) { return 111; }
                },
                zIndex:500, 
                useAbsolutePositioning: false,  
            });
        }

        , isScreenFilled: function () {
            var getWindowSize = (function () {
                var docEl = document.documentElement,
                    IS_BODY_ACTING_ROOT = docEl && docEl.clientHeight === 0,
                    b = document.body;

                // Used to feature test Opera returning wrong values
                // for documentElement.clientHeight.

                function isDocumentElementHeightOff() {
                    var d = document,
                        div = d.createElement('div'),
                        r;
                    div.style.height = "50000px";
                    d.body.insertBefore(div, d.body.firstChild);
                    r = d.documentElement.clientHeight > 49000;
                    d.body.removeChild(div);
                    return r;
                }

                if (typeof document.clientWidth === "number") {
                    return function () {
                        return {
                            width: document.clientWidth,
                            height: document.clientHeight
                        };
                    };
                } else if (IS_BODY_ACTING_ROOT || isDocumentElementHeightOff()) {
                    return function () {
                        return {
                            width: b.clientWidth,
                            height: b.clientHeight
                        };
                    };
                } else {
                    return function () {
                        return {
                            width: docEl.clientWidth,
                            height: docEl.clientHeight
                        };
                    };
                }
            })();

            var body = document.body, html = document.documentElement;

            var documentHeight = Math.max(body.scrollHeight, body.offsetHeight,
                                   html.clientHeight, html.scrollHeight, html.offsetHeight);

            return (!(getWindowSize().height >= documentHeight)); 
        }

        , 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 (options) {
            try {
                var that = this; 
                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.options.MYREFERENCES.autoRefresh.toid = setTimeout(function () { that._autoRefresh(options); }, 1);
            } catch (Error) { }
        }

        , _autoRefresh: function (options) {
            var that = this;
            options = options || {};

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

            //do not autorefresh if refreshing already
            if (!this.options.MYREFERENCES.isRefreshing && !this.options.MYREFERENCES.isSearching) {

                var fredraw = options.forceRedraw || false;
                delete options.forceRedraw;

                if (options.auto) {
                    options.collection = (this.options.MYREFERENCES.searchMode) ? "searchedTags" : "tags";
                }
                delete options.auto;

                this.refresh(fredraw, options);
            }

            if (this.options.MYREFERENCES.autoRefresh.enabled == true) {
                //refresh every one minute to avoid annoying freeze
                var autorefresh = function () { that._autoRefresh({ auto: true }); };
                //this.options.MYREFERENCES.autoRefresh.toid = setTimeout(autorefresh, (1000 * 60));
                this.options.MYREFERENCES.autoRefresh.toid = setTimeout(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;
        }

        , _agentAdquiringModelChanged: function (mm) {
            var that = this; 
            var prevAgentID = mm.previous("agentID");
            var prevAdquiringID = mm.previous("adquiringID"); 

            this.model.get("searchedTags").setFixedParameters([
                { Name: "" }
            ]);

            this.refresh(true);
            this.options.MYREFERENCES.subviews.subnavbarControlsRight.model.saveToLocalstorage();
            this.options.MYREFERENCES.subviews.subnavbarControlsLeft.clearSearchInput();

        }
        , preprocessResponse_keepChanges: function (resp) {
            var changed = this.model.get("changedTags").toJSON();
            var tags = this.model.get("tags"); 
            var respModels = [];
            var changedModels = [];

            //_.each(changed, function (i) {
            //    var m = _.findWhere(resp, { id: i.id });
            //    if (m) { respModels.push(m); changedModels.push(i); }
            //});

            //resp = _.difference(resp, respModels);

            this.tagsConfigLockCheck(resp); 

            if (tags.length > 0) {
                _.each(resp, function (m, i) {
                    var t = tags.findWhere({ id: m.id });
                    if (t != null) {
                        m.grid_status = t.get("grid_status");
                        m.grid_message = t.get("grid_message");
                    }
                });
            }

            var newresp = [];
            if (changed.length > 0) {
                _.each(resp, function (m, i) {
                    var mo = null;
                    if (mo = _.findWhere(changed, { id: m.id })) {
                        newresp.push(mo);
                    } else newresp.push(m);
                });
            }

            //resp = resp.concat(changedModels);
            resp = (changed.length > 0) ? newresp : resp; 
            return resp;
        }
        , refresh: function (forceRedraw, opt) {
            try {
                this.options.MYREFERENCES.isRefreshing = true; 
                var options = {
                    collection: "tags", 
                };
                opt = opt || {}; 
                options = _.extend(options, opt);

                var that = this; 
                forceRedraw = (forceRedraw == true) ? true : false; 

                var id = parseInt(this.options.MYREFERENCES.subviews.subnavbarControlsRight.model.get("agentID"), 10); 
                var subID = parseInt(this.options.MYREFERENCES.subviews.subnavbarControlsRight.model.get("adquiringID"), 10);
                var showOnlyEnabledTags = this.options.MYREFERENCES.subviews.subnavbarControlsLeft.model.get("showOnlyEnabledTags"); 

                var agentId = (id != -1) ? id : null; 
                var adquiringId = (subID != -1) ? subID : null;

                this.model.get(options.collection).setFixedParameters([
                    { Name: "AgentID", Type: "INT", Value: agentId },
                    { Name: "AdquiringID", Type: "INT", Value: adquiringId },
                    { Name: "OnlyEnabledTags", Type: "BIT", Value: showOnlyEnabledTags },
                ]);

                if (forceRedraw) {
                    this.show_backgrid({ loading: true });
                    this.model.get(options.collection).fetch(_.extend(options, {
                        //agentId: agentId,
                        //adquiringId: adquiringId,
                        //showOnlyEnabledTags: this.options.MYREFERENCES.subviews.subnavbarControlsLeft.model.get("showOnlyEnabledTags"), 
                        reset: true,
                        resetPagination: true, 
                        success: function (c, r, o) {
                            that.options.MYREFERENCES.isRefreshing = false;
                            that.show_backgrid({ name: "TAGS" });
                            that.keepRefreshingTillScreenFilled(r, options.collection);
                        },
                        preprocessResponse: this.preprocessResponse_keepChanges,
                    }));
                } else {
                    this.model.get(options.collection).fetch(_.extend(options, {
                        //agentId: agentId,
                        //adquiringId: adquiringId,
                        //showOnlyEnabledTags: this.options.MYREFERENCES.subviews.subnavbarControlsLeft.model.get("showOnlyEnabledTags"),
                        set: true,
                        refresh: true,
                        success: function () {
                            that.options.MYREFERENCES.isRefreshing = false;
                        },
                        preprocessResponse: this.preprocessResponse_keepChanges,
                    }));
                }
            } catch (Error) { }
        }

        , keepRefreshingTillScreenFilled: function (resp, collectionName) {
            var that = this; 
            if (!this.isScreenFilled() && resp.length > 0) {
                this.model.get(collectionName).getNextPage({
                    success: function (col, resp, opt) {
                        that.keepRefreshingTillScreenFilled(resp, collectionName); 
                    }
                });
            }
        }

        , _getXML: function (data, cols) {

            function _toString(val) {
                return (val == null) ? "" : val.toString(); 
            }

            cols = (_.isArray(cols)) ? cols : [];
            cols = _.invoke(cols, "toUpperCase");

            var xml = null;
            if (!data.length) data = [data];
            try {
                xml = '<XMLRoot>';
                for (var r = 0; r < data.length; r++) {
                    rowObj = data[r];
                    var row = '<Row ';
                    for (var c in rowObj) {
                        if ((cols.length == 0) || (cols.length > 0 && _.indexOf(cols, c.toString().toUpperCase()) != -1)) {
                            row += ((Trim(c).replace(' ', '')).replace('[', '')).replace(']', '') + '="' + _toString(rowObj[c]) + '" ';
                        }
                    }
                    row += '/>';
                    row = row.replace(/#/g, '');
                    xml += row;
                }
                xml += '</XMLRoot>';
            } catch (Error) {
            }
            return xml;
        }

        , _gridRefreshComplete: function () {
        }

        , _searchTerm_change_immediate: function () {
            var searchTerm = this.options.MYREFERENCES.subviews.subnavbarControlsLeft.model.get("searchTerm");
            this.options.MYREFERENCES.searchTerm = searchTerm;
        }
        , _searchTerm_change: _.debounce(function () {
            this.doSearch.call(this); 
        }, 400)
        , doSearch: function () {
            var that = this;
            var searchTerm = this.options.MYREFERENCES.subviews.subnavbarControlsLeft.model.get("searchTerm");
            var isEmpty = !searchTerm.trim().length > 0;
            if (!isEmpty) {
                if (!this.options.MYREFERENCES.isSearching) this.show_backgrid({ loading: true, searching: true });

                this.options.MYREFERENCES.isSearching = true;
                this.options.MYREFERENCES.searchMode = true;
                var collection = this.model.get("searchedTags");

                var id = parseInt(this.options.MYREFERENCES.subviews.subnavbarControlsRight.model.get("agentID"), 10);
                var subID = parseInt(this.options.MYREFERENCES.subviews.subnavbarControlsRight.model.get("adquiringID"), 10);
                var showOnlyEnabledTags = this.options.MYREFERENCES.subviews.subnavbarControlsLeft.model.get("showOnlyEnabledTags");

                var agentId = (id != -1) ? id : null;
                var adquiringId = (subID != -1) ? subID : null;

                this.model.get("searchedTags").setFixedParameters([
                    { Name: "AgentID", Type: "INT", Value: agentId },
                    { Name: "AdquiringID", Type: "INT", Value: adquiringId },
                    { Name: "OnlyEnabledTags", Type: "BIT", Value: showOnlyEnabledTags },
                ]);

                collection.search(searchTerm, {
                    //agentId: agentId,
                    //adquiringId: adquiringId,
                    //showOnlyEnabledTags: this.options.MYREFERENCES.subviews.subnavbarControlsLeft.model.get("showOnlyEnabledTags"),
                    success: function (collection, resp) {
                        if (that.options.MYREFERENCES.searchTerm == searchTerm) {
                            //collection.set(that.model.get("changedTags").models, { add: false, remove: false, silent: true });
                            that.show_backgrid({ name: "SEARCHEDTAGS" });
                            that.options.MYREFERENCES.isSearching = false;

                            that.keepRefreshingTillScreenFilled(resp, "searchedTags");
                        }
                    },
                    beforeAlteringCollection: function () {
                        if (that.options.MYREFERENCES.searchTerm != searchTerm) {
                            return false;
                        }
                        return true;
                    },
                    preprocessResponse: this.preprocessResponse_keepChanges
                });
            } else {
                this.options.MYREFERENCES.isSearching = false;
                this.options.MYREFERENCES.searchMode = false;
                this.show_backgrid({ loading: true });
                setTimeout(function () { that.show_backgrid({ name: "TAGS" }); }, 1);
            }
        }
        , _showOnlyEnabledTags_change: function () {
            if (this.options.MYREFERENCES.searchMode) {
                this.doSearch.call(this);
                this.refresh(false, { collection: "tags" }); 
            } else {
                this.refresh(true);
                //this.refresh(false, { collection: (this.options.MYREFERENCES.searchMode) ? "searchedTags" : "tags" });
            }
            this.options.MYREFERENCES.subviews.subnavbarControlsLeft.model.saveToLocalstorage();
        }

        , bindEvents: function () {
            this.listenTo(this.options.MYREFERENCES.subviews.subnavbarControlsLeft.model, "change:searchTerm", this._searchTerm_change);
            this.listenTo(this.options.MYREFERENCES.subviews.subnavbarControlsLeft.model, "change:searchTerm", this._searchTerm_change_immediate);
            this.listenTo(this.options.MYREFERENCES.subviews.subnavbarControlsLeft.model, "change:showOnlyEnabledTags", this._showOnlyEnabledTags_change); 

            this.listenTo(this.options.MYREFERENCES.subviews.subnavbarControlsRight.model, "change:agentID change:adquiringID", this._agentAdquiringModelChanged);

            this.listenTo(this.model.get("tags"), "change", this.tagsChanged);
            this.listenTo(this.model.get("searchedTags"), "change", this.searchedTagsChanged);

            app.models.locksManager.listenToCategory(
                this,
                ["add", "remove"],
                ["AGENTDISCONNECTED", "TAGSCONFIGCHANGE", "SETPLCADDRESS", "DBSTARTMON", "DBSTOPMON", "DBFIXCONFLICTS", "ENABLE", "DISABLE", "UNREGISTER"],
                this.tagsConfigLockCheck
            );
        }
        , tagsConfigLockCheck: function (tags) {
            var locks = app.models.locksManager.getCategoryLocks(
                ["AGENTDISCONNECTED", "TAGSCONFIGCHANGE", "SETPLCADDRESS", "DBSTARTMON", "DBSTOPMON", "DBFIXCONFLICTS", "ENABLE", "DISABLE", "UNREGISTER"],
                null, true
            );

            if (_.isArray(tags)) {
                var agentIdsLocked = locks.pluck("agentId");
                _.each(_.filter(tags, function (m) { return _.indexOf(agentIdsLocked, m.agentId) != -1; }), function (m) {
                    var lockName = locks.findWhere({ agentId: m.agentId }).get("name"); 
                    m.grid_can_commit = false;
                    m.lock_set = lockName; 
                }); 
            } else {
                var tags = this.model.get("tags");
                var search = this.model.get("searchedTags"); 

                var lockedModels = [];
                lockedModels = lockedModels.concat(tags.where({ grid_can_commit: false }), search.where({ grid_can_commit: false }));

                var modelsToLock = [];
                locks.forEach(function(model){
                    var agentId = model.get("agentId");
                    var models = []; 
                    models = models.concat(tags.where({ agentId: agentId }), search.where({ agentId: agentId }));
                    _.each(models, function (m) {
                        var lockName = locks.findWhere({ agentId: m.get("agentId") }).get("name");
                        m.set({ "grid_can_commit": false, "lock_set": lockName }, { source: TagsConfiguration.enums.sources.INTERNAL });
                    });
                    modelsToLock = modelsToLock.concat(models);
                });

                var modelsToUnlock = _.difference(lockedModels, modelsToLock);
                _.each(modelsToUnlock, function (m) {
                    m.set({ "grid_can_commit": true, "lock_set": null }, { source: TagsConfiguration.enums.sources.INTERNAL });
                });

                //if (this.options.MYREFERENCES.searchMode) this.options.MYREFERENCES.grids["SEARCHEDTAGS"].instance.render();
                //else this.options.MYREFERENCES.grids["TAGS"].instance.render();
            }
        }
        , searchedTagsChanged: function (model) {
            this.model.get("changedTags").set(model, { remove: false });
            this.model.get("tags").set(this.model.get("changedTags").models, { add: false, remove:false, silent: true }); 
        }

        , tagsChanged: function (model, opt) {
            var source = TagsConfiguration.enums.sources.UNKNOWN;
            source = (opt != null && opt != undefined && opt.source) ? opt.source : source; 

            if (source == TagsConfiguration.enums.sources.UI || source == TagsConfiguration.enums.sources.UNKNOWN)
                this.model.get("changedTags").set(model, { remove: false });
        }

        , bindViewScopedEvents: function () {

        }

        , unbindViewScopedEvents: function () {
            for (var g in this.options.MYREFERENCES.grids) {
                this.options.MYREFERENCES.grids[g].instance.footer.setEnabled(false);
            }
            this._stopAutoRefresh(); 
        }

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

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

            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("notificationBar", false);
            app.models.subnavbar.set("dateTimeScopeControl", false); 
            app.models.subnavbar.set("subnavbar", true);
            app.models.subnavbar.set("sections", "6-6"); 
        }

        , reRender: function () {
        }

        , saveConfiguration: function (e) {
            var that = this;
            var collection = this.model.get("changedTags");
            var json = collection.toJSON();

            _.forEach(json, function (m) { m["requiresLock"] = false; });
            _.forEach(_.filter(json, function (m) {
                return _.intersection(m.changedAttrs, that.options.MYREFERENCES.requireLockColumns).length > 0;
            }), function (m) {
                m["requiresLock"] = true; 
            });

            var xml = this._getXML(
                json, ["id", "name", "alias", "lineColor", "scanRate", "dataType", "stringLength", "unit", "minUnit", "maxUnit", "enabled", "requiresLock"]);

            var QP = new Core.Database.QueryParameters();
            QP.Add("XML", "XML", xml);

            app.views.topMessages.showMessage(this.options.i18n[this.template].translate("top_message_saving_text").fetch(), { stay: 10000 });

            app.log.debug(this, ("Saving new tags configuration using XML [{{xml}}].").replace("{{xml}}", xml));
            Core.Json.CallProcedure(app.DatabaseNames.IH + ".WEB.[SaveTagsCatalog]", QP, {
                onSuccess: this._handleSaveCatalog
            }, app.ConnectionStrings.app);
        }
        , _handleSaveCatalog: function (data) {

            var rowsState = data.Table;
            var rowsErrors = data.Table1;
            var rowsNotSaved = data.Table2; 
            var rowsLocked = data.Table3; 
            var transactionStatus = (data && data.Table4 && data.Table4[0]["Status"] == 1) ? true : false; 

            var collection = this.model.get("changedTags");
            collection.forEach(function (model) {
                model.set({ grid_status: null, grid_message: null }); 
            }); 

            var error_models = []; 
            if (_.isArray(rowsErrors) && rowsErrors.length > 0) {
                _.each(rowsErrors, function (i) {
                    var m = collection.findWhere({ id: i.TagID });
                    m.set({ grid_status: "error", grid_message: i.Error });
                    error_models.push(m); 
                });
            }

            var not_saved_models = [];
            if (_.isArray(rowsNotSaved) && rowsNotSaved.length > 0) {
                _.each(rowsNotSaved, function (i) {
                    var m = collection.findWhere({ id: i.TagID });
                    not_saved_models.push(m);
                });
            }

            var locked_models = [];
            if (_.isArray(rowsLocked) && rowsLocked.length > 0) {
                _.each(rowsLocked, function (i) {
                    var m = collection.findWhere({ id: i.TagID });
                    locked_models.push(m); 
                }); 
            }

            var saved_models = _.difference(collection.models, error_models, locked_models, not_saved_models); 
            _.each(saved_models, function (i) {
                i.set({ "changedAttrs": [] }, { silent: true });
            }); 

            this.model.get("tags").set(collection.models, { remove: false, add: false });
            this.model.get("searchedTags").set(collection.models, { remove: false, add: false });

            collection.remove(saved_models); 

            var container = this.$el.find(".tags-grid-container");
            //container.find(".tags-configuration-backgrid-table").floatThead('destroy');

            if (this.options.MYREFERENCES.searchMode) this.options.MYREFERENCES.grids["SEARCHEDTAGS"].instance.render();
            else this.options.MYREFERENCES.grids["TAGS"].instance.render();

            container.find(".tags-configuration-backgrid-table").floatThead({
                scrollingTop: function () {
                    try {
                        return $("#subnavbar-inner").height() + $("header").height();
                    } catch (error) { return 111; }
                },
                zIndex: 500,
                useAbsolutePositioning: false,
            });

            if (transactionStatus == true) {
                if (rowsErrors.length > 0) {
                    app.views.topMessages.showMessage(this.options.i18n[this.template].translate("top_message_some_changes_not_saved").fetch());
                } else {
                    app.views.topMessages.showMessage(this.options.i18n[this.template].translate("top_message_changes_saved").fetch());
                }
            } else {
                app.views.topMessages.showMessage(this.options.i18n[this.template].translate("top_message_error").fetch());
            }

            if (locked_models.length > 0) {
                var agentNames = _.uniq(_.map(locked_models, function (m) { return m.get("agentName"); }));
                var modal = new Modal.Views.Main({
                    id: "locked-agents"
                    , title: this.options.i18n[this.template].translate("changes_on_locked_agents_not_made_title").fetch()
                    , message: this.options.i18n[this.template].translate("changes_on_locked_agents_not_made").fetch(agentNames)
                    , allowCancel: false
                    , buttons_type: "OK"
                });

                modal.show(); 
            }

        }
    });

    TagsConfiguration.Models.SubnavBarButtons = Backbone.Model.extend({
        defaults: {
            agentID: ""
            , adquiringID: ""
        }
        , loadFromLocalstorage: function () {
            var agentID = localStorage.getItem("tags-configuration-agentID");
            var adquiringID = localStorage.getItem("tags-configuration-adquiringID");

            this.set({ agentID: agentID, adquiringID: adquiringID }, { silent: true }); 
        }
        , saveToLocalstorage: function () {
            var agentID = this.get("agentID");
            var adquiringID = this.get("adquiringID");

            localStorage.setItem("tags-configuration-agentID", agentID);
            localStorage.setItem("tags-configuration-adquiringID", adquiringID); 
        }
        , initialize: function () {
            //this.loadFromLocalstorage(); 
        }
    });

    //subview
    TagsConfiguration.Views.SubnavBarButtons = Backbone.View.extend({
        id: ""
        , title: ""
        , template: "tags-configuration"
        , 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 = {};

            this.model = new TagsConfiguration.Models.SubnavBarButtons({});

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

        events: {
            "click #saveConfiguration_button": "saveConfiguration"
        },

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

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

            T.render.call(this, this.template, function (tmp) {

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

                var ctx = {
                    editable: app.models.securityManager.getModuleActionValue("ihconfiguration_tags_configuration", "write"), 
                }; 

                that.$el.html(tmp(ctx));

                Core.Include({
                    Widgets: []
                    , Events: {
                        onLoad: function () {

                            that.model.loadFromLocalstorage(); 
                            var mm = that.model;
                            var optionID = ""; 
                            if (mm.get("agentID") != null && mm.get("adquiringID") != null) {
                                optionID = mm.get("agentID") + "&" + mm.get("adquiringID");
                            }

                            that.options.MYREFERENCES.agentsSelect = new FormSelectBootstrap(that.$("#agentsSelect").get(0), {
                                value: optionID, 
                                DatabaseInfo: {
                                    optionsData: {
                                        ConnectionStringName: app.ConnectionStrings.app
                                        , DBEngine: ""
                                        , FixedParameters: []
                                        , Procedure:  app.DatabaseNames.IH + ".WEB.GetAgentsDDP"
                                    }
                                }
                                , Events: {
                                    onValueChange: [that.agentsSelectChanged]
                                    , onRefreshOptionsDataComplete: [that.optionsDataComplete]
                                }
                                , Templates: {
                                    "parent": "<option value=\"{{Id}}&{{SubID}}\" data-content='<span>{{Name}}</span><span class=\"label label-info pull-right\">{{Type}}</span>'></option>"
                                    , "child": "<option value=\"{{Id}}&{{SubID}}\" data-content='<div style=\"width: 10px;height: 12px;border: none;border-left: 1px solid #c5c5c5; border-bottom: 1px solid #c5c5c5; float:left; margin-right:6px;\"></div><span>{{Name}}</span><span class=\"label label-info pull-right\">{{Type}}</span>' ></option>"
                                }
                            });

                            that.options.MYREFERENCES.previousValues = {
                                agentsSelect: ""
                            };

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

                            onViewComplete();
                        }
                    }
                    , ExternalWidgets: [
                        { Name: 'FormWidgetBase', URL: '/IndustrialDashboard/Widgets/FormWidgets2/FormWidgetBase/', JS: ['FormWidgetBase.js'] }
                        , { Name: 'FormWidget', URL: '/IndustrialDashboard/Widgets/FormWidgets2/FormWidget/', JS: ['FormWidget.js'], CSS: ['FormWidget.css'] }
                    ]
                });

            }, customPath, "subnav_buttons_right_template");

            //end:
        }

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

        , optionsDataComplete: function () {
        }

        , refreshAgentsSelect: function () {
            try {
                this.options.MYREFERENCES.agentsSelect.RefreshOptionsData();
            } catch (Error) { }
        }

        , agentsSelectChanged: function (e) {
            var internalID = this.options.MYREFERENCES.agentsSelect.GetValue();
            var splitted = internalID.split("&");

            var id = splitted[0];
            var subID = splitted[1];

            this.model.set({
                agentID: id
                , adquiringID: subID
            });
        }

        , saveConfiguration: function (e) {
            this.options.parent.saveConfiguration(e); 
        }

        , refresh: function (mm, force) {
            try {

                var internalID = this.options.MYREFERENCES.agentsSelect.GetValue();
                var splitted = internalID.split("&");

                var agentID = splitted[0];
                var adquiringID = splitted[1];

                if (mm && ((mm.changed["agentID"] || mm.changed["adquiringID"]) || force)) {
                    if (mm.get("agentID") != agentID || mm.get("adquiringID") != adquiringID){
                        var optionID = mm.get("agentID") + "&" + mm.get("adquiringID"); 
                        this.options.MYREFERENCES.agentsSelect.SetValue(optionID, { silent: true, force: true });
                    }
                }

            } catch (Error) { }
        }

        , checkTagsCount: function(c){
            if (c.length > 0) {
                this.$el.find("#saveConfiguration_button").prop("disabled", false);
            } else {
                this.$el.find("#saveConfiguration_button").prop("disabled", true);
            }
        }

        , 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.refresh);
            //this.listenTo(this.options.parent.model.get("changedTags"), "change", this.checkTagsCount); 
        }

        , close: function () {
            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.$el.hide();
            this.unbind();
            this.stopListening();
        }

        , reRender: function () {
        }
    });

    TagsConfiguration.Models.SubnavBarControlsLeft = Backbone.Model.extend({
        defaults: {
            searchTerm: "",
            showOnlyEnabledTags: false, 
        }
        , loadFromLocalstorage: function () {
            var showOnlyEnabledTags = localStorage.getItem("tags-configuration-showOnlyEnabledTags");
            if (showOnlyEnabledTags != null) {
                showOnlyEnabledTags = (showOnlyEnabledTags === 'true') ? true : (showOnlyEnabledTags === 'false') ? false : null; 
            }

            this.set({ showOnlyEnabledTags: ((_.isBoolean(showOnlyEnabledTags)) ? showOnlyEnabledTags : this.get("showOnlyEnabledTags")) }, { silent: true });
        }
        , saveToLocalstorage: function () {
            var showOnlyEnabledTags = this.get("showOnlyEnabledTags");
            localStorage.setItem("tags-configuration-showOnlyEnabledTags", showOnlyEnabledTags);
        }
    });

    //subview for the subnavbar controls
    TagsConfiguration.Views.SubnavBarControlsLeft = Backbone.View.extend({
        id: "tags-configuration-subnavbar-controls-left"
        , title: ""
        , template: "tags-configuration"
        , 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 = {};

            this.model = new TagsConfiguration.Models.SubnavBarControlsLeft({});

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

        events: {
            "keyup #searchTerm_input": "_searchTerm_input_keyup",
            "change #show_only_enabled_tags_checkbox": "_showOnlyEnabledTags_checkbox_click", 
        },

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

            //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/IHConfiguration/tags-configuration-v2/";

            T.render.call(this, this.template, function (tmp) {

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

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

            }, customPath, "subnav_buttons_left_template");

        }

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

        , _searchTerm_input_keyup: function () {
            this.model.set("searchTerm", this.$("#searchTerm_input").val()); 
        }

        , _showOnlyEnabledTags_checkbox_click: function (e) {
            var target = $(e.target);
            var checked = target.is(":checked");
            this.model.set("showOnlyEnabledTags", checked); 
        }

        , clearSearchInput: function () {
            try {
                this.model.set("searchTerm", ""); 
            } catch (Error) { }
        }

        , refresh: function (mm, force) {
            try {
                if (mm && (mm.changed["searchTerm"] || force)) {
                    if (mm.get("searchTerm") != this.$("#searchTerm_input").val())
                        this.$("#searchTerm_input").val(this.model.get("searchTerm"));
                }
            } catch (Error) { }
        }        

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

        , close: function () {
            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.$el.hide();
            this.unbind();
            this.stopListening();
        }

        , reRender: function () {
        }
    });

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

});
