define(['./fields.js', './rights.js'], function (Fields, Rights) {

    /**
     * Group controller
     * @class
     * @constructor
     * @param {Object} group - JSON data for group
     * @property {Object} el - container element for the group
     */
    var Group = function () {
        'use strict';
        this.model = new Group.Model();
        this.view = new Group.View();
        this.model.setView(this.view);
        this.view.setModel(this.model);
    };

    /**
     * @constructor
     * @param {Object} controller
     * @param {Object} group - JSON data for group
     * @property {Number} id - group id
     * @property {String} name - group name
     * @property {Object} fields - fields in group
     * @property {Object} rights - field rights in group
     * @property {Object} roles - roles
     * @property {Object} el - container element for the group
     */
    Group.Model = function () {
        'use strict';
        this.view = null;

        /**
         * @type {Number}
         */
        this.id = null;

        /**
         * @type {String}
         */
        this.name = null;

        /**
         * @type {Array}
         */
        this.fields = [];

        /**
         * @type {Array}
         */
        this.rights = [];

        /**
         * @type {Array}
         */
        this.roles = [];
    };

    Group.Model.prototype = (function () {
        'use strict';

        var setView = function (view) {
            this.view = view;
        };

        /**
         * Set model data
         * @private
         * @memberOf Group
         * @param {Object} data - JSON object
         * @returns {Object} Group
         */
        var setData = function (data) {
            setId.call(this, data.id);
            setName.call(this, data.name);
            setFields.call(this, data.fields);
            setRights.call(this, data.rights);
            setRoles.call(this, data.roles);
            return this;
        };

        /**
         * Create an array of groups excluding a group id
         * @private
         * @memberOf Group
         * @returns {Object} Group
         */
        var createGroupsDropdown = function () {
            var self = this;
            var dropdown = [];
            _.each(Instance.Groups.collection.groups, function (group) {
                if (self.id !== group.model.id) {
                    dropdown.push({
                        id: group.model.id,
                        name: group.model.name
                    });
                }
            });
            this.dropdown = dropdown;
        };

        /**
         * Create html for select of groups except the current group
         * @private
         * @memberOf Group
         * @param {Number|Undefined} current - current value if editing
         * @returns {Object} Group
         */
        var createConditionsDropdown = function (current) {
            var self = this;
            var tmpl = '';
            var filtered = _.reject(Instance.Rules.collection.rules, function (rule) {
                var rejected = false;
                _.each(self.rights, function (right) {
                    if (rejected === false && right.collection.ruleId === rule.model.ruleId && right.collection.ruleId !== current) {
                        rejected = true;
                    }
                });
                return rejected;
            });
            if (filtered.length === 0) {
                if (!_.isUndefined(current)) {
                    $("label[for=add_rule_id]").hide();
                    $("#field_condition_empty_error").show();
                    $('select[name=edit_rule_id]').parent().hide();
                    $('#edit-rule').addClass('disabled');
                } else {
                    $("#field_condition_sets_empty_error").show();
                    $("label[for=add_rule_id]").hide();
                    $('select[name=add_rule_id]').parent().hide();
                    $('#add-rule').addClass('disabled');
                }
            } else {
                if (!_.isUndefined(current)) {
                    $("#field_condition_sets_empty_error").hide();
                    $('select[name=edit_rule_id]').parent().show();
                    $('#edit-rule').removeClass('disabled');
                } else {
                    $("#field_condition_sets_empty_error").hide();
                    $('select[name=add_rule_id]').parent().show();
                    $('#add-rule').removeClass('disabled');
                }
                _.each(filtered, function (rule) {
                    tmpl += _.template($('#rule-tmpl').html())(rule.model);
                });
            }
            if (!_.isUndefined(current)) {
                $('select[name=edit_rule_id]').html(tmpl);
                $('select[name=edit_rule_id]').val(current);
            } else {
                $('select[name=add_rule_id]').html(tmpl);
            }
            return self;
        };

        /**
         * Replace rights with rights from selected groups
         * @private
         * @memberOf Group
         * @returns {Object} Group.Model
         */
        var copy = function (event) {
            event.preventDefault();
            var button = $(this);
            var input = button.siblings('select[name=groupName]');
            var sourceGroupId = parseInt(input.val(), 10);
            var sourceGroup = Instance.Groups.collection.getByGroupId(sourceGroupId);
            var targetGroupId = button.data('group-id');
            var targetGroup = Instance.Groups.collection.getByGroupId(targetGroupId);
            var originalRights = targetGroup.model.rights;
            targetGroup.model.rights = [];
            _.each(sourceGroup.model.rights, function (rights) {
                rights.collection.groupId = targetGroupId;
                targetGroup.model.rights.push(rights);
            });
            Instance.Undo.model.addHistory({
                action: 'group-copy',
                sourceGroupId: sourceGroupId,
                targetGroupId: targetGroupId,
                sourceRights: sourceGroup.model.rights,
                targetRights: originalRights
            });
            Instance.Groups.view.render();
            window.location.hash = 'group-' + targetGroupId;
        };

        var setId = function (id) {
            this.id = parseInt(id, 10);
        };

        /**
         * @private
         * @memberOf Group
         */
        var getId = function () {
            return parseInt(this.id, 10);
        };

        var setName = function (name) {
            this.name = name;
        };

        /**
         * @private
         * @memberOf Group
         */
        var getName = function () {
            return this.name;
        };

        var setFields = function (fields) {
            this.fields = new Fields();
            this.fields.collection.setData(fields, this.id);
        };

        /**
         * @private
         * @memberOf Group
         */
        var getFields = function () {
            return this.fields;
        };

        var setRights = function (rights) {
            var self = this;
            rights = _.sortBy(rights, function (right) {
                return right.position;
            });
            _.each(rights, function (rights) {
                var instance = new Rights();
                instance.collection.setData(rights);
                self.rights.push(instance);
            });
        };

        /**
         * @private
         * @memberOf Group
         */
        var getRights = function () {
            return this.rights;
        };

        var setRoles = function (roles) {
            this.roles = Instance.Roles;
        };

        /**
         * @private
         * @memberOf Group
         */
        var getRoles = function () {
            return this.roles;
        };

        return {
            setView: setView,

            /**
             * @public
             * @memberOf Group
             */
            setData: setData,

            /**
             * @public
             * @memberOf Group
             */
            id: getId,

            /**
             * @public
             * @memberOf Group
             */
            name: getName,

            /**
             * @public
             * @memberOf Group
             */
            fields: getFields,

            /**
             * @public
             * @memberOf Group
             */
            rights: getRights,

            /**
             * @public
             * @memberOf Group
             */
            roles: getRoles,

            createConditionsDropdown: createConditionsDropdown,

            createGroupsDropdown: createGroupsDropdown,

            copy: copy
        };
    })();

    Group.View = function () {
        'use strict';
        this.model = null;

        /**
         * @type {Object}
         */
        this.el = null;
    };

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

        /**
         * Render group
         * @private
         * @memberOf Group
         * @returns {Object} Group
         */
        var render = function () {
            var self = this;
            this.model.createGroupsDropdown.call(this.model);
            $('#group-list').append(_.template($('#group-tmpl').html())(this.model));
            setElement.call(this);
            this.model.fields.view.render(getElement.call(this));
            this.model.roles.view.render(getElement.call(this));
            _.each(this.model.rights, function (collection) {
                collection.view.render(getElement.call(self));
            });
            bindElements.call(this);
        };

        /**
         * Set group DOM element
         * @private
         * @memberOF Group
         */
        var setElement = function () {
            this.el = $('#group-list').children('div[data-group-id=' + this.model.id + ']').eq(0);
        };

        /**
         * @private
         * @memberOf Group
         */
        var getElement = function () {
            return this.el;
        };

        var bindElements = function () {
            this.el.find('.accordion-toggle').on('click', toggleAccordion);
            this.el.find('a[name="new_rule_link"]').on('click', Instance.Rules.view.addRule);
            this.el.find('a[name="edit_rule"]').on('click', Instance.Rules.view.editRule);
            this.el.find('a[name="del_link"]').on('click', Instance.Rules.collection.deleteRule);
            this.el.find('button[name="copy_perms_btn"]').on('click', this.model.copy);
        };
        /**
         * Open/Close fields list
         * @private
         * @memberOf Group
         * @returns {Object} Group
         */
        var toggleAccordion = function () {
            $(this).find('span[class^="cla-icon-accordion"]').toggleClass('cla-icon-accordion-open');
            //
            $(this).find('span.glyphicons-collapse').toggleClass('glyphicons-collapse-top', 'glyphicons-collapse');
        };

        return {
            setModel: setModel,
            /**
             * @public
             * @memberOf Group
             */
            el: getElement,

            /**
             * @public
             * @memberOf Group
             */
            render: render
        };
    })();

    return Group;
});
