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

/**
 * The Form Builder Component
 *
 * @module aui-form-builder
 * @submodule aui-form-builder-field
 */

var L = A.Lang,
    isArray = L.isArray,
    isObject = L.isObject,

    AArray = A.Array,
    AEscape = A.Escape,

    getCN = A.getClassName,

    CSS_CLEARFIX = getCN('clearfix'),
    CSS_COMPONENT = getCN('component'),
    CSS_FB_DROP_ZONE = getCN('form', 'builder', 'drop', 'zone'),
    CSS_FB_FIELD = getCN('form', 'builder', 'field'),
    CSS_FB_FIELD_NODE = getCN('form', 'builder', 'field', 'node'),
    CSS_FB_FIELD_SELECTED = getCN('form', 'builder', 'field', 'selected'),
    CSS_FB_UNIQUE = getCN('form', 'builder', 'unique'),
    CSS_ICON = getCN('glyphicon'),
    CSS_ICON_ASTERISK = getCN('glyphicon', 'asterisk'),
    CSS_ICON_PLUS = getCN('glyphicon', 'plus'),
    CSS_ICON_QUESTION_SIGN = getCN('glyphicon', 'question', 'sign'),
    CSS_ICON_TRASH = getCN('glyphicon', 'trash'),
    CSS_ICON_WRENCH = getCN('glyphicon', 'wrench'),
    CSS_WIDGET = getCN('widget'),

    TPL_BOUNDING_BOX = '<div class="' + [CSS_WIDGET, CSS_COMPONENT, CSS_FB_FIELD].join(' ') + '"></div>',
    TPL_DROP_ZONE = '<div class="' + CSS_FB_DROP_ZONE + '"></div>',
    TPL_FLAG_REQUIRED = '<span class="' + [CSS_ICON, CSS_ICON_ASTERISK].join(' ') + '"></span>',
    TPL_FLAG_TIP = '<span class="' + [CSS_ICON, CSS_ICON_QUESTION_SIGN].join(' ') + '"></span>',
    TPL_LABEL = '<label for="{id}">{label}</label>',

    INVALID_CLONE_ATTRS = ['id', 'name'];

/**
 * A base class for `A.FormBuilderField`.
 *
 * @class A.FormBuilderField
 * @param {Object} config Object literal specifying widget configuration
 *     properties.
 * @constructor
 */
var FormBuilderField = A.Component.create({

    /**
     * Static property provides a string to identify the class.
     *
     * @property NAME
     * @type String
     * @static
     */
    NAME: 'form-builder-field',

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

        /**
         * If `true` children are accepted.
         *
         * @attribute acceptChildren
         * @default true
         * @type Boolean
         */
        acceptChildren: {
            value: true
        },

        /**
         * The `A.FormBuilder` instance.
         *
         * @attribute builder
         * @default null
         */
        builder: {
            value: null
        },

        /**
         * Collection of toolbar controls.
         *
         * @attribute controlsToolbar
         * @type Object
         */
        controlsToolbar: {
            validator: isObject,
            valueFn: function() {
                var instance = this;

                return {
                    children: instance._getToolbarItems(instance.get('required'), instance.get('unique')),
                    visible: A.UA.touchEnabled && A.UA.mobile
                };
            }
        },

        /**
         * Indicates which is the type of data for the input field.
         *
         * @attribute dataType
         * @default 'string'
         * @type String
         */
        dataType: {
            value: 'string'
        },

        /**
         * Checks if the input field is disabled or not.
         *
         * @attribute disabled
         * @default false
         * @type Boolean
         */
        disabled: {
            value: false
        },

        /**
         * Checks if the input field is selected or not.
         *
         * @attribute selected
         * @default false
         * @type Boolean
         */
        selected: {
            value: false
        },

        /**
         * List of hidden attributes.
         *
         * @attribute hiddenAttributes
         * @default []
         * @type Array
         */
        hiddenAttributes: {
            validator: isArray,
            value: []
        },

        /**
         * The id of the input field.
         *
         * @attribute id
         */
        id: {
            setter: '_setId'
        },

        /**
         * The label of the input field.
         *
         * @attribute label
         * @default ''
         * @type String
         */
        label: {
            value: ''
        },

        /**
         * Collection for content localization.
         *
         * @attribute localizationMap
         * @default {}
         * @type Object
         */
        localizationMap: {
            value: {}
        },

        /**
         * The name of the input field.
         *
         * @attribute name
         */
        name: {
            valueFn: function() {
                var instance = this,
                    type = instance.get('type');

                return A.FormBuilderField.buildFieldName(type);
            }
        },

        /**
         * Container for the field parent.
         *
         * @attribute parent
         * @default null
         */
        parent: {
            value: null
        },

        /**
         * Specifies a predefined value for the input field.
         *
         * @attribute predefinedValue
         * @default ''
         * @type String
         */
        predefinedValue: {
            value: ''
        },

        /**
         * Checks if an input field is read-only.
         * In other words, it cannot be modified.
         *
         * @attribute readOnly
         * @default false
         * @type Boolean
         */
        readOnly: {
            setter: A.DataType.Boolean.parse,
            value: false
        },

        /**
         * List of read-only input fields.
         *
         * @attribute readOnlyAttributes
         * @default []
         * @type Array
         */
        readOnlyAttributes: {
            validator: isArray,
            value: []
        },

        /**
         * Checks if an input field is required.
         * In other words, it needs content to be valid.
         *
         * @attribute required
         * @default false
         * @type Boolean
         */
        required: {
            setter: A.DataType.Boolean.parse,
            value: false
        },

        /**
         * If `true` the label is showed.
         *
         * @attribute showLabel
         * @default true
         * @type Boolean
         */
        showLabel: {
            setter: A.DataType.Boolean.parse,
            value: true
        },

        /**
         * Collection of strings used to label elements of the UI.
         *
         * @attribute strings
         * @type Object
         */
        strings: {
            value: {
                button: 'Button',
                buttonType: 'Button Type',
                deleteFieldsMessage: 'Are you sure you want to delete the selected field(s)?',
                duplicateMessage: 'Duplicate',
                editMessage: 'Edit',
                label: 'Label',
                large: 'Large',
                medium: 'Medium',
                multiple: 'Multiple',
                name: 'Name',
                no: 'No',
                options: 'Options',
                predefinedValue: 'Predefined Value',
                readOnly: 'Read Only',
                required: 'Required',
                reset: 'Reset',
                showLabel: 'Show Label',
                small: 'Small',
                submit: 'Submit',
                tip: 'Tip',
                type: 'Type',
                width: 'Width',
                yes: 'Yes'
            }
        },

        /**
         * Specify the tab order.
         *
         * @attribute tabIndex
         * @default 0
         * @type Number
         */
        tabIndex: {
            value: 0
        },

        /**
         * Reusable block of markup used to generate the field.
         *
         * @attribute template
         * @default ''
         * @type String
         */
        template: {
            value: ''
        },

        /**
         * Hint to help the user to fill the input field.
         *
         * @attribute tip
         * @default ''
         * @type String
         */
        tip: {
            value: ''
        },

        /**
         * Defines the type of field.
         *
         * @attribute type
         * @default ''
         * @type String
         */
        type: {
            value: ''
        },

        /**
         * Checks if the input field is unique or not.
         *
         * @attribute unique
         * @default false
         * @type Boolean
         */
        unique: {
            setter: A.DataType.Boolean.parse,
            value: false
        },

        /**
         * Stack order of the field. An element with greater stack order is
         * always in front of an element with a lower stack order.
         *
         * @attribute zIndex
         * @default 100
         * @type Number
         */
        zIndex: {
            value: 100
        },

        /**
         * Node used to generate the drop zone.
         *
         * @attribute dropZoneNode
         */
        dropZoneNode: {
            valueFn: function() {
                return A.Node.create(TPL_DROP_ZONE);
            }
        },

        /**
         * Node used to generate a label.
         *
         * @attribute labelNode
         */
        labelNode: {
            valueFn: function() {
                var instance = this;

                return A.Node.create(
                    L.sub(
                        TPL_LABEL, {
                            id: AEscape.html(instance.get('id')),
                            label: AEscape.html(instance.get('label'))
                        }
                    )
                );
            }
        },

        /**
         * Node used to generate the required flag.
         *
         * @attribute requiredFlagNode
         */
        requiredFlagNode: {
            valueFn: function() {
                return A.Node.create(TPL_FLAG_REQUIRED);
            }
        },

        /**
         * Node used to generate a template.
         *
         * @attribute templateNode
         */
        templateNode: {
            valueFn: 'getNode'
        },

        /**
         * Node used to generate a tip.
         *
         * @attribute tipFlagNode
         */
        tipFlagNode: {
            valueFn: function() {
                return A.Node.create(TPL_FLAG_TIP);
            }
        }

    },

    /**
     * Static property used to define the UI attributes.
     *
     * @property UI_ATTRS
     * @type Array
     * @static
     */
    UI_ATTRS: [
        'acceptChildren', 'disabled', 'fields', 'label', 'name',
        'predefinedValue', 'required', 'selected', 'showLabel', 'tip', 'unique'
    ],

    /**
     * Static property used to define the augmented classes.
     *
     * @property AUGMENTS
     * @type Array
     * @static
     */
    AUGMENTS: [A.PropertyBuilderFieldSupport],

    /**
     * Creates the field id.
     *
     * @method buildFieldId
     * @param id
     * @private
     * @return {String}
     */
    buildFieldId: function(id) {
        return 'fields' + '_' + 'field' + '_' + id;
    },

    /**
     * Creates the field name.
     *
     * @method buildFieldName
     * @param type
     * @private
     * @return {String}
     */
    buildFieldName: function(type) {
        return type + (++A.Env._uidx);
    },

    /**
     * Object hash, defining how attribute values have to be parsed from markup.
     *
     * @property HTML_PARSER
     * @type Object
     * @static
     */
    HTML_PARSER: {
        dropZoneNode: '.' + CSS_FB_DROP_ZONE,
        labelNode: 'label',
        requiredFlagNode: '.' + CSS_ICON + ' .' + CSS_ICON_ASTERISK,
        tipFlagNode: '.' + CSS_ICON + ' .' + CSS_ICON_QUESTION_SIGN
    },

    prototype: {
        BOUNDING_TEMPLATE: TPL_BOUNDING_BOX,

        /**
         * Construction logic executed during `A.FormBuilderField` instantiation.
         * Lifecycle.
         *
         * @method initializer
         * @protected
         */
        initializer: function() {
            var instance = this;

            instance.controlsToolbar = new A.Toolbar(
                instance.get('controlsToolbar')
            );
        },

        /**
         * Render the `A.FormBuilderField` component instance. Lifecycle.
         *
         * @method renderUI
         * @protected
         */
        renderUI: function() {
            var instance = this,
                boundingBox = instance.get('boundingBox'),
                contentBox = instance.get('contentBox'),
                labelNode = instance.get('labelNode'),
                requiredFlagNode = instance.get('requiredFlagNode'),
                templateNode = instance.get('templateNode'),
                tipFlagNode = instance.get('tipFlagNode');

            contentBox.addClass(CSS_CLEARFIX);

            contentBox.append(labelNode);
            contentBox.append(requiredFlagNode);
            contentBox.append(tipFlagNode);
            contentBox.append(templateNode);

            instance.controlsToolbar.render(boundingBox);
        },

        /**
         * Destructor lifecycle implementation for the `A.FormBuilderField`
         * class.
         *
         * @method destructor
         * @protected
         */
        destructor: function() {
            var instance = this,
                builder = instance.get('builder'),
                fieldId = builder._getFieldId(instance);

            instance.get('fields').each(function(field) {
                field.destroy();
            });

            if (builder.editingField === instance) {
                delete builder.editingField;

                builder.closeEditProperties();
            }

            if (instance.controlsToolbar) {
                instance.controlsToolbar.destroy();
            }

            // destroy manually because NestedList doesn`t
            // use delegate
            instance.get('boundingBox').dd.destroy();

            instance.tooltip.destroy();

            instance.get('parent').removeField(instance);

            builder.uniqueFieldsMap.remove(fieldId);
        },

        /**
         * Creates the field using the `createField` method from
         * `A.FormBuilder`.
         *
         * @method createField
         * @param val
         * @return {Object}
         */
        createField: function(val) {
            var instance = this,
                builder = instance.get('builder');

            val = builder.createField(val);

            val.set('parent', instance);

            return val;
        },

        /**
         * Gets the field markup.
         *
         * To developer: Implement this
         *
         * @method getHTML
         * @return {String}
         */
        getHTML: function() {
            return '';
        },

        /**
         * Creates a `Node` from the HTML string.
         *
         * @method getNode
         * @return {Node}
         */
        getNode: function() {
            var instance = this;

            return A.Node.create(instance.getHTML());
        },

        /**
         * Gets all necessary attributes for cloning this field.
         *
         * @method getAttributesForCloning
         * @return {Object}
         */
        getAttributesForCloning: function() {
            // List of all non-property attributes that need to be cloned.
            var attributes = {
                hiddenAttributes: this.get('hiddenAttributes'),
                readOnlyAttributes: this.get('readOnlyAttributes'),
                localizationMap: this.get('localizationMap')
            };

            // All field properties should be cloned as well.
            AArray.each(this.getProperties(), function(property) {
                var name = property.attributeName;

                if (AArray.indexOf(INVALID_CLONE_ATTRS, name) === -1) {
                    attributes[name] = property.value;
                }
            });

            return attributes;
        },

        /**
         * Gets properties from the property model.
         *
         * @method getProperties
         * @return {Array}
         */
        getProperties: function(excludeHidden) {
            var instance = this,
                propertyModel = instance.getPropertyModel(),
                hiddenAttributes = instance.get('hiddenAttributes'),
                readOnlyAttributes = instance.get('readOnlyAttributes'),
                properties = [];

            AArray.each(propertyModel, function(property) {
                var attribute = property.attributeName;

                // TODO - Change checking to use hashes O(1) instead of indexOf
                // arrays O(N)
                if (excludeHidden && AArray.indexOf(hiddenAttributes, attribute) > -1) {
                    return;
                }

                var value = instance.get(attribute),
                    type = L.type(value);

                if (type === 'boolean') {
                    value = String(value);
                }

                property.value = value;

                // TODO - Change checking to use hashes O(1) instead of indexOf
                // arrays O(N)
                if (AArray.indexOf(readOnlyAttributes, attribute) > -1) {
                    property.readOnly = true;
                }

                properties.push(property);
            });

            return properties;
        },

        /**
         * Returns a list of property models. Each property model is made of a
         * name, attribute, editor, and formatter.
         *
         * @method getPropertyModel
         * @return {Array}
         */
        getPropertyModel: function() {
            var instance = this,
                strings = instance.getStrings();

            return [{
                attributeName: 'type',
                editor: false,
                name: strings.type
            }, {
                attributeName: 'label',
                editor: new A.TextCellEditor(),
                name: strings.label
            }, {
                attributeName: 'showLabel',
                editor: new A.RadioCellEditor({
                    options: {
                        'true': strings.yes,
                        'false': strings.no
                    }
                }),
                formatter: A.bind(instance._booleanFormatter, instance),
                name: strings.showLabel
            }, {
                attributeName: 'readOnly',
                editor: new A.RadioCellEditor({
                    options: {
                        'true': strings.yes,
                        'false': strings.no
                    }
                }),
                formatter: A.bind(instance._booleanFormatter, instance),
                name: strings.readOnly
            }, {
                attributeName: 'required',
                editor: new A.RadioCellEditor({
                    options: {
                        'true': strings.yes,
                        'false': strings.no
                    }
                }),
                formatter: A.bind(instance._booleanFormatter, instance),
                name: strings.required
            }, {
                attributeName: 'name',
                editor: new A.TextCellEditor({
                    validator: {
                        rules: {
                            value: {
                                required: true
                            }
                        }
                    }
                }),
                name: strings.name
            }, {
                attributeName: 'predefinedValue',
                editor: new A.TextCellEditor(),
                name: strings.predefinedValue
            }, {
                attributeName: 'tip',
                editor: new A.TextAreaCellEditor(),
                name: strings.tip
            }];
        },

        /**
         * Transforms a `Boolean` value into "yes" or "no" string.
         *
         * @method _booleanFormatter
         * @param o
         * @protected
         */
        _booleanFormatter: function(o) {
            var instance = this,
                strings = instance.getStrings();

            return A.DataType.Boolean.parse(o.data.value) ? strings.yes : strings.no;
        },

        /**
         * Returns the node for the current field.
         *
         * @method _getFieldNode
         * @protected
         */
        _getFieldNode: function() {
            var templateNode = this.get('templateNode'),
                fieldNode = templateNode.one('.' + CSS_FB_FIELD_NODE);

            if (!fieldNode) {
                fieldNode = templateNode;
            }

            return fieldNode;
        },

        /**
         * Gets a list of toolbar items.
         *
         * @method _getToolbarItems
         * @return {Array}
         */
        _getToolbarItems: function() {
            var instance = this,
                builder = instance.get('builder'),
                items = [
                    {
                        icon: [CSS_ICON, CSS_ICON_WRENCH].join(' '),
                        on: {
                            click: A.bind(instance._handleEditEvent, instance)
                        }
                    }
                ];

            if (!instance.get('unique')) {
                items.push({
                    icon: [CSS_ICON, CSS_ICON_PLUS].join(' '),
                    on: {
                        click: A.bind(instance._handleDuplicateEvent, instance)
                    }
                });
            }

            if ((builder && builder.get('allowRemoveRequiredFields')) || !instance.get('required')) {
                items.push({
                    icon: [CSS_ICON, CSS_ICON_TRASH].join(' '),
                    on: {
                        click: A.bind(instance._handleDeleteEvent, instance)
                    }
                });
            }

            return [items];
        },

        /**
         * Checks if the field isn't unique. If not, duplicates the instance.
         *
         * @method _handleDuplicateEvent
         * @param event
         * @protected
         */
        _handleDuplicateEvent: function(event) {
            var instance = this;

            if (!instance.get('unique')) {
                instance.get('builder').duplicateField(instance);
            }

            event.stopPropagation();
        },

        /**
         * Handles the edit event.
         *
         * @method _handleEditEvent
         * @param event
         * @protected
         */
        _handleEditEvent: function(event) {
            var instance = this;

            instance.get('builder').editField(instance);

            event.stopPropagation();
        },

        /**
         * Popups a dialog to confirm deletion. If "yes", destroys the instance.
         *
         * @method _handleDeleteEvent
         * @param event
         * @protected
         */
        _handleDeleteEvent: function(event) {
            var instance = this,
                strings = instance.getStrings();

            if (window.confirm(strings.deleteFieldsMessage)) {
                instance.destroy();
            }

            event.stopPropagation();
        },

        /**
         * Set the `id` attribute on the UI.
         *
         * @method _setId
         * @param val
         * @protected
         */
        _setId: function(val) {
            return A.FormBuilderField.buildFieldId(val);
        },

        /**
         * Set the `acceptChildren` attribute on the UI.
         *
         * @method _uiSetAcceptChildren
         * @param val
         * @protected
         */
        _uiSetAcceptChildren: function(val) {
            var instance = this,
                boundingBox = instance.get('boundingBox'),
                dropZone = instance.get('dropZoneNode'),
                markupDropZone = boundingBox.one('.' + CSS_FB_DROP_ZONE);

            if (val && !markupDropZone) {
                boundingBox.append(dropZone);
            }
            else if (!val && markupDropZone) {
                markupDropZone.remove();
            }
            else if (val && markupDropZone) {
                instance.set('dropZoneNode', markupDropZone);
            }
        },

        /**
         * Set the `selected` attribute on the UI.
         *
         * @method _uiSetSelected
         * @param val
         * @protected
         */
        _uiSetSelected: function(val) {
            var instance = this;

            instance.get('boundingBox').toggleClass(CSS_FB_FIELD_SELECTED, val);
        },

        /**
         * Set the `disabled` attribute on the UI.
         *
         * @method _uiSetDisabled
         * @param val
         * @protected
         */
        _uiSetDisabled: function(val) {
            var fieldNode = this._getFieldNode();

            if (val) {
                fieldNode.setAttribute('disabled', val);
            }
            else {
                fieldNode.removeAttribute('disabled');
            }
        },

        /**
         * Set the fields on the UI using the `plotFields` method from
         * `A.FormBuilder`.
         *
         * @method _uiSetFields
         * @param val
         * @protected
         */
        _uiSetFields: function(val) {
            var instance = this,
                builder = instance.get('builder');

            builder.plotFields(val, instance.get('dropZoneNode'));
        },

        /**
         * Set the label content on the UI.
         *
         * @method _uiSetLabel
         * @param val
         * @protected
         */
        _uiSetLabel: function(val) {
            var instance = this,
                labelNode = instance.get('labelNode');

            labelNode.setContent(AEscape.html(val));
        },

        /**
         * Set the `name` attribute on the UI.
         *
         * @method _uiSetName
         * @param val
         * @protected
         */
        _uiSetName: function(val) {
            var fieldNode = this._getFieldNode();

            fieldNode.set('name', val);
        },

        /**
         * Set the `predefinedValue` attribute on the UI.
         *
         * @method _uiSetPredefinedValue
         * @param val
         * @protected
         */
        _uiSetPredefinedValue: function(val) {
            var fieldNode = this._getFieldNode();

            fieldNode.val(val);
        },

        /**
         * Set the `required` attribute on the UI.
         *
         * @method _uiSetRequired
         * @param val
         * @protected
         */
        _uiSetRequired: function(val) {
            var instance = this,
                controlsToolbar = instance.controlsToolbar,
                requiredNode = instance.get('requiredFlagNode');

            requiredNode.toggle(val);

            controlsToolbar.set('children', instance._getToolbarItems());
        },

        /**
         * Set the `showLabel` attribute on the UI.
         *
         * @method _uiSetShowLabel
         * @param val
         * @protected
         */
        _uiSetShowLabel: function(val) {
            var instance = this,
                labelNode = instance.get('labelNode');

            labelNode.toggle(val);
        },

        /**
         * Set the `tip` attribute on the UI.
         *
         * @method _uiSetTip
         * @param val
         * @protected
         */
        _uiSetTip: function(val) {
            var tipFlagNode = this.get('tipFlagNode');

            tipFlagNode.toggle(val.length !== 0);

            if (this.tooltip) {
                this.tooltip.set('bodyContent', val);
                return;
            }

            this.tooltip = new A.Tooltip({
                bodyContent: val,
                trigger: tipFlagNode,
                position: 'right',
                visible: false
            }).render();
        },

        /**
         * Set the `unique` attribute on the UI.
         *
         * @method _uiSetUnique
         * @param val
         * @protected
         */
        _uiSetUnique: function(val) {
            var instance = this,
                boundingBox = instance.get('boundingBox'),
                controlsToolbar = instance.controlsToolbar;

            boundingBox.toggleClass(CSS_FB_UNIQUE, val);

            controlsToolbar.set('children', instance._getToolbarItems());
        }

    }

});

A.FormBuilderField = FormBuilderField;
A.namespace('FormBuilderField.types').field = FormBuilderField;


}, '3.1.0-deprecated.112', {
    "requires": [
        "panel",
        "aui-datatype",
        "aui-datatable-edit",
        "aui-property-builder-field-support"
    ],
    "skinnable": true
});
