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

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

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

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

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

    init: function (options) {
        this._permissions = options.permissions || [];
        this._super(_.extend({
            enabled: true,
            change: function () { }
        }, options));
    },

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

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

    get_isBasicView: function () {
        return (this.get_ddl().find(":selected").attr("value") * 1) == 1;
    },

    get_enabled: function () {
        return this.get_options().enabled;
    },
    set_enabled: function (value) {
        this.get_options().enabled = value;
        this._updateCheckBoxesToReflectEnabledState();
    },

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

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

    onComplete: function () {

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

        this.loadPermissions();

        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
        }
    }
    */
    loadAce: function (ace) {
        this._clearAllCheckboxes();
        if (ace == null) {
            return;
        }
        this._ace = _.extend({ allow: 0, deny: 0 }, ace);
        this._filterPermissions();
        this._updateCheckBoxesToReflectEnabledState();
    },

    /*
    == arguments ==
    permissions: [{ 
        isBasic: true|false,
        value: number,
        name: string
    }]
    */
    loadPermissions: function (permissions) {
        this._permissions = permissions || this._permissions;
        if (!this._hasExpandedPermissions()) {
            this.get_ddl().hide();
        }
        this._filterPermissions(true);
    },

    redraw: function () {
        this._grid.redraw();
        this.loadAce(this._ace);
    },

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

    template: function (options) {
        return [
            "<div class='-pd-ace-editor'>",
                "<div class='-pd-ace-editor-header'>",
                    "<div>",
                        "<label>Permissions</label>",
                    "</div>",
                    "<div>",
                        "<select data-id='permissions-type'>",
                            "<option value='1'>Basic</option>",
                            "<option value='0'>Expanded</option>",
                        "</select>",
                    "</div>",
                "</div>",
                "<div data-id='grid' class='-pd-ace-editor-grid' style='border:1px solid #CCCCCC;'></div>",
            "</div>"
        ];
    },

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

    _updateCheckBoxesToReflectEnabledState: function () {
        if (this.get_enabled()) {
            this._enableAllCheckboxes();
        }
        else {
            this._disableAllCheckboxes();
        }
    },

    _grid_init: function () {

        this._grid = new PD.Web.UI.Controls.Grid({
            insertAt: "div[data-id=grid]",
            selectionMode: "none",
            footer: {
                visible: false
            },
            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);

        this._updateCheckBoxesToReflectEnabledState();

    },

    _filterPermissions: function (isBasic) {

        isBasic = isBasic == null ? this.get_isBasicView() : isBasic;

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

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

        if (this._ace == null) {
            this._disableAllCheckboxes();
        }
        else {
            this._enableAllCheckboxes();
        }

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

        if (this._ace == null) {
            return;
        }

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

        if (this._ace == null) {
            return;
        }

        var permission = this._checkbox_getPermissionValue($checkbox);
        var diametricRole = (role === "allow" ? "deny" : "allow");
        var check = $checkbox.is(":checked");
        var ace = this._ace;
        var callback = this.get_options().change;

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

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

        if (_.isFunction(callback)) {
            callback(ace);
        }

    },

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

    _hasSpecialPermission: function (role, permission) {

        if (this._ace == null) {
            return;
        }

        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["isBasic"] == false;
        });
        return found != null;
    },

    _disableAllCheckboxes: function () {
        this.get_node().find('input:checkbox').attr('disabled', 'disabled');
    },
    
    _enableAllCheckboxes: function () {
        this.get_node().find('input:checkbox').removeAttr('disabled');
    },

    _clearAllCheckboxes: function () {
        this.get_node().find('input:checkbox').removeAttr('checked');
    }

});