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

  "backgrid", 

  "js/jstree/jstree",

],

function (app, T, Modal, Backgrid){

    var procsDB = app.DatabaseNames.System;
    var procsConnectionString = app.ConnectionStrings.app;

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

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

    Profiles.Collections.ModulesActionsTreeItems = Backbone.Collection.extend({
        model: Profiles.Models.TreeItem,
        initialize: function () {
            _.bindAll(this);

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

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

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

            QP.Add("id", "INT", options.data.id); 

            var items = [];
            Core.Json.CallProcedure(procsDB + ".SECURITY.GetIdentityModulesTree", QP, {
                onSuccess: function (data) {
                    if (Core.Object.Eval(data, "Table")) {
                        var data = data.Table;
                        data.sort((a, b) => {
                            const nameA = a.Name.toUpperCase();
                            const nameB = b.Name.toUpperCase();
                            if (nameA < nameB) {
                                return -1;
                            }
                            if (nameA > nameB) {
                                return 1;
                            }
                            return 0;
                        });

                        for (var i = 0; i < data.length; i++) {
                            var itemData = data[i];
                            var prodItem = {
                                id: itemData.Id,
                                parent: (itemData.ParentId != null) ? itemData.ParentId : '#',
                                type: itemData.Type.toLowerCase(),
                                text: itemData.Name,
                                checked: itemData.Checked,
                            };

                            items.push(prodItem);
                        }
                    }

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

                    if (options.callback != null && _.isFunction(options.callback))
                        options.callback.call(this, that);
                },
                Async: options.async,
            }, procsConnectionString);
           
            return this;
        },
        bindEvents: function () {
        },
    });

    Profiles.Models.Profile = Backbone.Model.extend({
        defaults: {
            id: null,
            name: null,
            internal: false, 

            //behind the scenes
            changed: false,
            prevAttrs: null,
            changedAttrs: [],
            mode: "READ",
            isNew: false,
        },
        initialize: function () {
            var opts = { loaded: false, };
            this.options = _.extend(this.options ? this.options : {}, opts);

            this.bindEvents(); 
        },
        bindEvents: function () {
        },
        setModel: function (m) {
            var ismodel = m && _.isFunction(m.toJSON) && _.isFunction(m.get) ? true : false;
            var json = (ismodel) ? m.toJSON() : m;

            this.set(json);
        },
        
    });    

    Profiles.Models.Action = Backbone.Model.extend({
        defaults: {
            id: null,
            name: null,
            role: null,
            value: null, 
        }, 
    });

    Profiles.Collections.Actions = Backbone.Collection.extend({
        model: Profiles.Models.Action,
    });

    Profiles.Collections.Profiles = Backbone.Collection.extend({
        model: Profiles.Models.Profile,
        fetch: function (opt) {
            var options = {
                method: "set",
                async: true,
                callback: null,
            };

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

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

            var items = [];

            Core.Json.CallProcedure(procsDB + ".Security.GetProfiles", QP, {
                onSuccess: function (data) {
                    if (Core.Object.Eval(data, "Table")) {
                        var data = data.Table;

                        for (var i = 0; i < data.length; i++) {
                            var itemData = data[i];

                            items.push({
                                id: itemData.Id,
                                name: itemData.Name,
                                internal: itemData.Internal, 
                            });
                        }
                    }

                    var newItems = _.where(that.toJSON(), { isNew: true });
                    [].push.apply(items, newItems);

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

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

            return this;
        },
        upsertItem: function (id, props, success, error) {
            var that = this;
            var QP = new QueryParameters();
            QP.Add("Id", "INT", id);

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

            Core.Json.CallProcedure(procsDB + ".SECURITY.UpsertProfile", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var data = data.Table;
                        var ids = _.pluck(data, 'Id');

                        if (success != null && _.isFunction(success))
                            success.call(this, that, ids);
                    } else {
                        error.call(this, that, data);
                    }
                },
                Async: true,
            }, procsConnectionString);
        },
        updateItem: function (m, success, error) {
            this.upsertItem(m.get("id"), [
                { name: "Name", type: "VARCHAR", value: m.get("name") },
            ], success, error);
        },
        callRemoveItem: function (id, success, error) {
            var that = this;
            var QP = new QueryParameters();

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

            Core.Json.CallProcedure(procsDB + ".Security.RemoveIdentity", QP, {
                onSuccess: function (data) {
                    if (data && data.Table) {
                        var data = data.Table;
                        var ids = _.pluck(data, 'Id');

                        if (success != null && _.isFunction(success))
                            success.call(this, that, ids);
                    } else {
                        error.call(this, that, data);
                    }
                },
                Async: true,
            }, procsConnectionString);
        },
        removeItem: function (id, success, error) {
            var that = this;
            var model = this.get(id);
            if (model) {
                this.callRemoveItem(
                    id
                    , function (ref, ids) {
                        //removing from collection; 
                        that.remove(model);

                        if (success && _.isFunction(success))
                            success.call(this, that, ids);
                    },
                    function (ref) {
                        if (error && _.isFunction(error))
                            error.call(this, that);
                    }
                );
            }
        },
        addItem: function (m, success, error) {
            var that = this;
            this.upsertItem(m.get("id"), [
                { name: "Name", type: "VARCHAR", value: m.get("name") },
            ], function (ref, ids) {
                m.set({ id: ids[0] });

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

    Profiles.Models.Main = Backbone.Model.extend({
        defaults: {
            profiles: null,
            profile: null,
            showFilterPerm: false,
        },
        initialize: function () {
            this.attributes.profiles = new Profiles.Collections.Profiles();
            this.attributes.profile = new Profiles.Models.Profile();

            this.bindEvents(); 
        },
        setProfile: function (profile) {
            this.get("profile").setModel(profile); 
        },
        bindEvents: function () {
        }, 
    });

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

    Profiles.Views.Main = Backbone.Epoxy.View.extend({
        template: "profiles"
        , id: "profiles"
        , title: "Profiles"
        //default not cacheable, change this if you want the view to be cacheable
        // if the view is set as cacheable should also have a refresh method to reset the view without erasing the DOM.
        , isCacheable: true
        , initialize: function () {
            this.options.state = app.view_states.loading;
            this.options.onappend = (_.isFunction(this.options.onappend)) ? this.options.onappend : function () { };

            if (this.options.viewParams) {
            }

            var model = new Profiles.Models.Main({
            });

            this.model = model;

            this.options.grids = {
                profiles: null,
            }; 

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

            this.bindEvents();
            //_.bindAll(this);
        },
        events: {
            "click .addProfile": "addProfile",
            'keyup #searchPermissionInput': 'filterPermList',
        }, 
        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/security/profiles/";

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

                    that.drawProfilesGrid();

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

                    that._startAutoRefresh(); 
                }, true, customPath); 
            }, customPath);
        }
        , drawProfilesGrid: function () {
            try {
                var that = this; 

                var ActionsCell = Backgrid.Cell.extend({
                    template: Handlebars.compile(that.$el.find("#actions_cell_template").html()),
                    initialize: function () {
                        Backgrid.Cell.prototype.initialize.apply(this, arguments);
                        this.bindEvents();
                    },
                    events: {
                        "click .btn-cell-action": "cellActionClick"
                    },
                    cellActionClick: function (e) {
                        var target = $(e.target);
                        var actionData = target.closest("[data-cell-action]").data("cell-action");
                        if (actionData) {
                            that.profiles_actionOnRow(this.model, actionData);
                        }
                    },
                    render: function () {
                        var mode = this.model.get("mode");
                        if (this.model.get("internal")) {
                            mode = "INTERNAL"; 
                        }

                        this.$el.html(this.template({
                            mode: mode, 
                        }));

                        this.$el.find("[data-toggle='tooltip']").tooltip();

                        //this.checkMode(); 
                        this.delegateEvents();
                        return this;
                    },
                    bindEvents: function () {
                        this.listenTo(this.model, "change:mode", this.render);
                    },
                });

                var columns = [
                    {
                        label: app.translate(that, "name_label"),
                        name: 'name',
                        editable: function (a, b, c) {
                            if (a.get("mode") == "EDIT" || a.get("mode") == "NEW")
                                return true;

                            return false; 
                        },
                        sortable: true,
                        cell: Backgrid.StringCell.extend({
                            orderSeparator: '',
                            className: "string-cell align-center-cell name",
                            initialize: function () {
                                Backgrid.StringCell.prototype.initialize.apply(this, arguments);

                                if (this.model.get("mode") == "EDIT" || this.model.get("mode") == "NEW") {
                                    _.delay(_.bind(this.enterEditMode, this), 50);
                                }

                                this.listenTo(this.model, "change:mode", function () {
                                    if (this.model.get("mode") == "EDIT") {
                                        this.enterEditMode();
                                    }
                                }); 
                            }, 
                        })
                    },
                    {
                        name: "actions",
                        label: "",
                        editable: false,
                        sortable: false,
                        cell: ActionsCell
                    },
                ];

                var CustomRow = Backgrid.Row.extend({
                    events: {
                        "click": "onClick"
                    },
                    className: "clickeable-row",
                    initialize: function () {
                        Backgrid.Row.prototype.initialize.apply(this, arguments);
                        this.bindEvents();
                    },
                    render: function () {
                        Backgrid.Row.prototype.render.apply(this, arguments);
                        return this;
                    },
                    onClick: function (e) {
                        var target = $(e.target);
                        var data_prevent = (target.closest("[data-preventclick]").length > 0) ? target.closest("[data-preventclick]").data("preventclick") : false;

                        if (!data_prevent) {
                            that.$el.find(".profiles-grid-container").find(".selected").removeClass("selected");
                            this.$el.addClass("selected");
                            that.profileClick(this.model);
                        }
                    },
                    bindEvents: function () {
                    },
                });
                

                var grid = new Backgrid.Grid({
                    className: "backgrid table table-hover profileTable",
                    row: CustomRow,
                    columns: columns,
                    collection: that.model.get("profiles"),
                });

                grid.render().sort("name", "ascending");

                this.options.grids.profiles = grid; 
                var grid_el = grid.render().el;
                that.$el.find(".tableProfileContainer").append(grid_el);

            } catch (error) { console.error(error); }
        }
        , profiles_actionOnRow: function (model, action) {
            action = action.toUpperCase();
            switch (action) {
                case "EDIT":
                    this.editProfile(model);
                    break;
                case "DELETE":
                    this.removeProfile(model);
                    break;
                case "SAVECHANGES":
                    this.saveProfile(model);
                    break;
                case "DISCARDCHANGES":
                    this.discardProfileChanges(model);
                    break;
            }
        }
        , editProfile: function (m) {
            m.set("mode", "EDIT");
        }
        , removeProfile: function (m) {
            var that = this;
            var id = m.get("id");
            this.model.get("profiles").removeItem(id,
                function () {
                    that.refresh();
                },
                function () {
                    that.refresh();
                }
            );
        }
        , saveProfile: function (m) {
            var that = this;
            var id = m.get("id");
            var isNew = m.get("isNew");

            if (!isNew) {
                this.model.get("profiles").updateItem(m,
                    function () {
                        m.set({ changed: false, prevAttrs: null, changedAttrs: [] }, { from: "BCHANGED" });
                        that.refresh();
                    },
                    _.bind(that.handleErrors, that)
                );
            } else {
                this.model.get("profiles").addItem(m,
                    function () {
                        m.set({ changed: false, prevAttrs: null, changedAttrs: [], isNew: false, mode: "READ" }, { from: "BCHANGED" });
                        that.refresh();
                    },
                    _.bind(that.handleErrors, that)
                );
            }
        }
        , discardProfileChanges: function (m) {
            if (m.get("isNew")) {
                m.collection.remove(m);
            } else {
                m.set(_.extend(m.get("prevAttrs"), { prevAttrs: null, changedAttrs: [], mode: "READ" }), { from: "BCHANGED" });
                this.refresh();
            }
        }
        , profilesChanged: function (m, opt, opt2) {
            var that = this;
            var source = "UNKNOWN";
            source = (opt != null && opt != undefined && opt.from) ? opt.from : source;

            if (source == "UNKNOWN") {
                var prevAttrs = m.get("prevAttrs");
                if (!prevAttrs) prevAttrs = _.omit(m.previousAttributes(), "prevAttrs");

                m.set({
                    changed: true,
                    prevAttrs: prevAttrs,
                }, { from: "BCHANGED" });

                m.set({
                    "changedAttrs": _.union(m.get("changedAttrs"), _.keys(m.changed)),
                }, { from: "BCHANGED" });
            }
        }
        , profileNameChanged: function (a, b, c) {
            var that = this; 
            var m = a;
            var from = "UI";
            from = (c && c.from) ? c.from.toUpperCase() : from;

            if (from == "UI") {
                if (m.get("id") != -1) {
                    this.model.get("profiles").updateItem(m,
                        function () {
                            m.set({ changed: false, prevAttrs: null, changedAttrs: [], mode: "READ" }, { from: "BCHANGED" });
                            that.refresh();
                        },
                        _.bind(that.handleErrors, that)
                    );
                }
            }
        }
        , addProfile: function () {
            this.model.get("profiles").unshift(new Profiles.Models.Profile({
                id: -1,
                isNew: true,
                mode: "NEW", 
            }));
        }
        , handleErrors: function (a, b, c) {
            var that = this;

            var error = {
                type: (b && b.ErrorType) ? b.ErrorType.toUpperCase() : "UNKNOWN",
                message: (b && b.Message) ? b.Message : "UNKNOWN",
            };

            var error_message = "";
            switch (error.message) {
                default:
                    error_message = app.translate(app, "DEFAULT_CATALOG_ERROR_MESSAGE");
                    break;
            }

            app.views.topMessages.showMessage(error_message);

            this.refresh();
        }
        , 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;
            }
        }
        , refresh: function () {
            try {
                this.model.get("profiles").fetch();
            } catch (Error) { }
        }
        , profileClick: function (model) {
            if (model.get("id") != this.model.get("profile").get("id")) {
                this.model.setProfile(model);
            }
        }
        , profileChanged: function () {
            var that = this;

            if (this.options.MYREFERENCES.subviews.modulesActionsTree)
                this.options.MYREFERENCES.subviews.modulesActionsTree.close();

            var modulesActionsConfigurationContainer = this.$el.find(".modules-actions-tree-view-container");

            var model = new Profiles.Models.ModulesActionsTree({
            });

            this.options.MYREFERENCES.subviews.modulesActionsTree = new Profiles.Views.ModulesActionsTree({
                container: modulesActionsConfigurationContainer,
                model: model,
                parent: that, 
            });

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

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

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

            this.refresh();

            if (this.options.MYREFERENCES.autoRefresh.enabled == true) {
                this.options.MYREFERENCES.autoRefresh.toid = setTimeout(_.bind(this._autoRefresh, this), 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;
        }
        , bindEvents: function () {
            //this function should be in every view that uses listenTo anywhere
            //all the model bindings or view-model binding should be here, to manage
            //the show/hide view easily
            this.listenTo(this.model.get("profiles"), "change", this.profilesChanged);
            this.listenTo(this.model.get("profiles"), "change:name", _.debounce(this.profileNameChanged, 100));

            this.listenTo(this.model.get("profile"), "change:id", this.profileChanged);
        }
        , 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();
        }
        , preRender: function () {
            app.models.subnavbar.set("dateControl", false);
            app.models.subnavbar.set("subnavbar", false);
        }
        , reRender: function () {
        }
        , filterPermList: function () {
            var input, filter, ul, liList, i, txtValue;
            input = document.getElementById("searchPermissionInput");
            filter = input.value.toUpperCase();
            ul = document.getElementsByClassName('jstree-container-ul')[0];
            liList = ul.getElementsByTagName("li");

            for (i = 0; i < liList.length; i++) {
                li = liList[i]
                if (li) {
                    txtValue = li.textContent || li.innerText;
                    if (txtValue.toUpperCase().indexOf(filter) > -1) {
                        liList[i].style.display = "";
                    } else {
                        liList[i].style.display = "none";
                    }
                }
            }
        }
    });

    Profiles.Models.ModulesActionsTree = Backbone.Epoxy.Model.extend({
        defaults: {
            modulesActionsItems: null,
        },
        initialize: function (model, options) {
            this.attributes.modulesActionsItems = new Profiles.Collections.ModulesActionsTreeItems(); 
        },
    });

    Profiles.Views.ModulesActionsTree = Backbone.Epoxy.View.extend({
        template: "profiles"
        , id: "modules-actions-tree"
        , title: ""
        //default not cacheable, change this if you want the view to be cacheable
        // if the view is set as cacheable should also have a refresh method to reset the view without erasing the DOM.
        , isCacheable: false
        , bindings: "data-bind"
        , initialize: function () {
            this.options.state = app.view_states.loading;
            this.options.onappend = (_.isFunction(this.options.onappend)) ? this.options.onappend : function () { };

            if (this.options.viewParams) {
            }

            this.options.trees = {
                modulesActions: null, 
            };

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

            this.options.MYREFERENCES.subviews = {};

            var model = this.model;

            this.bindEvents();
            //_.bindAll(this);
        },
        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/IHConfiguration/security/profiles/";

            var tmp = Handlebars.compile(that.options.parent.$el.find("#modules_actions_tree_view").html());
            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();

                

                var disabled = !app.models.securityManager.getModuleActionValue("ihconfiguration_security_profiles", "write");

                var treeContainer = that.$el.find(".modules-actions-tree-container"); 
                $.jstree.defaults.core.themes.variant = "large";
                treeContainer.jstree({
                    core: {
                        check_callback: true,
                        data: function (obj, cb) {
                            var data = that.model.get("modulesActionsItems").toJSON();
                            if (disabled) {
                                _.each(data, function (t) {
                                    t.state = {
                                        disabled: true,
                                    };
                                });
                            }

                            cb.call(this, data);
                        },
                    },
                    checkbox: {
                        "three_state": true,
                        "keep_selected_style": true,
                        "whole_node": false, 
                        tie_selection: false, 
                    },
                    types: {
                        "#": {
                            valid_children: ['module']
                        },
                        "module": {
                            "icon": "fa fa-circle-thin",
                            valid_children: ['action'],
                        },
                        "action": {
                            "icon": "fa fa-chevron-right",
                            max_children: 0
                        }
                    },
                    plugins: [
                        "wholerow",
                        "types",
                        "checkbox",
                    ],
                }); 

                that.options.trees.modulesActions = treeContainer.jstree(true);

                treeContainer.bind({
                    "create_node.jstree": _.bind(function () { }, that),
                    "delete_node.jstree": _.bind(function () { }, that),
                    "select_node.jstree": _.bind(that.treeModuleSelected, that),
                    "check_node.jstree": _.bind(function (a, b, c) {
                        if (b && b.event != "REFRESH") {
                            that.node_checked.call(that, a, b, c); 
                        }
                    }, that),
                    "uncheck_node.jstree": _.bind(function (a, b, c) {
                        if (b && b.event != "REFRESH") {
                            that.node_unchecked.call(that, a, b, c);
                        }
                    }, that),
                    "deselect_node.jstree": _.bind(function () { }, that),
                    "deselect_all.jstree": _.bind(function () { }, that),
                    "refresh.jstree": function (e, data) {
                        var checked = that.model.get("modulesActionsItems").where({ checked: true });
                        var checkedArr = _.map(checked, function (t) {
                            return t.get("id"); 
                        });

                        data.instance.check_node(checkedArr, "REFRESH"); 
                    }, 
                });

                that.refresh(); 

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

                //end:

            }, true, customPath);
        }
        , node_checked: function (a, b, c) {
            var that = this; 
            var node = b.node;
            var parentsc = node.parents.length; 
            var type = node.type;

            var id = node.id.split("+")[parentsc - 1]; 
            switch (type) {
                case "module":
                    that.updateModuleOnIdentity(id, that.options.parent.model.get("profile").get("id"), true, function (ctx, data) {
                        that.refresh(); 
                    });
                    break;
                case "action":
                    that.updateActionOnModule(id, that.options.parent.model.get("profile").get("id"), true, function (ctx, data) {
                        that.refresh(); 
                    });
                    break; 
            }
        }
        , node_unchecked: function (a, b, c) {
            var that = this; 
            var node = b.node;
            var parentsc = node.parents.length;
            var type = node.type;

            var id = node.id.split("+")[parentsc - 1];
            switch (type) {
                case "module":
                    that.updateModuleOnIdentity(id, that.options.parent.model.get("profile").get("id"), false, function (ctx, data) {
                        //that.refresh(); 
                        that.debounce_refresh(); 
                    });
                    break;
                case "action":
                    that.updateActionOnModule(id, that.options.parent.model.get("profile").get("id"), false, function (ctx, data) {
                        //that.refresh(); 
                        that.debounce_refresh();
                    });
                    break;
            }
        }
        , updateModuleOnIdentity: function (id, identityId, value, callback) {
            try{
                var that = this,
                    options = {
                        callback: callback, 
                    }, 
                    QP = new Core.Database.QueryParameters();

                QP.Add("id", "INT", id);
                QP.Add("identityId", "INT", identityId);
                QP.Add("value", "BIT", value);

                var items = [];
                Core.Json.CallProcedure(procsDB + ".SECURITY.UpdateModuleOnIdentity", QP, {
                    onSuccess: function (data) {
                        app.models.appController.set("menuChanged", true); 

                        if (options.callback != null && _.isFunction(options.callback))
                            options.callback.call(this, that, data);
                    },
                    Async: options.async,
                    Secured: true, 
                }, procsConnectionString);
            } catch (error) {
                console.log(error); 
            }
        }
        , updateActionOnModule: function (id, identityId, value, callback) {
            try{
                var that = this,
                    options = {
                        callback: callback,
                    },
                    QP = new Core.Database.QueryParameters();

                QP.Add("id", "INT", id);
                QP.Add("identityId", "INT", identityId);
                QP.Add("value", "BIT", value);

                var items = [];
                Core.Json.CallProcedure(procsDB + ".SECURITY.UpdateActionOnModule", QP, {
                    onSuccess: function (data) {
                        app.models.appController.set("menuChanged", true);

                        if (options.callback != null && _.isFunction(options.callback))
                            options.callback.call(this, that, data);
                    },
                    Async: options.async,
                    Secured: true, 
                }, procsConnectionString);
            } catch (error) {
                console.log(error); 
            }
        }
        , append: function (container, el) {
            el = (el != null && el != undefined) ? el : this.$el;

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

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

                this.options.onappend(this);
            }

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

            if (this.options.state == app.view_states.closed) {
                //return without appending.
                return;
            }
        }
        , reRender: function (viewParams) {
            try {
            } catch (Error) { }
        }
        , refresh: function (viewParams) {
            var that = this;
            that.options.parent.model.set('showFilterPerm', true)
            this.model.get("modulesActionsItems").fetch({
                data: {
                    id: that.options.parent.model.get("profile").get("id"), 
                }
            });
            that.options.parent.model.set('showFilterPerm', true)

        }
        , debounce_refresh: _.debounce(function (viewParams) {
            this.refresh(viewParams);
        }, 500)
        , treeModuleSelected: function (e, obj) {
            var that = this;
            var node = obj.node;
            var instance = obj.instance;
            var collection = this.model.get("modulesActionsItems");

            switch (node.type) {
                case "module":
                    break;
                case "action":
                    break; 
            }
        }
        , modulesActionsItemsChanged: function (a, b, c) {
            var fromFetch = (
                            (c && c.from && c.from == "fetch") ||
                            (!c && b && b.from == "fetch")
                            ) ? true : false;

            if (fromFetch) {
                (_.bind(this.debounced_refreshModulesActionsTree, this))();
            }
        }
        , debounced_refreshModulesActionsTree: _.debounce(function () {
            this.options.trees.modulesActions.refresh({
                forget_state: true, 
            });
        }, 500)
        , 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.get("modulesActionsItems"), "add", _.bind(this.modulesActionsItemsChanged, this));
            this.listenTo(this.model.get("modulesActionsItems"), "remove", _.bind(this.modulesActionsItemsChanged, this));
            this.listenTo(this.model.get("modulesActionsItems"), "change", _.bind(this.modulesActionsItemsChanged, this));
        }
        , bindViewScopedEvents: function () {
        }
        , unbindViewScopedEvents: function () {
        }
        , close: function () {
            this.options.state = app.view_states.closed;

            this.closeSubviews();
            this.remove();
            this.unbindViewScopedEvents();
            this.unbind();
        }
        , closeSubviews: function () {
            _.each(this.options.MYREFERENCES.subviews, function (sview) {
                sview.close();
            });
        }
        , show: function () {
            this.options.state = app.view_states.shown;

            this.showSubviews();
            this.bindEvents();
            this.$el.show();
        }
        , showSubviews: function () {
            _.each(this.options.MYREFERENCES.subviews, function (sview) {
                sview.show();
            });
        }
        , resetModel: function () {
            this.model.set(this.model.defaults);
        }
        , hide: function () {
            this.options.state = app.view_states.hidden;

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

            this.$el.hide();
            this.unbind();
            this.stopListening();
        }
        , hideSubviews: function () {
            _.each(this.options.MYREFERENCES.subviews, function (sview) {
                sview.hide();
            });
        }
        , preRender: function () {
            app.models.subnavbar.set("subnavbar", false);
        }
    });

    //Profiles.Models.Property = Backbone.Model.extend({
    //    defaults: {
    //        code: null,
    //        name: null,
    //        value: null, 
    //    }, 
    //});

    //Profiles.Models.PropertyValue = Backbone.Model.extend({
    //    id: null,
    //    code: null,
    //}); 

    //Profiles.Models.ModulePropertiesConfiguration = Backbone.Epoxy.Model.extend({
    //    defaults: {
    //    },
    //    initialize: function (model, options) {
    //    }, 
    //}); 

    //Profiles.Views.ModulePropertiesConfiguration = Backbone.Epoxy.View.extend({
    //    template: "profiles"
    //    , id: "module-properties-configuration"
    //    , title: "Module Properties Configuration"
    //    //default not cacheable, change this if you want the view to be cacheable
    //    // if the view is set as cacheable should also have a refresh method to reset the view without erasing the DOM.
    //    , isCacheable: false
    //    , bindings: "data-bind"
    //    , initialize: function () {
    //        this.options.state = app.view_states.loading;
    //        this.options.onappend = (_.isFunction(this.options.onappend)) ? this.options.onappend : function () { };

    //        if (this.options.viewParams) {
    //        }

    //        this.options.grids = {
    //            properties: null, 
    //        };

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

    //        this.options.MYREFERENCES.subviews = {};

    //        var model = this.model; 

    //        this.bindingSources = {
    //            actions: function () {
    //                return model.get('actions');
    //            },
    //        };

    //        this.bindEvents();
    //        //_.bindAll(this);
    //    },
    //    events: {
    //    },
    //    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/IHConfiguration/security/profiles/";

    //        var tmp = Handlebars.compile(that.options.parent.$el.find("#screen_actions_configuration").html()); 
    //        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();

    //            var columns = [
    //                {
    //                    label: app.translate(that, "name_label"),
    //                    name: 'name',
    //                    editable: false,
    //                    sortable: false,
    //                    cell: Backgrid.StringCell.extend({
    //                        orderSeparator: '',
    //                        className: "string-cell align-center-cell name",
    //                    })
    //                },
    //                {
    //                    label: app.translate(that, "value_label"),
    //                    name: 'value',
    //                    editable: false,
    //                    sortable: false,
    //                    cell: Backgrid.Cell.extend({
    //                        template: _.template("<input class='value-checkbox' tabindex='-1' type='checkbox' />"),
    //                        initialize: function () {
    //                            Backgrid.Cell.prototype.initialize.apply(this, arguments);
    //                        },
    //                        events: {
    //                            "change .value-checkbox": "chkboxChanged",
    //                        },
    //                        chkboxChanged: function (e) {
    //                            this.model.set("value", $(e.target).is(":checked"));
    //                        },
    //                        render: function () {
    //                            this.$el.html(this.template());

    //                            if (this.model.get("value")) this.$el.find(".value-checkbox").attr("checked", "checked");
    //                            this.delegateEvents();
    //                            return this;
    //                        },
    //                        className: "align-center-cell enabled",
    //                    }),
    //                },
    //            ];

    //            var grid = new Backgrid.Grid({
    //                className: "backgrid table table-hover",
    //                columns: columns,
    //                collection: that.model.get("actions"),
    //            });

    //            that.options.grids.actions = grid;
    //            var grid_el = grid.render().el;
    //            that.$el.find(".actions-grid-container").append(grid_el);

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

    //            //end:

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

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

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

    //            this.options.onappend(this);
    //        }

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

    //        if (this.options.state == app.view_states.closed) {
    //            //return without appending.
    //            return;
    //        }
    //    }
    //    , reRender: function (viewParams) {
    //        try {
    //        } catch (Error) { }
    //    }
    //    , refresh: function (viewParams) {
    //    }
    //    , checkRender: function (a, b, c) {
    //        var fromFetch = (b && b.from == "fetch") ? true : false;
    //        if (fromFetch) {
    //            this.render();
    //        }
    //    }
    //    , setSaveCancelButtons: function (val) {
    //        var btnSave = this.$el.find(".btn-save");
    //        var btnCancel = this.$el.find(".btn-cancel");

    //        btnSave.prop("disabled", !val);
    //        btnCancel.prop("disabled", !val);
    //    }
    //    , bindEvents: function () {
    //        //this function should be in every view that uses listenTo anywhere
    //        //all the model bindings or view-model binding should be here, to manage
    //        //the show/hide view easily
    //        this.listenTo(this.model, "change", this.checkRender);

    //        //this.listenTo(this.model, "change", this.checkButtonsState);
    //    }
    //    , bindViewScopedEvents: function () {
    //    }
    //    , unbindViewScopedEvents: function () {
    //    }

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

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

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

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

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

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

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

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

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

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

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

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

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

});
