define(['./fields.js'], function (Fields) {
    /**
     * Group model
     * @constructor
     * @param {Object} group - JSON data for group
     * @property {Object} model - Group.Model
     * @property {Object} view - Group.View
     */
    var Group = function(group) {"use strict";
        this.model = new Group.Model(group);
        this.view = new Group.View();
        this.model.setView(this.view);
        this.view.setModel(this.model);
    };

    /**
     * Group model
     * @constructor
     * @param {Object} group - JSON data for group
     * @property {number} id - group id
     * @property {Array} fields - array of fields
     * @property {String} name - group name
     * @property {bool} newRow - display on new row
     */
    Group.Model = function(group) {"use strict";
        this.view = null;
        /**
         * Group id
         * @private
         * @type {Number}
         */
        this.id = null;

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

        /**
         * Array of field objects
         * @private
         * @type {Array}
         */
        this.fields = [];

        this.init(group);
    };

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

        /**
         * Set model data
         * @private
         * @memberOf ICFieldGroups.Group
         * @param {Object} data - JSON object
         */
        var setData = function(data) {
            setId.call(this, data.id);
            setName.call(this, data.name);
            setFields.call(this, data.contents);
        };

        /**
         * Accept edit event
         * @public
         * @memberOf ICFieldGroups.Group
         */
        var acceptEdit = function(name) {
            var group = Instance.Groups.collection.getByGroupId(this.id);
            var originalName = group.model.name;
            group.model.name = name;
            Instance.Undo.model.addHistory({
                action : 'edit',
                id : this.id,
                oldName : originalName,
                newName : group.model.name
            });
            cla.showMessage(lmsg('infocapture.admin.field_groups.message_title'), lmsg('infocapture.admin.field_groups.group_edited'), 0);
            this.view.el.find('.acceptEditGroupName').tooltip('hide');
            Instance.Groups.view.render();
        };

        /**
         * Delete a group from the collection (fields within the group moved to unassigned)
         * @public
         * @memberOf ICFieldGroups.Group
         */
        var deleteGroup = function(event) {
            var button = $(event.currentTarget);
            var message, isError = 0;
            var groupId = this.id;
            var groupIndex = Instance.Groups.collection.getIndexByGroupId(groupId);
            if (groupIndex === -1) {
                isError = 1;
                message = lmsg('infocapture.admin.field_groups.group_not_found');
            } else {
                var group = Instance.Groups.collection.getByGroupId(groupId);
                var undo = [];
                var groupName = group.model.name;
                message = lmsg('infocapture.admin.field_groups.group_deleted', _.escape(groupName));
                if (group.model.fields.collection.fields.length > 0) {
                    var toDelete = [];
                    _.each(group.model.fields.collection.fields, function(data) {
                        undo.push({
                            position : data.model.position,
                            symName : data.model.symName
                        });
                        Instance.Groups.collection.groups[0].model.fields.collection.fields.push(data);
                        toDelete.push(_.findIndex(group.model.fields.collection.fields, function(field) {
                            return field.model.symName === data.model.symName;
                        }));
                    });
                    _.each(toDelete, function(index) {
                        group.model.fields.collection.fields.splice(index, 1);
                    });

                    cla.showMessage(lmsg('infocapture.admin.field_groups.message_title'), lmsg('infocapture.admin.field_groups.group_field_move', _.escape(Instance.Groups.collection.groups[groupIndex].model.name), _.escape(Instance.Groups.collection.groups[0].model.name)), 0);
                }
                Instance.Groups.collection.groups.splice(groupIndex, 1);
                Instance.Undo.model.addHistory({
                    action : 'delete',
                    id : groupId,
                    index : groupIndex,
                    name : groupName,
                    move : {
                        action : 'move',
                        sourceGroup : groupId,
                        targetGroup : 0,
                        fields : undo
                    }
                });
                button.tooltip('hide');
            }
            Instance.Groups.view.render();
            cla.showMessage(lmsg('infocapture.admin.field_groups.message_title'), message, isError);
        };

        /**
         * Move fields from one group to another
         * @public
         * @memberOf ICFieldGroups.Group
         */
        var moveFields = function() {
            var undo = [];
            var button = $(this);
            var fieldList = button.parent().siblings('.field-list');
            var targetGroupId = parseInt(button.siblings('select').val(), 10);
            var targetGroup = Instance.Groups.collection.getByGroupId(targetGroupId);
            var sourceGroupId = parseInt(fieldList.data('group-id'), 10);
            var sourceGroup = Instance.Groups.collection.getByGroupId(sourceGroupId);
            _.each(fieldList.find('input[type=checkbox]:checked'), function(data) {
                var symName = $(data).val();
                var field = sourceGroup.model.fields.collection.getBySymName(symName);
                targetGroup.model.fields.collection.fields.push(field);
                undo.push({
                    position : field.model.position,
                    symName : symName
                });
                var fieldIndex = sourceGroup.model.fields.collection.getIndexBySymName(symName);
                sourceGroup.model.fields.collection.fields.splice(fieldIndex, 1);
            });
            Instance.Undo.model.addHistory({
                action : 'move',
                sourceGroup : sourceGroupId,
                targetGroup : targetGroupId,
                fields : undo
            });
            Instance.Groups.view.render();
            cla.showMessage(lmsg('infocapture.admin.field_groups.message_title'), lmsg('infocapture.admin.field_groups.group_field_move', _.escape(sourceGroup.model.name), _.escape(targetGroup.model.name)), 0);
        };

        /**
         * Set group id
         * @private
         * @memberOf ICFieldGroups.Groups.Model
         */
        var setId = function(id) {
            this.id = parseInt(id, 10);
        };

        /**
         * Get group id
         * @private
         * @memberOf ICFieldGroups.Group
         * @returns {Number}
         */
        var getId = function() {
            if (_.isNumber(this.id)) {
                return parseInt(this.id, 10);
            } else {
                return NaN;
            }
        };

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

        /**
         * Get group name
         * @private
         * @memberOf ICFieldGroups.Group
         * @returns {String}
         */
        var getName = function() {
            if (_.isString(this.name)) {
                return this.name;
            } else {
                return '';
            }
        };

        var setFields = function(fields) {
            this.fields = new Fields(fields, getId);
        };

        /**
         * Get group fields
         * @private
         * @memberOf ICFieldGroups.Group
         * @returns {Array}
         */
        var getFields = function() {
            if (_.isArray(this.fields)) {
                return this.fields;
            } else {
                return [];
            }
        };

        /**
         * Check if group should create a new row
         * @private
         * @memberOf ICFieldGroups.Group
         * @returns {Bool}
         */
        var isNewRow = function() {
            return this.newRow;
        };

        return {
            setView : setView,

            init : setData,

            /**
             * Get group id
             * @public
             * @memberOf ICFieldGroups.Group
             * @returns {Number}
             */
            id : getId,

            /**
             * Get group name
             * @public
             * @memberOf ICFieldGroups.Group
             * @returns {String}
             */
            name : getName,

            /**
             * Get group fields
             * @public
             * @memberOf ICFieldGroups.Group
             * @returns {Array}
             */
            fields : getFields,

            /**
             * Check if group should create a new row
             * @public
             * @memberOf ICFieldGroups.Group
             * @returns {Bool}
             */
            newRow : isNewRow,

            acceptEdit : acceptEdit,

            deleteGroup : deleteGroup,

            moveFields : moveFields
        };
    })();

    Group.View = function() {"use strict";
        this.model = null;
        this.el = null;
    };

    Group.View.prototype = (function() {"use strict";
        var setModel = function(model) {
            this.model = model;
        };
        /**
         * Render a group
         * @public
         * @memberOf ICFieldGroups.Group
         */
        var render = function() {
            if (this.newRow === true) {
                $('#group-list').append($('<div class="row"></div>').html(_.template($('#group-tmpl').html())(this.model)));
            } else {
                $('#group-list').children('div[class="row"]').last().append(_.template($('#group-tmpl').html())(this.model));
            }
            setElement.call(this);
            this.model.fields.view.render(this.el);
            this.el.find('select[name="move_to"]').html(createGroupDropdown(this.model.id));
            bindElements.call(this);
        };

        /**
         * Get DOM element
         * @private
         * @memberOf ICFieldGroups.Group
         * @returns {Object}
         */
        var getElement = function() {
            return this.el;
        };

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

        /**
         * Bind events to elements
         * @private
         * @memberOf ICFieldGroups.Group
         */
        var bindElements = function() {
            var self = this;
            this.el.find('input[name="select_all"]').on('change', selectAllFields);
            this.el.find('.editGroupName').on('click', {
                group : this
            }, editName);
            this.el.find('select[name="move_to"]').on('change', {
                group : this
            }, toggleMoveButton);
            this.el.find('input[type="checkbox"]').on('change', function() {
                self.el.find('select[name="move_to"]').trigger('change');
            });
            this.el.find('.js-move-fields').on('click', this.model.moveFields);
            this.el.find('.deleteGroup').on('click', function(event) {
                if (confirm('Are you sure?')) {
                    self.model.deleteGroup(event);
                } else {
                    return false;
                }
            });
        };

        /**
         * Create select list of groups excluding the current group
         * @public
         * @memberOf ICFieldGroups.Group
         * @param {number} exclude - id for the group
         * @returns {String}
         */
        var createGroupDropdown = function(exclude) {
            var html = _.template($('#group-dropdown-tmpl').html())({
                id : null,
                name : lmsg('infocapture.admin.field_groups.move_fields_select')
            });
            _.each(Instance.Groups.collection.groups, function(group) {
                if (exclude !== group.model.id) {
                    html += _.template($('#group-dropdown-tmpl').html())({
                        id : group.model.id,
                        name : group.model.name
                    });
                }
            });
            return html;
        };

        /**
         * When checkbox is checked, check all fields in the group
         * @public
         * @memberOf ICFieldGroups.Group
         */
        var selectAllFields = function() {
            var checkbox = $(this);
            var checked = checkbox.prop('checked');
            checkbox.parentsUntil('.js-group-block').find('.js-field-checkbox').prop('checked', checked);
        };

        /**
         * Toggle the move button if a field is selected and a group is selected
         * @public
         * @memberOf ICFieldGroups.Group
         */
        var toggleMoveButton = function(event) {
            var select = $(this);
            var group = event.data.group;
            if (select.val() !== '' && group.el.find('input[type=checkbox]:checked').length > 0) {
                select.siblings('input').prop('disabled', false);
            } else {
                select.siblings('input').prop('disabled', true);
            }
        };

        /**
         * Change the group name
         * @public
         * @memberOf ICFieldGroups.Group
         * @param {Object} event - trigger event contains the group object
         */
        var editName = function(event) {

            console.log("wha??")


            var button = $(this);
            var parent = button.parents('.card-body');
            var name = parent.find('.js-group-name-text').text();
            var group = event.data.group;
            // button.hide();
            parent.find('.js-group-name').hide().end().find('.js-edit-group').show().end().find('input[name="edit_group"]').val(name).focus();
            group.el.find('form').validate({
                submitHandler : function(form) {
                    var groupName = $(form).find('input[name=edit_group]');
                    group.model.acceptEdit(groupName.val());
                    groupName.val('');
                },
                rules : {
                    'edit_group' : {
                        maxlength : 50,
                        required : true,
                        unique : true
                    }
                },
                errorPlacement : function(error, element) {
                    $(element).attr('title', $(error).text()).data('original-title', $(error).text()).tooltip('show');
                    $(element).parents('.control-group').addClass('error');
                },
                success : function(label, element) {
                    group.el.find('form').find('.control-group').removeClass('error');
                    group.el.find('form').find('.control-group').find('input').removeAttr('title').tooltip('hide');
                    $('#newGroupName').focus();
                },
                messages : {
                    'edit_group' : {
                        maxlength : lmsg('infocapture.admin.field_groups.error_name_length'),
                        required : lmsg('infocapture.admin.field_groups.error_empty_name'),
                        unique : lmsg('infocapture.admin.field_groups.error_unique_name')
                    }
                }
            });
            group.el.find('.acceptEditGroupName').on('click', function() {
                group.el.find('form').submit();
            });
            group.el.find('.cancelEditGroupName').on('click', group.cancelEdit);
        };

        /**
         * Cancel edit event
         * @public
         * @memberOf ICFieldGroups.Group
         */
        var cancelEdit = function() {
            var button = $(this);
            var parent = button.parents('.card-body');
            parent.find('.js-group-name').show().end().find('.js-edit-group').hide();
        };

        return {
            setModel : setModel,
            /**
             * Get DOM element
             * @public
             * @memberOf ICFieldGroups.Group
             * @returns {Object}
             */
            el : getElement,

            render : render,

            selectAllFields : selectAllFields,

            toggleMoveButton : toggleMoveButton,

            editName : editName,

            cancelEdit : cancelEdit
        };
    })();

    return Group;
});
