define([], function () {

    /**
     * Right class
     * @class
     * @constructor
     * @property {Number} bitmask - Right bitmask
     * @property {Number} view - View rights
     * @property {Number} edit - Edit rights
     */
    var Right = function (mode) {
        'use strict';
        this.model = new Right.Model(mode);
        this.view = new Right.View(mode);
        this.model.setView(this.view);
        this.view.setModel(this.model);
    };

    Right.Model = function (mode) {
        'use strict';
        this.view = null;

        this.mode = mode;

        /**
         * Right bitmask
         * @private
         * @type {Number}
         */
        this.bitmask = null;

        /**
         * View rights
         * @private
         * @type {Number}
         */
        this.right = null;
    };

    Right.Model.prototype = (function () {
        'use strict';
        var setView = function (view) {
            this.view = view;
        };

        /**
         * Set data
         * @private
         * @memberOf Right
         * @param {Object} data - JSON object
         * @returns {Object} Right
         */
        var setData = function (data) {
            setBitmask.call(this, data.bitmask);
            if (this.mode === 'view') {
                setRight.call(this, data.view);
            } else {
                setRight.call(this, data.edit);
            }
        };

        var setBitmask = function (bitmask) {
            this.bitmask = parseInt(bitmask, 10);
        };

        /**
         * Get bitmask
         * @private
         * @memberOf Right
         * @returns {Number}
         */
        var getBitmask = function () {
            if (_.isNumber(this.bitmask)) {
                return this.bitmask;
            } else {
                return NaN;
            }
        };

        var setRight = function (right) {
            this.right = parseInt(right, 10);
        };

        /**
         * View permission
         * @private
         * @memberOf Right
         * @returns {Boolean}
         */
        var getRight = function () {
            if (_.isNumber(this.right)) {
                return this.right;
            } else {
                return NaN;
            }
        };

        /**
         * Edit permission
         * @private
         * @memberOf Right
         * @returns {Boolean}
         */
        var getMode = function () {
            return this.mode;
        };

        return {
            setView: setView,
            /**
             * Initalise object
             * @public
             * @memberOf Right
             */
            setData: setData,

            /**
             * Get bitmask
             * @public
             * @memberOf Right
             * @returns {Number}
             */
            bitmask: getBitmask,

            /**
             * View permission
             * @public
             * @memberOf Right
             * @returns {Number}
             */
            right: getRight,

            mode: getMode,

            setRight: setRight
        };
    })();

    Right.View = function (mode) {
        'use strict';
        this.mode = mode;
        this.model = null;
        this.el = null;
    };

    Right.View.prototype = (function () {
        'use strict';
        var setModel = function (model) {
            this.model = model;
        };

        var render = function () {
            var el = $(_.template($('#right-tmpl').html())(this.model));
            this.el = el;
            bindElements.call(this, el);
            return el;
        };

        var bindElements = function (el) {
            $(el).on('click', 'a', {
                view: this
            }, rightToggle);
            $(el).on('right.change', {
                view : this
            }, rightSelect);
            $(el).on('right.change-no-recurse', {
                view : this
            }, rightReplace);
        };

        /**
         * Toggle rights
         * @private
         */
        var rightToggle = function (event) {
            event.preventDefault();
            $('#state-select').parent().remove();
            var self = event.data.view;
            $('html').on('click', function () {
                $('#state-select').parent().remove();
            });
            rightDropdown.call(self, this);
            return false;
        };

        var rightReplace = function (event, params){
            if(event.data.view.model.bitmask == -1)
                event.data.view.updateAndReplace(params.newRight);
            else
                event.data.view.updateAndReplaceWithUndo(params.newRight);
        };

        var rightSelect = function (event) {
            event.preventDefault();
            //event.stopPropagation();
            $('#state-select').parent().remove();
            var view = event.data.view;
            var originalRight = view.model.right;
            var originalElement = $(view.el);
            var mode = originalElement.data('mode');
            var row = originalElement.parent('tr');
            var groupId = parseInt(row.data('group-id'));
            var ruleId = parseInt(row.data('rule-id'));
            var bitmask = parseInt(view.model.bitmask, 10);
            var option = $(this);
            var newRight = option.data('right');
            if (view.model.bitmask == -1) {
                //change all the matching cells in this row
                $(row).children().each(function(){
                    if($(this).data('bitmask')!=-1 && $(this).data('mode') == mode)
                        $(this).trigger('right.change-no-recurse',{"newRight":newRight});
                });
                var numCellsAffected = $(row).children('[data-bitmask!=-1][data-mode=' + mode + ']').length;
                view.updateAndReplace(newRight);
                Instance.Undo.model.addHistory({
                    action: 'all-change',
                    "groupId": groupId,
                    "ruleId": ruleId,
                    right: mode,
                    depth: numCellsAffected,
                    original: originalRight,
                    current: newRight
                });
            }else{
                //check if all the cells now match
                var allsame = true;
                $(row).children().each(function () {
                    if ($(this).data('bitmask') != -1 && $(this).data('bitmask') != bitmask && $(this).data('mode') == mode)
                    {
                        var link = $(this).find('a');
                        if( link.data('value') !== undefined && link.data('value') != newRight)
                            allsame = false;
                    }
                });
                var allElem = row.find('td[data-bitmask=-1][data-mode=' + mode + ']');
                var allRight;
                if (allsame) {
                    allRight = newRight;
                } else {
                    allRight = 3;
                }
                allElem.trigger("right.change-no-recurse", {
                    "newRight": allRight
                });
                view.updateAndReplaceWithUndo(newRight);
            }
        };

        var updateAndReplace = function (newRight){
            var originalElement = $(this.el);;
            var row = originalElement.parent('tr');
            this.model.setRight(newRight);
            originalElement.replaceWith(this.render(row));
        };

        var updateAndReplaceWithUndo = function(newRight){
            var originalRight = this.model.right;
            var originalElement = $(this.el);
            var mode = originalElement.data('mode');
            var row = originalElement.parent('tr');
            var groupId = parseInt(row.data('group-id'));
            var ruleId = parseInt(row.data('rule-id'));
            var bitmask = parseInt(this.model.bitmask, 10);
            this.updateAndReplace(newRight);
            Instance.Undo.model.addHistory({
                action: 'right-change',
                "groupId": groupId,
                "ruleId": ruleId,
                "bitmask": bitmask,
                right: mode,
                original: originalRight,
                current: newRight
            });
        };

        var rightDropdown = function (el) {
            var states = [{
                name: lmsg('infocapture.admin.field_rights.permission_default'),
                right: 0,
                badgeName: 'field-default',
                current: this.model.right === 0 ? true : false
            }, {
                name: lmsg('infocapture.admin.field_rights.permission_allow'),
                right: 1,
                badgeName: 'field-success',
                current: this.model.right === 1 ? true : false
            }, {
                name: lmsg('infocapture.admin.field_rights.permission_deny'),
                right: 2,
                badgeName: 'field-important',
                current: this.model.right === 2 ? true : false
            }];
            var menu = _.template($('#right-select-tmpl').html())({
                states: states
            });
            $(el).after(menu);
            $('#state-select').parent().find('a').off('click').on('click', {
                view: this
            }, rightSelect);
        };

        return {
            rightToggle: rightToggle,

            setModel: setModel,

            render: render,

            updateAndReplace: updateAndReplace,

            updateAndReplaceWithUndo: updateAndReplaceWithUndo
        };
    })();

    return Right;
});