/// class PD.Web.UI.Controls.Security.PermissionsEditor
/// using PD.Web.UI.Controls.Control

PD.Web.UI.Controls.Security.PermissionsEditor =
PD.Web.UI.Controls.Control.extend({

    //===========================
    // FIELDS
    //===========================

    _grid: null,
    _permissions: null,
    _ace: null,

    //===========================
    // CONSTRUCTORS
    //===========================

    init: function (options) {
        this._super(options);

        this._ace = { allow: 0, deny: 0 };
        
    },

    //===========================
    // PROPERTIES
    //===========================

    get_ddl: function () {
        return this.get_node().find("select");
    },

    //===========================
    // EVENT HANDLERS
    //===========================

    onInit: function () {
        this._grid_init();
    },

    onComplete: function () {

        this.get_ddl().on("change", _.bind(this._ddl_onChange, this));

        this._filterPermissions(true);

        this.get_node().find("div[data-id=grid]").on("change",
            ".allow input[type=checkbox]",
            _.bind(this._checkbox_allow_onChange, this));

        this.get_node().find("div[data-id=grid]").on("change",
            ".deny input[type=checkbox]",
            _.bind(this._checkbox_deny_onChange, this));

    },

    //===========================
    // PUBLIC METHODS
    //===========================
    
    /*
    == arguments ==
    options: { 
        permissions: [ { 
            isBasic: true|false,
            value: number,
            name: string
        }],  
        ace: {
            allow: number,
            deny: number
        }
    }
    */
    load: function (options) {
        this._permissions = options.permissions;
        this._ace = _.extend({ allow: 0, deny: 0}, options.ace);

        if (!this._hasExpandedPermissions()) {
            this.get_ddl().hide();
        }

    },

    getAcePermissions: function () {
        return this._ace;
    },

    //===========================
    // PROTECTED METHODS
    //===========================

    template: function (options) {
        return [
            "<div>",
                "<div style='position:absolute;top:0;left:0px;right:0;height:30px;'>",
                    "<table style='width:100%;'>",
                        "<tr>",
                            "<td>",
                                "<label style='font-weight:bold;'>",
                                    "Permissions",
                                "</label>",
                            "</td>",
                            "<td style='text-align:right;'>",
                                "<select data-id='permissions-type' style='width:180px;padding:2px;'>",
                                    "<option value='1'>Basic</option>",
                                    "<option value='0'>Expanded</option>",
                                "</select>",
                            "</td>",
                        "</tr>",
                    "</table>",
                "</div>",
                "<div data-id='grid' style='position:absolute;top:30px;left:0px;right:0;bottom:2px;border:1px solid #cccccc;'></div>",
            "</div>"
        ];
    },

    //===========================
    // PRIVATE METHODS
    //===========================

    _grid_init: function () {

        this._grid = new PD.Web.UI.Controls.Grid({
            insertAt: "div[data-id=grid]",
            selectionMode: "none",
            messaging: {
                noRecordsMessage: "No Permissions Defined"
            },
            columns: [
                new PD.Web.UI.Controls.GridColumn({
                    title: "Name",
                    field: "name"
                }),
                new PD.Web.UI.Controls.GridCheckboxColumn({
                    title: "Allow",
                    width: "40px",
                    attributes: {
                        class: "permission-check allow"
                    }
                }),
                new PD.Web.UI.Controls.GridCheckboxColumn({
                    title: "Deny",
                    width: "40px",
                    attributes: {
                        class: "permission-check deny"
                    }
                }),
                new PD.Web.UI.Controls.GridColumn({
                    field: "value",
                    hidden: true,
                    template: function (e) {
                        return "<input data-id='permission-id' value='" + (e.value == null ? -1 : e.value ) + "' />";
                    }
                })
            ]
        });

        this.get_children().add(this._grid);

    },

    _ddl_onChange: function () {

        var value = this.get_ddl().find(":selected").attr("value") * 1;

        this._filterPermissions(value);

    },

    _filterPermissions: function (isBasic) {

        var data = _.filter(this._permissions, function (e) {
            return e.isBasic == isBasic;
        });

        this._grid.get_dataSource().data(data);

        this._updateCheckboxesToMatchAce();
        
    },
    
    _checkbox_allow_onChange: function (e) {

        var $checkbox = $(e.currentTarget);
        var permission = this._checkbox_getPermissionValue($checkbox);
        var role = "allow"
        
        this._checkbox_clearAnalog($checkbox);

        this._updateAce($checkbox, role);
        
        this._setCheckboxSpecialPermissionState($checkbox, false);

    },
    
    _checkbox_deny_onChange: function (e) {

        var $checkbox = $(e.currentTarget);
        var permission = this._checkbox_getPermissionValue($checkbox);
        var role = "deny"
        
        this._checkbox_clearAnalog($checkbox);

        this._updateAce($checkbox, role);
        
        this._setCheckboxSpecialPermissionState($checkbox, false);

    },

    _checkbox_clearAnalog: function ($target) {

        var isAllow = $target.closest(".permission-check").hasClass("allow");
        var $checkbox = null;

        if (isAllow) {
            $checkbox = $target.closest("tr").find(".deny input[type=checkbox]");
        }
        else {
            $checkbox = $target.closest("tr").find(".allow input[type=checkbox]");
        }

        $checkbox.prop("checked", false);

        this._setCheckboxSpecialPermissionState($checkbox, false);

    },
    
    _checkbox_setChecked: function (role) {

        var that = this;
        var ace = this._ace;
        
        _.each(this._getCheckboxesAndValues(role), function (item) {

            var hasSpecialPermissions = that._hasSpecialPermission(role, item.value);;
                
            item.checkbox.prop("checked", (ace[role] & item.value) === item.value);
            
            if (hasSpecialPermissions) {
                item.checkbox.prop("checked", hasSpecialPermissions);
            }
            
            that._setCheckboxSpecialPermissionState(item.checkbox, hasSpecialPermissions);

        });
        
    },

    _checkbox_getPermissionValue: function ($element) {

        var result = 0;
        var data = this._grid.getRowData($element);

        if (data != null) {
            result = data.value;
        }

        return result;

    },

    _checkbox_findDeny: function ($element) {
        return $element.closest("tr").find(".deny input[type=checkbox]");
    },

    _checkbox_findAllow: function ($element) {
        return $element.closest("tr").find(".allow input[type=checkbox]");
    },
    
    _updateAce: function ($checkbox, role) {
        
        var permission = this._checkbox_getPermissionValue($checkbox);
        var diametricRole = (role === "allow" ? "deny" : "allow");
        var check = $checkbox.is(":checked");
        var ace = this._ace;

        if (check) {
            ace[role] = ace[role] | permission;
        }
        else {
            ace[role] = ace[role] & ~permission;
        }

        ace[diametricRole] = ace[diametricRole] & ~permission;
        
    },

    _updateCheckboxesToMatchAce: function () {
        this._checkbox_setChecked("allow");
        this._checkbox_setChecked("deny");
    },

    _hasSpecialPermission: function (role, permission) {

        var acePermission = this._ace[role];

        return ((acePermission & permission) !== permission) && ((acePermission & permission) !== 0);

    },
    
    _getCheckboxesAndValues: function (role) {

        var that = this;
        var result = [];
        
        this.get_node()
            .find("div[data-id=grid] ." + role + " input[type=checkbox]").each(function (idx, el) {

            result[result.length] = { checkbox: $(el), value: that._checkbox_getPermissionValue($(el)) };
            
        });
        
        return result;

    },

    _setCheckboxSpecialPermissionState: function ($checkbox, hasSpecialPermissions) {

        $checkbox.css({
            opacity: hasSpecialPermissions ? ".3" : "1"
        });

    },

    _hasExpandedPermissions: function () {
        var found = _.find(this._permissions, function (item) {
            return item.hasOwnProperty("isBasic");
        });
        return found != null;
    }

});