define(['./field.js'], function (Field) {

    /**
     * Fields controller class
     * @class Fields
     * @constructor
     * @property {Object} collection - Fields.Collection
     * @property {Object} view - Fields.View
     */
    var Fields = function () {
        /**
         * Fields.Collection object
         * @type {Object}
         */
        this.collection = new Fields.Collection();

        /**
         * Fields.View object
         * @type {Object}
         */
        this.view = new Fields.View();

        this.collection.setView(this.view);
        this.view.setCollection(this.collection);
    };

    /**
     * Fields collection
     * @class Fields.Collection
     * @constructor
     * @property {Object} collection - Fields
     * @property {Array} - models - An array of Field objects
     */
    Fields.Collection = function () {
        /**
         * Fields class
         * @type {Object}
         */
        this.view = null;

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

        this.init();
    };

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

        /**
         * Initalise object
         * @private
         * @memberOf Fields.Collection
         */
        var init = function () {
            setData.call(this, window.fields);
        };

        /**
         * Add models to the collection
         * @private
         * @memberOf Fields.Collection
         * @param {Object} data - JSON data for all fields
         */
        var setData = function (data) {
            var self = this;
            _.each(data, function (field) {
                var instance = new Field(field);
                self.fields.push(instance);
            });
        };

        /**
         * Get collection of models
         * @private
         * @memberOf Fields.Collection
         * @returns {Array}
         */
        var getData = function () {
            if (_.isArray(this.fields)) {
                return this.fields;
            } else {
                return [];
            }
        };

        /**
         * Fetch a field from the Fields collection by id
         * @private
         * @memberOf Fields.Collection
         * @returns {Object}
         * @param fieldSymName
         */
        var getByFieldSymName = function (fieldSymName) {
            var field = _.find(this.fields, function (field) {
                return field.model.symName === fieldSymName;
            });
            return field;
        };

        /**
         * Fetch the index from the Fields collection
         * @private
         * @memberOf Fields.Collection
         * @returns {number}
         * @param fieldSymName
         */
        var getIndexByFieldSymName = function (fieldSymName) {
            var index = _.findIndex(this.fields, function (field) {
                return field.model.symName === fieldSymName;
            });
            return parseInt(index, 10);
        };

        /**
         * Call Field modal view
         * @private
         * @memberOf Fields.Collection
         * @param {Object} event - jQuery event
         */
        var addRule = function (event) {
            event.preventDefault();
            var fieldSymName = $('#add-rule-select').val();
            if (!_.isUndefined(fieldSymName) && fieldSymName !== '') {
                var field = Instance.Fields.collection.getByFieldSymName(fieldSymName);
                field.view.addRuleModal();
            }
        };

        return {
            setView: setView,

            /**
             * @public
             * @memberOf Fields.Collection
             */
            init: init,

            /**
             * Get collection of models
             * @public
             * @memberOf Fields.Collection
             * @returns {Array}
             */
            models: getData,

            /**
             * Fetch a field from the Fields collection by id
             * @pubic
             * @memberOf Fields.Collection
             * @param {String} symName - field symbolic name
             * @returns {Object}
             */
            getByFieldSymName: getByFieldSymName,

            /**
             * Fetch the index from the Fields collection
             * @public
             * @memberOf Fields.Collection
             * @param {String} symName - field symbolic name
             * @returns {number}
             */
            getIndexByFieldSymName: getIndexByFieldSymName,

            /**
             * Call Field modal view
             * @public
             * @memberOf Fields.Collection
             * @param {Object} event - jQuery event
             */
            addRule: addRule
        };
    })();

    /**
     * Fields.View class
     * @class
     * @constructor
     */
    Fields.View = function () {
        /**
         * Fields object
         * @type {Object}
         * @memberOf Fields.View
         */
        this.collection = null;

        /**
         * DOM element for the fields list
         * @type {Object}
         * @memberOf Fields.View
         */
        this.el = null;

        this.init();
    };

    Fields.View.prototype = (function () {
        var setCollection = function (collection) {
            this.collection = collection;
        };

        /**
         * Initalise object
         * @private
         * @memberOf Fields.View
         */
        var init = function () {
            setElement.call(this);
        };

        /**
         * Set the DOM element for the fields list
         * @private
         * @memberOf Fields.View
         */
        var setElement = function () {
            this.el = $('#fields-list');
        };

        /**
         * Get the DOM element for the fields list
         * @private
         * @memberOf Fields.View
         */
        var getElement = function () {
            return this.el;
        };

        /**
         * Bind events to DOM objects
         * @private
         * @memberOf Fields.View
         */
        var bindElements = function () {
            $('#newGroup').on('click', this.addRule);
        };

        /**
         * Render fields list
         * @private
         * @memberOf Fields.View
         * @param {Object} data - Fields.Collection
         */
        var render = function (data) {
            var self = this;
            this.el.empty();
            $('#add-rule-select').empty().append($('<option>Select field</option>'));
            if (_.isUndefined(data)) {
                _.each(self.collection.fields, function (field) {
                    if (field.model.rules.collection.rules.length > 0) {
                        field.view.render();
                    } else {
                        field.view.addToSelect();
                    }
                });
            } else {
                _.each(data, function (field) {
                    if (field.model.rules.collection.rules.length > 0) {
                        field.view.render();
                    } else {
                        field.view.addToSelect();
                    }
                });
            }
            bindElements.call(this);
        };

        return {
            setCollection: setCollection,

            /**
             * Initalise object
             * @pubic
             * @memberOf Fields.View
             */
            init: init,

            /**
             * Get the DOM element for the fields list
             * @pubic
             * @memberOf Fields.View
             */
            el: getElement,

            /**
             * Render fields list
             * @public
             * @memberOf Fields.View
             * @param {Object} data - Fields.Collection
             */
            render: render
        };
    })();

    return Fields;
});
