define(['./group.js', 'jquery'], function (Group, $) {

    /**
     * A collection of groups
     * @class
     * @constructor
     * @property {Object} groups - an array of group instances
     */
    var Groups = function() {"use strict";
        this.collection = new Groups.Collection();
        this.view = new Groups.View();
        this.collection.setView(this.view);
        this.view.setCollection(this.collection);
    };

    Groups.Collection = function() {"use strict";
        this.view = null;

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

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

        /**
         * Add Group object to groups array
         * @private
         * @memberOf Groups
         * @param {Object} data - JSON data for all groups
         * @returns {Object} Groups.Collection
         */
        var setData = function(data) {
            var self = this;
            _.each(data, function(group) {
                var instance = new Group(group);
                self.groups.push(instance);
            });
            return self;
        };

        /**
         * Get an array of Group objects
         * @private
         * @returns {Array} Array of Group objects
         */
        var getData = function() {
            if (_.isArray(this.groups)) {
                return this.groups;
            } else {
                return [];
            }
        };

        /**
         * Add a group to the collection
         * @private
         * @memberOf Groups
         * @param {String} groupName - name of the group
         */
        var addGroup = function(groupName) {
            var rand = _.random(1, 1001);
            while (this.getIndexByGroupId(rand) !== -1) {
                rand = _.random(1, 1001);
            }
            var group = new Group({
                id : rand,
                name : groupName,
                fields : {},
                dropdown : {}
            });
            Instance.Groups.collection.groups.push(group);
            //Instance.Groups.collection.groups.splice(_.sortedIndex(Instance.Groups.collection.groups, group.model, 'id'), 0, group);
            Instance.Undo.model.addHistory({
                action : 'add',
                id : rand,
                name : groupName
            });
            $('#addGroup').modal('hide');
            Instance.Groups.view.render();
        };

        /**
         * Filter Groups collection by name, label or sym_name
         * @private
         * @memberOf Groups
         */
        var filter = function() {
            var needle = $('#filterGroups').val().toLocaleLowerCase();
            if (_.isString(needle) && needle !== '') {
                var groups = Instance.Groups.collection.groups;
                var result = _.filter(groups, function(group) {
                    var match = false;
                    if (_.isString(group.model.name) && group.model.name !== '') {
                        var groupName = group.model.name.toLocaleLowerCase();
                        if (groupName.indexOf(needle) !== -1) {
                            match = true;
                        }
                        if (_.isArray(group.model.fields)) {
                            _.each(group.model.fields, function(field) {
                                if (_.isString(field.fieldSymName)) {
                                    var symName = field.model.fieldSymName.toLocaleLowerCase();
                                    if (symName.indexOf(needle) !== -1) {
                                        match = true;
                                    }
                                }
                                if (_.isString(field.model.label)) {
                                    var label = field.model.label.toLocaleLowerCase();
                                    if (label.indexOf(needle) !== -1) {
                                        match = true;
                                    }
                                }
                            });
                        }
                    }
                    return match;
                });
                return result;
            }
        };

        /**
         * Fetch a group from the Groups collection by id
         * @private
         * @memberOf Groups
         * @param {number} groupId	- group id
         * @returns {Object}
         */
        var getByGroupId = function(groupId) {
            var group = _.find(Instance.Groups.collection.groups, function(group) {
                return parseInt(group.model.id, 10) === parseInt(groupId, 10);
            });
            return group;
        };

        /**
         * Fetch the index from the Groups collection
         * @private
         * @memberOf Groups
         * @param {number} groupId	- group id
         * @returns {number}
         */
        var getIndexByGroupId = function(groupId) {
            var index = _.findIndex(Instance.Groups.collection.groups, function(group) {
                return parseInt(group.model.id, 10) === parseInt(groupId, 10);
            });
            return parseInt(index, 10);
        };

        /**
         * Called from xajax when a group is inserted into db
         * @private
         * @memberOf Groups
         * @param {number} previous - previous group id
         * @param {number} current - from db
         */
        var updateGroupId = function(previous, current) {
            var group = this.getByGroupId(previous);
            group.model.id = parseInt(current, 10);
            Instance.Groups.view.render();
        };

        return {
            setView : setView,

            /**
             * Groups initialisation
             * @public
             * @memberOf Groups.Collection
             */
            setData : setData,

            /**
             * @public
             * @memberOf Groups.Collection
             */
            groups : getData,

            /**
             * @public
             * @memberOf Groups.Collection
             */
            addGroup : addGroup,

            /**
             * @public
             * @memberOf Groups.Collection
             */
            filter : filter,

            /**
             * @public
             * @memberOf Groups.Collection
             */
            getByGroupId : getByGroupId,

            /**
             * @public
             * @memberOf Groups.Collection
             */
            getIndexByGroupId : getIndexByGroupId,

            /**
             * @public
             * @memberOf Groups.Collection
             */
            updateGroupId : updateGroupId

        };
    })();

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

    Groups.View.prototype = (function() {"use strict";
        var setCollection = function(collection) {
            this.collection = collection;
        };

        var init = function() {
            setElement.call(this);
        };

        var setElement = function() {
            this.el = $('#group-list');
        };

        var getElement = function() {
            return this.el;
        };

        /**
         * Render groups collection
         * @private
         * @memberOf Groups
         * @param {object|undefined} data - optional data be rendered instead of groups collection
         */
        var render = function(data) {
            this.el.empty();
            if (_.isUndefined(data)) {
                var needle = $('#filterGroups').val().toLocaleLowerCase();
                if (_.isString(needle) && needle !== '' && $('#filterGroups').attr('placeholder') !== lmsg('infocapture.admin.field_groups.filter_input')) {
                    data = applyRows(this.collection.filter());
                } else {
                    data = applyRows(this.collection.groups);
                }
            }
            data = applyRows(data);
            _.each(data, function(group) {
                group.view.render();
            });
            bindElements.call(this);
        };

        var filter = function(event) {
            if ( typeof event !== 'undefined') {
                event.preventDefault();
            }
            Instance.Groups.view.render(Instance.Groups.collection.filter());
        };

        /**
         * Add a bool value to newRow property - 2 columns
         * @private
         * @memberOf Groups
         * @param {Object} data - array of Group instances
         * @returns {Object}
         */
        var applyRows = function(data) {
            var i = 0;
            _.each(data, function(group) {
                i++;
                if (i % 2 === 1) {
                    group.view.newRow = true;
                } else {
                    group.view.newRow = false;
                }
            });
            return data;
        };

        /**
         *
         * @private
         * @memberOf Groups
         */
        var bindElements = function() {
            $('#filterGroups').keyup(_.debounce(filter, 1000));
            $('#resetFilterGroups').on('click', clearFilter);
            $('#add-group').validate({
                submitHandler : function(form) {
                    var groupName = $('#newGroupName');
                    Instance.Groups.collection.addGroup(groupName.val());
                    cla.showMessage(lmsg('infocapture.admin.field_groups.message_title'), lmsg('infocapture.admin.field_groups.group_added', _.escape(groupName.val())), 0);
                    groupName.val('');
                    $('#add-group').validate().resetForm();
                },
                rules : {
                    'infocapture:admin:field_groups:add_group_input' : {
                        maxlength : 50,
                        required : true,
                        unique : true,
                        not_placeholder : 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() {
                    $('#add-group').find('.control-group').removeClass('error');
                    $('#newGroupName').tooltip('dispose');
                    $('#newGroupName').focus();
                },
                messages : {
                    'infocapture:admin:field_groups:add_group_input' : {
                        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'),
                        not_placeholder : lmsg('infocapture.admin.field_groups.error_empty_name')
                    }
                }
            });
        };

        /**
         * Clear the filter value
         * @private
         * @memberOf Groups.View
         */
        var clearFilter = function() {
            $('#filterGroups').val('');
            Instance.Groups.view.render();
        };

        return {
            setCollection : setCollection,

            /**
             * @public
             * @memberOf Groups.View
             */
            init : init,

            /**
             * @public
             * @memberOf Groups.View
             */
            el : getElement,

            /**
             * @public
             * @memberOf Groups.View
             */
            clearFilter : clearFilter,

            /**
             * @public
             * @memberOf Groups.View
             */
            render : render
        };
    })();

    return Groups;
});
