YUI.add('aui-input-text-control-deprecated', function (A, NAME) {

var Lang = A.Lang,
    isArray = Lang.isArray,
    isFunction = Lang.isFunction,
    isString = Lang.isString,

    KeyMap = A.Event.KeyMap,

    ALERT = 'alert',
    BINDUI = 'bindUI',
    CONTENT = 'content',
    ICON = 'icon',
    LIST = 'list',
    LOADING = 'loading',
    RENDERUI = 'renderUI',

    ICON_DEFAULT = 'circle-triangle-b',
    ICON_ERROR = ALERT,
    ICON_LOADING = LOADING,

    BACKSPACE = 'BACKSPACE',
    TAB = 'TAB',
    ALT = 'ALT',
    WIN_IME = 'WIN_IME',

    OVERLAY_ALIGN = {
        node: null,
        points: ['tl', 'bl']
    },

    BOUNDING_BOX = 'boundingBox',
    CONTENT_BOX = 'contentBox';

var InputTextControl = function() {
    var instance = this;

    instance.on(RENDERUI, instance._renderUIInputTextControl, instance);
    instance.on(BINDUI, instance._bindUIInputTextControl, instance);
};

/**
 * Static property used to define the default attribute
 * configuration for the AutoComplete.
 *
 * @property AutoComplete.ATTRS
 * @type Object
 * @static
 */

InputTextControl.ATTRS = {
    /**
     * To use a button
     *
     * @attribute button
     * @default true
     * @type Boolean
     * @deprecated
     */
    button: {
        value: true
    },

    /**
     * The character used to indicate the beginning or ending of a new value. Most commonly used
     * is a ",".
     *
     * @attribute delimChar
     * @default null
     * @type String
     */
    delimChar: {
        value: null,
        setter: function(value) {
            if (isString(value) && (value.length > 0)) {
                value = [value];
            }
            else if (!isArray(value)) {
                value = A.Attribute.INVALID_VALUE;
            }

            return value;
        }
    },

    /**
     * If <a href="AutoComplete.html#config_typeAhead">typeAhead</a> is true, this
     * will clear a selection when the overlay closes unless a user explicitly selects an item.
     *
     * @attribute forceSelection
     * @default false
     * @type Boolean
     */
    forceSelection: {
        value: false
    },

    iconButton: {
        value: ICON_DEFAULT
    },

    /**
     * The input field which will recieve the users input.
     *
     * @attribute input
     * @default null
     * @type String | Node
     */
    input: {
        value: null
    },

    /**
     * The key or numeric index in the schema to match the result against.
     *
     * @attribute matchKey
     * @default 0
     * @type String | Number
     */
    matchKey: {
        value: 0
    },

    /**
     * The minimum number of characters required to query the data source.
     *
     * @attribute minQueryLength
     * @default 1
     * @type Number
     */
    minQueryLength: {
        value: 1
    },

    /**
     * The amount of time in seconds to delay before submitting the query.
     *
     * @attribute queryDelay
     * @default 0.2
     * @type Number
     */
    queryDelay: {
        value: 0.2,
        getter: function(value) {
            return value * 1000;
        }
    },

    /**
     * When IME usage is detected or interval detection is explicitly enabled,
     * AutoComplete will detect the input value at the given interval and send a
     * query if the value has changed.
     *
     * @attribute queryInterval
     * @default 0.5
     * @type Number
     */
    queryInterval: {
        value: 0.5,
        getter: function(value) {
            return value * 1000;
        }
    },

    /**
     * When <a href="AutoComplete.html#config_applyLocalFilter">applyLocalFilter</a> is true,
     * setting this to true will match only results with the same case.
     *
     * @attribute queryMatchCase
     * @default false
     * @type Boolean
     */
    queryMatchCase: {
        value: false
    },

    /**
     * When <a href="AutoComplete.html#config_applyLocalFilter">applyLocalFilter</a> is true,
     * setting this to true will match results which contain the query anywhere in the text,
     * instead of just matching just items that start with the query.
     *
     * @attribute queryMatchContains
     * @default false
     * @type Boolean
     */
    queryMatchContains: {
        value: false
    },

    /**
     * For IO DataSources, AutoComplete will automatically insert a "?" between the server URI and
     * the encoded query string. To prevent this behavior, you can
     * set this value to false. If you need to customize this even further, you
     * can override the <a href="AutoComplete.html#method_generateRequest">generateRequest</a> method.
     *
     * @attribute queryQuestionMark
     * @default true
     * @type Boolean
     */
    queryQuestionMark: {
        value: true
    },

    /**
     * Whether or not the input field should be updated with selections.
     *
     * @attribute suppressInputUpdate
     * @default false
     * @type Boolean
     */
    suppressInputUpdate: {
        value: false
    },

    /**
     * If <a href="AutoComplete.html#config_autoHighlight">autoHighlight</a> is enabled, whether or not the
     * input field should be automatically updated with the first result as the user types,
     * automatically selecting the portion of the text the user has not typed yet.
     *
     * @attribute typeAhead
     * @default false
     * @type Boolean
     */
    typeAhead: {
        value: false
    },

    /**
     * If <a href="AutoComplete.html#config_typeAhead">typeAhead</a> is true, number of seconds
     * to delay before updating the input. In order to prevent certain race conditions, this value must
     * always be greater than the <a href="AutoComplete.html#config_queryDelay">queryDelay</a>.
     *
     * @attribute typeAheadDelay
     * @default 0.2
     * @type Number
     */
    typeAheadDelay: {
        value: 0.2,
        getter: function(value) {
            return value * 1000;
        }
    },

    /**
     * The unique ID of the input element.
     *
     * @attribute uniqueName
     * @default null
     * @type String
     */
    uniqueName: {
        value: null
    }
};

InputTextControl.prototype = {
    /**
     * Construction logic executed during AutoComplete instantiation. Lifecycle.
     *
     * @method initializer
     * @protected
     */
    initializer: function(config) {
        var instance = this;

        instance._overlayAlign = A.mix({}, OVERLAY_ALIGN);
    },

    /**
     * Create the DOM structure for the InputTextControl. Lifecycle.
     *
     * @method _renderUIInputTextControl
     * @protected
     */
    _renderUIInputTextControl: function() {
        var instance = this;

        instance._renderInput();
    },

    /**
     * Bind the events on the InputTextControl UI. Lifecycle.
     *
     * @method _bindUIInputTextControl
     * @protected
     */
    _bindUIInputTextControl: function() {
        var instance = this;

        instance._bindDataSource();

        var button = instance.button;
        var inputNode = instance.inputNode;

        inputNode.on('blur', instance._onTextboxBlur, instance);
        inputNode.on('focus', instance._onTextboxFocus, instance);
        inputNode.on('keydown', instance._onTextboxKeyDown, instance);
        inputNode.on('keypress', instance._onTextboxKeyPress, instance);
        inputNode.on('keyup', instance._onTextboxKeyUp, instance);

        instance.publish('handleResponse');

        instance.publish('textboxKeyDown');

        instance.publish('textboxKeyPress');

        instance.publish('textboxKeyUp');

        instance.publish('invalidQueryLength');

        instance.publish('sendQueryDisabled');

        /**
         * Handles the containerCollapse event. Fired when the container is hidden.
         *
         * @event containerCollapse
         * @param {Event.Facade} event The containerCollapse event.
         */
        instance.publish('containerCollapse');

        /**
         * Handles the containerExpand event. Fired when the container is shown.
         *
         * @event containerExpand
         * @param {Event.Facade} event The containerExpand event.
         */
        instance.publish('containerExpand');

        /**
         * Handles the containerPopulate event. Fired when the container is populated.
         *
         * @event containerPopulate
         * @param {Event.Facade} event The containerPopulate event.
         */
        instance.publish('containerPopulate');

        /**
         * Handles the itemArrowFrom event. Fired when the user navigates via the keyboard away from
         * a selected item.
         *
         * @event itemArrowFrom
         * @param {Event.Facade} event The itemArrowFrom event.
         */
        instance.publish('itemArrowFrom');

        /**
         * Handles the itemArrowTo event. Fired when the user navigates via the keyboard to a selected item.
         *
         * @event itemArrowTo
         * @param {Event.Facade} event The itemArrowTo event.
         */
        instance.publish('itemArrowTo');

        /**
         * Handles the itemMouseOut event. Fired when the user mouses away from an item.
         *
         * @event itemMouseOut
         * @param {Event.Facade} event The itemMouseOut event.
         */
        instance.publish('itemMouseOut');

        /**
         * Handles the itemMouseOver event. Fired when the user mouses over an item.
         *
         * @event itemMouseOver
         * @param {Event.Facade} event The itemMouseOver event.
         */
        instance.publish('itemMouseOver');

        /**
         * Handles the itemSelect event. Fired when an item in the list is selected.
         *
         * @event itemSelect
         * @param {Event.Facade} event The itemSelect event.
         */
        instance.publish('itemSelect');

        /**
         * Handles the selectionEnforce event. Fired if <a href="Autocomplete.html#config_forceSelection">forceSelection</a>
         * is enabled and the users input element has been cleared because it did not match one of the results.
         *
         * @event selectionEnforce
         * @param {Event.Facade} event The selectionEnforce event.
         */
        instance.publish('selectionEnforce');

        /**
         * Handles the textboxBlur event. Fired when the user leaves the input element.
         *
         * @event textboxBlur
         * @param {Event.Facade} event The textboxBlur event.
         */
        instance.publish('textboxBlur');

        /**
         * Handles the textboxChange event. Fired when the value in the input element is changed.
         *
         * @event textboxChange
         * @param {Event.Facade} event The textboxChange event.
         */
        instance.publish('textboxChange');

        /**
         * Handles the textboxFocus event. Fired when user moves focus to the input element.
         *
         * @event textboxFocus
         * @param {Event.Facade} event The textboxFocus event.
         */
        instance.publish('textboxFocus');

        /**
         * Handles the textboxKey event. Fired when the input element receives key input.
         *
         * @event textboxKey
         * @param {Event.Facade} event The textboxKey event.
         */
        instance.publish('textboxKey');

        /**
         * Handles the typeAhead event. Fired when the input element has been pre-filled by the type-ahead feature.
         *
         * @event typeAhead
         * @param {Event.Facade} event The typeAhead event.
         */
        instance.publish('typeAhead');

        /**
         * Handles the unmatchedItemSelect event. Fired when a user selects something that does
         * not match any of the displayed results.
         *
         * @event unmatchedItemSelect
         * @param {Event.Facade} event The unmatchedItemSelect event.
         */
        instance.publish('unmatchedItemSelect');
    },

    /**
     * Sync the AutoComplete UI. Lifecycle.
     *
     * @method syncUI
     * @protected
     */
    syncUI: function() {
        var instance = this;

        instance.inputNode.setAttribute('autocomplete', 'off');
    },

    /**
     * An overridable method that is executed before the result overlay is loaded with results.
     *
     * @method doBeforeLoadData
     * @param {EventFacade} event
     * @return {Boolean}
     */
    doBeforeLoadData: function(event) {
        return true;
    },

    /**
     * An overridable method for formatting the result of the query before it's displayed in the overlay.
     *
     * @method formatResult
     * @param {Object} result The result data object
     * @param {String} request The current query string
     * @param {String} resultMatch The string from the results that matches the query
     * @return {String}
     */
    formatResult: function(result, request, resultMatch) {
        return resultMatch || '';
    },

    /**
     * An overridable method that creates an object to be passed to the sendRequest
     * method of the data source object. Useful to overwrite if you wish to create
     * a custom request object before it's sent.
     *
     * @method generateRequest
     * @param {String} query The string currently being entered
     * @return {Object}
     */
    generateRequest: function(query) {
        return {
            request: query
        };
    },

    /**
     * Handles the response for the display of the results. This is a callback method
     * that is fired by the sendRequest method so that results are ready to be accessed.
     *
     * @method handleResponse
     * @param {EventFacade} event
     */
    handleResponse: function(event) {
        var instance = this;

        instance.fire('handleResponse', event);

        var iconClass = instance.get('iconButton') || ICON_DEFAULT;

        if (event.error) {
            iconClass = ICON_ERROR;
        }

        instance.button.set(ICON, iconClass);
    },

    _bindDataSource: function() {
        var instance = this;

        var button = instance.button;
        var dataSource = instance.get('dataSource');
        var dataSourceType = instance.get('dataSourceType');

        dataSource.on('request', A.bind(button.set, button, ICON, ICON_LOADING));
        dataSource.on('error', instance.handleResponse, instance);
        dataSource.after('response', instance.handleResponse, instance);
    },

    /**
     * Clears the query interval
     *
     * @method _clearInterval
     * @private
     */
    _clearInterval: function() {
        var instance = this;

        if (instance._queryIntervalId) {
            clearInterval(instance._queryIntervalId);

            instance._queryIntervalId = null;
        }
    },

    /**
     * When <a href="Autocomplete.html#config_forceSelection">forceSelection</a> is true and
     * the user tries to leave the input element without selecting an item from the results,
     * the user selection is cleared.
     *
     * @method _clearSelection
     * @protected
     */
    _clearSelection: function() {
        var instance = this;

        var delimChar = instance.get('delimChar');
        var extraction = {
            previous: '',
            query: instance.inputNode.get('value')
        };

        if (delimChar) {
            extraction = instance._extractQuery(instance.inputNode.get('value'));
        }

        instance.fire('selectionEnforce', extraction.query);
    },

    /**
     * Enables query interval detection for IME support.
     *
     * @method _enableIntervalDetection
     * @protected
     */
    _enableIntervalDetection: function() {
        var instance = this;

        var queryInterval = instance.get('queryInterval');

        if (!instance._queryIntervalId && queryInterval) {
            instance._queryInterval = setInterval(A.bind(instance._onInterval, instance), queryInterval);
        }
    },

    /**
     * Extracts the right most query from the delimited string in the input.
     *
     * @method _extractQuery
     * @param {String} query String to parse
     * @protected
     * @return {String}
     */
    _extractQuery: function(query) {
        var instance = this;

        var delimChar = instance.get('delimChar');
        var delimIndex = -1;
        var i = delimChar.length - 1;

        var newIndex, queryStart, previous;

        for (; i >= 0; i--) {
            newIndex = query.lastIndexOf(delimChar[i]);

            if (newIndex > delimIndex) {
                delimIndex = newIndex;
            }
        }

        if (delimChar[i] == ' ') {
            for (var j = delimChar.length - 1; j >= 0; j--) {
                if (query[delimIndex - 1] == delimChar[j]) {
                    delimIndex--;

                    break;
                }
            }
        }

        if (delimIndex > -1) {
            queryStart = delimIndex + 1;

            while (query.charAt(queryStart) == ' ') {
                queryStart += 1;
            }

            previous = query.substring(0, queryStart);

            query = query.substring(queryStart);
        }
        else {
            previous = '';
        }

        return {
            previous: previous,
            query: query
        };
    },

    /**
     * Focuses the input element.
     *
     * @method _focus
     * @protected
     */
    _focus: function() {
        var instance = this;

        setTimeout(
            function() {
                instance.inputNode.focus();
            },
            1
        );
    },

    /**
     * Called when the user mouses down on the button element in the combobox.
     *
     * @method _onButtonMouseDown
     * @param {EventFacade} event
     * @protected
     */
    _onButtonMouseDown: function(event) {
        var instance = this;

        event.halt();

        instance._focus();

        instance._sendQuery(instance.inputNode.get('value') + '*');
    },

    /**
     * Enables the query to be triggered based on detecting text input via intervals instead of via
     * key events.
     *
     * @method _onInterval
     * @protected
     */
    _onInterval: function() {
        var instance = this;

        var curValue = instance.inputNode.get('value');
        var lastValue = instance._lastValue;

        if (curValue != lastValue) {
            instance._lastValue = curValue;

            instance._sendQuery(curValue);
        }
    },

    /**
     * Handles the input element losing focus.
     *
     * @method _onTextboxBlur
     * @param {EventFacade} event
     * @protected
     */
    _onTextboxBlur: function(event) {
        var instance = this;

        if (!instance._overContainer || KeyMap.isKey(instance._keyCode, TAB)) {
            instance.fire('textboxBlur');
        }
        else {
            instance._focus();
        }
    },

    /**
     * Handles the input element gaining focus.
     *
     * @method _onTextboxFocus
     * @param {EventFacade} event
     * @protected
     */
    _onTextboxFocus: function(event) {
        var instance = this;

        if (!instance.get('focused')) {
            instance.inputNode.setAttribute('autocomplete', 'off');
            instance.focus();
            instance._initInputValue = instance.inputNode.get('value');

            instance.fire('textboxFocus');
        }
    },

    /**
     * Handles the keydown events on the input element for functional keys.
     *
     * @method _onTextboxKeyDown
     * @param {EventFacade} event
     * @protected
     */
    _onTextboxKeyDown: function(event) {
        var instance = this;

        var keyCode = event.keyCode;

        if (instance._typeAheadDelayId != -1) {
            clearTimeout(instance._typeAheadDelayId);
        }

        instance.fire('textboxKeyDown', event);

        if (event.isKey(ALT)) {
            instance._enableIntervalDetection();
        }

        instance._keyCode = keyCode;
    },

    /**
     * Handles the key press events of the input element.
     *
     * @method _onTextboxKeyPress
     * @param {EventFacade} event
     * @protected
     */
    _onTextboxKeyPress: function(event) {
        var instance = this;

        instance.fire('textboxKeyPress', event);

        if (event.isKey(WIN_IME)) {
            instance._enableIntervalDetection();
        }
    },

    /**
     * Handles the keyup events of the input element.
     *
     * @method _onTextboxKeyUp
     * @param {EventFacade} event
     * @protected
     */
    _onTextboxKeyUp: function(event) {
        var instance = this;

        if (event.isSpecialKey() && !event.isKey(BACKSPACE)) {
            return;
        }

        instance.fire('textboxKeyUp', event);
    },

    /**
     * Handles the rendering of the input element.
     *
     * @method _renderInput
     * @protected
     */
    _renderInput: function() {
        var instance = this;

        var contentBox = instance.get(CONTENT_BOX);
        var input = instance.get('input');
        var iconButton = instance.get('iconButton') || ICON_DEFAULT;

        var comboConfig = {
            field: {
                labelText: false
            },
            icons: [
                {
                    icon: iconButton,
                    id: 'trigger',
                    handler: {
                        fn: instance._onButtonMouseDown,
                        context: instance
                    }
    }
   ]
        };

        var inputReference = null;
        var inputParent = null;

        if (input) {
            input = A.one(input);

            comboConfig.field.node = input;

            inputReference = input.next();
            inputParent = input.get('parentNode');
        }

        var comboBox = new A.Combobox(comboConfig).render(contentBox);

        if (inputParent) {
            var comboBoundingBox = comboBox.get('boundingBox');

            inputParent.insertBefore(comboBoundingBox, inputReference);
        }

        instance.inputNode = comboBox.get('node');
        instance.button = comboBox.icons.item('trigger');
        instance.comboBox = comboBox;

        instance.set('uniqueName', A.stamp(instance.inputNode));
    },

    /**
     * Makes a query request to the data source.
     *
     * @method _sendQuery
     * @param {String} query The query string
     * @protected
     */
    _sendQuery: function(query) {
        var instance = this;

        if (instance.get('disabled')) {
            instance.fire('sendQueryDisabled', query);

            return;
        }

        var delimChar = instance.get('delimChar');
        var minQueryLength = instance.get('minQueryLength');

        if (delimChar) {
            var extraction = instance._extractQuery(query);

            query = extraction.query;

            instance._pastSelections = extraction.previous;
        }

        if ((query && (query.length < minQueryLength)) || (!query && minQueryLength > 0)) {
            instance.fire('invalidQueryLength', query);

            return;
        }

        query = encodeURIComponent(query);

        var dataSource = instance.get('dataSource');

        var request = instance.generateRequest(query);

        instance.fire('dataRequest', request);

        dataSource.sendRequest(request);
    },

    /**
     * Updates in the input element with the first result as the user types,
     * selecting the text the user has not typed yet.
     *
     * @method _typeAhead
     * @param {Node} elListItem The selected list item
     * @param {String} query The query string
     * @protected
     */
    _typeAhead: function(elListItem, query) {
        var instance = this;

        if (!instance.get('typeAhead') || KeyMap.isKey(instance._keyCode, BACKSPACE)) {
            return;
        }

        var inputEl = A.Node.getDOMNode(instance.inputNode);

        if (inputEl.setSelectionRange || inputEl.createTextRange) {
            instance._typeAheadDelayId = setTimeout(
                function() {
                    var value = inputEl.value;

                    var start = value.length;

                    instance._updateValue(elListItem);

                    var end = inputEl.value.length;

                    instance.inputNode.selectText(start, end);

                    var prefill = inputEl.value.substr(start, end);

                    instance.fire('typeAhead', query, prefill);
                },
                instance.get('typeAheadDelay')
            );
        }
    },

    _currentQuery: null,
    _initInputValue: null,
    _keyCode: null,
    _lastValue: null,
    _pastSelections: '',
    _typeAheadDelayId: -1
};

A.InputTextControl = InputTextControl;


}, '3.1.0-deprecated.110', {
    "requires": [
        "aui-base-deprecated",
        "aui-datasource-control-base-deprecated",
        "aui-form-combobox-deprecated"
    ]
});
