YUI.add('aui-form-builder-field-list', function (A, NAME) {

/**
 * The Form Builder Field List Component
 *
 * @module aui-form-builder-field-list
 */

var CSS_FIELD_LIST = A.getClassName('form', 'builder', 'field', 'list'),
    CSS_FIELD_LIST_ADD_BUTTON =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button'),
    CSS_FIELD_LIST_ADD_BUTTON_ICON =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button', 'icon'),
    CSS_FIELD_LIST_ADD_BUTTON_LABEL =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button', 'label'),
    CSS_FIELD_LIST_ADD_BUTTON_LARGE =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button', 'large'),
    CSS_FIELD_LIST_ADD_BUTTON_PLUS_ICON =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button', 'plus', 'icon'),
    CSS_FIELD_LIST_ADD_BUTTON_VISIBLE =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'button', 'visible'),
    CSS_FIELD_LIST_ADD_CONTAINER =
        A.getClassName('form', 'builder', 'field', 'list', 'add', 'container'),
    CSS_FIELD_LIST_CONTAINER =
        A.getClassName('form', 'builder', 'field', 'list', 'container'),
    CSS_FIELD_LIST_EMPTY = A.getClassName('form', 'builder', 'field', 'list', 'empty'),
    CSS_FIELD_MOVE_TARGET =
        A.getClassName('form', 'builder', 'field', 'move', 'target'),
    CSS_FIELD_MOVE_TARGET_LABEL =
        A.getClassName('form', 'builder', 'field', 'move', 'target', 'label'),
    CSS_LIST_MOVE_TARGET =
        A.getClassName('form', 'builder', 'list', 'move', 'target');

/**
 * A base class for `A.FormBuilderFieldList`.
 *
 * @class A.FormBuilderFieldList
 * @extends A.Base
 * @param {Object} config Object literal specifying widget configuration
 *     properties.
 * @constructor
 */
A.FormBuilderFieldList  = A.Base.create('form-builder-field-list', A.Base, [], {
    TPL_ADD_FIELD: '<div class="' + CSS_FIELD_LIST_ADD_CONTAINER + '">' +
        '<a class="btn ' + CSS_FIELD_LIST_ADD_BUTTON + '" href="javascript:;">' +
        '<span class="' + CSS_FIELD_LIST_ADD_BUTTON_ICON + ' ' + CSS_FIELD_LIST_ADD_BUTTON_PLUS_ICON + '">+</span>' +
        '<label class="' + CSS_FIELD_LIST_ADD_BUTTON_LABEL + '">' +
        '{addField}' +
        '</label>' +
        '</a></div>',
    TPL_FIELD_LIST: '<div class="' + CSS_FIELD_LIST + '">' +
        '<div class="' + CSS_FIELD_LIST_CONTAINER + '"></div>' +
        '</div>',
    TPL_FIELD_MOVE_TARGET: '<button type="button" class="' + CSS_FIELD_MOVE_TARGET + ' ' + CSS_LIST_MOVE_TARGET +
        ' layout-builder-move-target layout-builder-move-col-target">' +
        '<label class="' + CSS_FIELD_MOVE_TARGET_LABEL + '">{pasteHere}</label></button>',

    /**
     * Construction logic executed during the `A.FormBuilderFieldList`
     * instantiation. Lifecycle.
     *
     * @method initializer
     * @protected
     */
    initializer: function() {
        var content = this.get('content');

        this._uiSetFields(this.get('fields'));

        content.delegate('click', this._onClickAddField, '.' + CSS_FIELD_LIST_ADD_BUTTON, this);
        content.delegate('mouseenter', this._onMouseEnterAddButton, '.' + CSS_FIELD_LIST_ADD_CONTAINER, this);
        content.delegate('mouseleave', this._onMouseLeaveAddButton, '.' + CSS_FIELD_LIST_ADD_CONTAINER, this);

        this.after('fieldsChange', A.bind(this._afterFieldsChange, this));
        this.after('enableAddFieldsChange', A.bind(this._afterEnableAddFieldsChange, this));
    },

    /**
     * Adds a new field to the `A.FormBuilderFieldList`.
     *
     * @method addField
     * @param {A.FormBuilderFieldBase} field
     * @param {Number} index
     */
    addField: function(field, index) {
        var fields = this.get('fields');

        if (!this.get('enableAddFields')) {
            return;
        }

        if (A.Lang.isNumber(index)) {
            fields.splice(index, 0, field);
        }
        else {
            fields.splice(this._newFieldIndex, 0, field);
        }

        this.set('fields', fields);
    },

    /**
     * Removes the given field from the `A.FormBuilderFieldList`.
     *
     * @method removeField
     * @param {A.FormBuilderFieldBase} field
     */
    removeField: function(field) {
        var fields = this.get('fields'),
            indexOf = fields.indexOf(field);

        fields.splice(indexOf, 1);
        this.set('fields', fields);
    },

    /**
     * Executed to the last empty column.
     *
     * @method _addEmptyColumnFieldClasses
     * @param {Node} content
     * @protected
     */
    _addEmptyColumnFieldClasses: function(content) {
        content.one('.' + CSS_FIELD_LIST_ADD_CONTAINER).addClass(CSS_FIELD_LIST_ADD_BUTTON_VISIBLE);
        content.one('.' + CSS_FIELD_LIST_ADD_BUTTON).addClass(CSS_FIELD_LIST_ADD_BUTTON_LARGE);
    },

    /**
     * Fired after the `enableAddFields` attribute change.
     *
     * @method _afterEnableAddFieldsChange
     * @protected
     */
    _afterEnableAddFieldsChange: function() {
        this._uiToggleDisableAddField();
    },

    /**
     * Fired after the `fields` attribute is set.
     *
     * @method _afterFieldsChange
     * @protected
     */
    _afterFieldsChange: function() {
        var fields = this.get('fields');

        this._uiSetFields(fields);
        this._updateRemovableLayoutColProperty();
    },

    /**
     * Appends add field on the given container.
     *
     * @method _appendAddFieldNode
     * @param {Node} container
     * @protected
     */
    _appendAddFieldNode: function(container) {
        var addFieldNode;

        addFieldNode = A.Node.create(A.Lang.sub(this.TPL_ADD_FIELD, {
            addField: this.get('strings').addField
        }));

        container.append(addFieldNode);

        return addFieldNode;
    },

    /**
     * Appends move target button on the given container.
     *
     * @method _appendAddMoveTargetNode
     * @param {Node} container
     * @param {Number} index
     * @protected
     */
    _appendAddMoveTargetNode: function(container, index) {
        var moveTargetNode;

        moveTargetNode = A.Node.create(A.Lang.sub(this.TPL_FIELD_MOVE_TARGET, {
            pasteHere: this.get('strings').pasteHere
        }));

        moveTargetNode.setData('field-list-index', index);

        container.append(moveTargetNode);

        return moveTargetNode;
    },

    /**
     * Fired when the button for adding a new field is clicked.
     *
     * @method _onClickAddField
     * @param {EventFacade} event
     * @protected
     */
    _onClickAddField: function(event) {
        var emptyFieldList = this.get('content').all('.' + CSS_FIELD_LIST_ADD_BUTTON);

        this._newFieldIndex = emptyFieldList.indexOf(event.currentTarget);
    },

    /**
     * Fired when mouse enters the button for adding a new field.
     *
     * @method _onMouseEnterAddButton
     * @param {EventFacade} event
     * @protected
     */
    _onMouseEnterAddButton: function(event) {
        var addButtonNode = event.currentTarget;

        if (this.get('fields').length > 0) {
            addButtonNode.addClass(CSS_FIELD_LIST_ADD_BUTTON_VISIBLE);
        }
    },

    /**
     * Fired when mouse leaves the button for adding a new field.
     *
     * @method _onMouseLeaveAddButton
     * @param {EventFacade} event
     * @protected
     */
    _onMouseLeaveAddButton: function(event) {
        var addButtonNode = event.currentTarget;

        if (this.get('fields').length > 0) {
            addButtonNode.removeClass(CSS_FIELD_LIST_ADD_BUTTON_VISIBLE);
        }
    },

    /**
     * Append a field and its necessaries elements into a given container.
     *
     * @method _uiSetField
     * @param {Node} container
     * @param {Node} field
     * @param {Number} index
     * @protected
     */
    _uiSetField: function(container, field, index) {
        this._appendAddFieldNode(container);
        this._appendAddMoveTargetNode(container, index);

        container.append(field.get('content'));
    },

    /**
     * Updates the ui according to the value of the `fields` attribute.
     *
     * @method _uiSetFields
     * @param {Array} fields
     * @protected
     */
    _uiSetFields: function(fields) {
        var content = this.get('content'),
            container = content.one('.' + CSS_FIELD_LIST_CONTAINER),
            index;

        container.empty();

        for (index = 0; index < fields.length; index++) {
            this._uiSetField(container, fields[index], index);
        }

        this._appendAddFieldNode(container);
        this._appendAddMoveTargetNode(container, index);

        content.toggleClass(CSS_FIELD_LIST_EMPTY, !fields.length);

        if (fields.length === 0) {
            this._addEmptyColumnFieldClasses(content);
        }
    },

    /**
     * Toggle disabled class to the add field button.
     *
     * @method _uiToggleDisableAddField
     * @protected
     */
    _uiToggleDisableAddField: function() {
        this.get('content').one('.' + CSS_FIELD_LIST_ADD_BUTTON).toggleClass('disabled', !this.get('enableAddFields'));
    },

    /**
     * Update removable property for layout cols.
     *
     * @method _updateRemovableLayoutColProperty
     * @protected
     */
    _updateRemovableLayoutColProperty: function() {
        var fields = this.get('fields'),
            content = this.get('content'),
            col = content.ancestor('.col'),
            layoutCol;

        if (col) {
            layoutCol = col.getData('layout-col');
            layoutCol.set('removable', fields.length === 0);
        }
    }
}, {

    /**
     * Static property used to define the default attribute
     * configuration for the `A.FormBuilderFieldList`.
     *
     * @property ATTRS
     * @type Object
     * @static
     */
    ATTRS: {

        /**
         * Node containing the contents of this field list.
         *
         * @attribute content
         * @type Node
         */
        content: {
            validator: function(val) {
                return A.instanceOf(val, A.Node);
            },
            valueFn: function() {
                return A.Node.create(this.TPL_FIELD_LIST);
            },
            writeOnce: 'initOnly'
        },

        /**
         * Attribute responsible for enabling or disabling the feature of adding fields.
         *
         * @attribute enableAddFields
         * @type {Boolean}
         */
        enableAddFields: {
            validator: A.Lang.isBoolean,
            value: true
        },

        /**
         * List of field.
         *
         * @attribute fields
         * @type {Array}
         */
        fields: {
            validator: A.Lang.isArray,
            value: []
        },

        /**
         * Collection of strings used to label elements of the UI.
         *
         * @attribute strings
         * @type {Object}
         */
        strings: {
            value: {
                addField: 'Add Field',
                pasteHere: 'Paste here'
            },
            writeOnce: true
        }
    }
});


}, '3.1.0-deprecated.110', {
    "requires": [
        "aui-form-builder-field-type",
        "aui-form-builder-field-types",
        "aui-form-builder-layout-builder"
    ],
    "skinnable": true
});
