YUI.add('aui-datepicker-delegate', function (A, NAME) {

/**
 * The DatePicker Component
 *
 * @module aui-datepicker
 * @submodule aui-datepicker-delegate
 */

var Lang = A.Lang,
    isString = Lang.isString,

    EVENT_ENTER_KEY = 'enterKey',
    EVENT_TAB_KEY = 'tabKey',

    _DOCUMENT = A.one(A.config.doc);

/**
 * Fired when then enter key is pressed on an input node.
 *
 * @event enterKey
 */

/**
 * A base class for `DatePickerDelegate`.
 *
 * @class A.DatePickerDelegate
 * @param {Object} config Object literal specifying widget configuration
 *     properties.
 * @constructor
 */

function DatePickerDelegate() {}

DatePickerDelegate.prototype = {
    _eventHandles: null,

    _userInteractionInProgress: false,

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

        instance.bindDelegateUI();
    },

    /**
     * Destructor logic implementation for the `DatePickerDelegate` class.
     *
     * @method destroy
     * @protected
     */
    destroy: function() {
        var instance = this;

        (new A.EventHandle(instance._eventHandles)).detach();
    },

    /**
     * Bind the events on the `DatePickerDelegate` UI. Lifecycle.
     *
     * @method bindDelegateUI
     * @protected
     */
    bindDelegateUI: function() {
        var instance = this,
            container = instance.get('container'),
            trigger = instance.get('trigger');

        instance._eventHandles = [
            container.delegate(
                ['focus', 'mousedown'],
                A.bind('_onceUserInteraction', instance), trigger),

            container.delegate(
                'blur',
                A.bind('_onUserInteractionRelease', instance), trigger),

            container.delegate(
                'click',
                A.bind('_onceUserInteractionRelease', instance), trigger),

            container.delegate(
                'key',
                A.bind('_handleTabKeyEvent', instance), 'tab', trigger),

            container.delegate(
                'key',
                A.bind('_handleEnterKeyEvent', instance), 'enter', trigger)

        ];

        instance.after(
            'activeInputChange',
            A.bind('_afterActiveInputChange', instance));

        instance.publish(
            'selectionChange', {
                defaultFn: instance._defSelectionChangeFn
            }
        );
    },

    /**
     * Method not implemented.
     *
     * @method focusSelectedValue
     */
    focusSelectedValue: function() {},

    /**
     * Gets the selected dates.
     *
     * @method getSelectedDates
     * @param node
     * @return {Object | null}
     */
    getSelectedDates: function(node) {
        var instance = this,
            activeInput = node || instance.get('activeInput'),
            selectedDates = null;

        if (activeInput) {
            selectedDates = activeInput.getData('datepickerSelection');
        }

        return selectedDates;
    },

    /**
     * Gets parsed dates from input value.
     *
     * @method getParsedDatesFromInputValue
     * @param opt_value
     * @return {Object | null}
     */
    getParsedDatesFromInputValue: function(opt_value) {
        var instance = this,
            valueExtractor = instance.get('valueExtractor'),
            parsedDates = valueExtractor.call(instance, opt_value);

        if (parsedDates) {
            return A.Array.filter(parsedDates, function(parsed) {
                return parsed !== false;
            });
        }

       return null;
    },

    /**
     * Method not implemented.
     *
     * @method useInputNode
     */
    useInputNode: function() {},

    /**
     * Triggers `useInputNode` method once.
     *
     * @method useInputNodeOnce
     * @param node
     */
    useInputNodeOnce: function(node) {
        var instance = this;

        if (!instance._userInteractionInProgress) {
            instance.useInputNode(node);
        }
    },

    /**
    * Fires when the 'activeInput' attribute changes.  The keydown listener is
    * removed from the old active input and is attached to the new one.
    *
    * @method _afterActiveInputChange
    * @param {EventFacade} event
    * @protected
    */
    _afterActiveInputChange: function(event) {
        var instance = this;

        if (event.prevVal) {
            event.prevVal.detach(
                'keydown', instance._handleKeydownEvent, instance);
        }

        if (event.newVal) {
            event.newVal.on('keydown', instance._handleKeydownEvent, instance);
        }
    },

    /**
     * Default behavior for selection change.
     *
     * @method _defSelectionChangeFn
     * @param event
     * @protected
     */
    _defSelectionChangeFn: function(event) {
        var instance = this,
            selection = event.newSelection,
            activeInput = instance.get('activeInput'),
            valueFormatter = instance.get('valueFormatter');

        valueFormatter.call(instance, selection);

        if (activeInput) {
            activeInput.setData('datepickerSelection', selection);
        }
    },

    /**
     * Focus on active calendar.
     *
     * @method _focusActiveCalendar
     * @protected
     */
    _focusActiveCalendar: function() {
        var instance = this;

        if (instance.calendar) {
            var calendar = instance.getCalendar();

            calendar.get('boundingBox').focus();
        }
    },

    /**
     * Formats a date according to a mask.
     *
     * @method _formatDate
     * @param event
     * @protected
     * @return {Date}
     */
    _formatDate: function(date) {
        var instance = this,
            mask = instance.get('mask');

        return A.Date.format(
            date,
            {
                format: mask
            }
        );
    },


    /**
    * Handles keydown events
    *
    * @method _handleKeydownEvent
    * @param event
    * @protected
    */
    _handleKeydownEvent: function(event) {
        var instance = this;

        if (event.isKey('enter')) {
            instance.fire(EVENT_ENTER_KEY);
        }
        else if (event.isKey('tab')) {
            instance.fire(EVENT_TAB_KEY);
        }
    },

    /**
     * Handles tab key events
     *
     * @method _handleTabKeyEvent
     * @param event
     * @protected
     */
    _handleTabKeyEvent: function(event) {
        var instance = this;

        instance._focusActiveCalendar();
    },

    /**
     * Handles enter key events
     *
     * @method _handleEnterKeyEvent
     * @param event
     * @protected
     */
    _handleEnterKeyEvent: function(event) {
        var instance = this;

        event.preventDefault();

        instance.show();
    },

    /**
     * Fires once user interacts.
     *
     * @method _onceUserInteraction
     * @param event
     * @protected
     */
    _onceUserInteraction: function(event) {
        var instance = this;

        instance.useInputNodeOnce(event.currentTarget);

        instance._userInteractionInProgress = true;
    },

    /**
     * Fires once user interaction releases.
     *
     * @method _onceUserInteractionRelease
     * @param event
     * @protected
     */
    _onceUserInteractionRelease: function(event) {
        var instance = this;

        instance.useInputNodeOnce(event.currentTarget);

        instance.focusSelectedValue();

        instance._userInteractionInProgress = false;
    },

    /**
     * Fires when user interaction releases.
     *
     * @method _onUserInteractionRelease
     * @param event
     * @protected
     */
    _onUserInteractionRelease: function(event) {
        var instance = this;

        instance.useInputNode(event.currentTarget);

        instance._userInteractionInProgress = false;
    },

    /**
     * Extracts the input value.
     *
     * @method _valueExtractorFn
     * @protected
     */
    _valueExtractorFn: function() {
        return function(opt_value) {
            var instance = this,
                activeInput = instance.get('activeInput'),
                activeInputVal,
                activeInputValue,
                dateSeparator = instance.get('dateSeparator'),
                mask = instance.get('mask'),
                dates;

            if (activeInput) {
                activeInputVal = activeInput.val();
            }

            activeInputValue = Lang.trim(opt_value || activeInputVal);

            if (activeInputValue) {
                dates = [];

                A.Array.each(
                    activeInputValue.split(dateSeparator),
                    function(text) {
                        text = Lang.trim(text);

                        if (text) {
                            dates.push(A.Date.parse(mask, text));
                        }
                    }
                );
            }

            return dates;
        };
    },

    /**
     * Formats a date value.
     *
     * @method _valueFormatterFn
     * @protected
     * @return {Function}
     */
    _valueFormatterFn: function() {
        return function(dates) {
            var instance = this,
                activeInput = instance.get('activeInput'),
                dateSeparator = instance.get('dateSeparator'),
                values = [];

            A.Array.each(dates, function(date) {
                values.push(instance._formatDate(date));
            });

            if (activeInput) {
                activeInput.val(values.join(dateSeparator));
            }
        };
    },
};

/**
 * Static property used to define the default attribute configuration for the
 * `DatePickerDelegate`.
 *
 * @property ATTRS
 * @type {Object}
 * @static
 */
DatePickerDelegate.ATTRS = {

    /**
     * The active input element that holds the calendar instance.
     *
     * @attribute activeInput
     */
    activeInput: {},

    /**
     * Contains an element.
     *
     * @attribute container
     * @writeOnce
     */
    container: {
        setter: A.one,
        value: _DOCUMENT,
        writeOnce: true
    },

    /**
     * Character that separate dates.
     *
     * @attribute dateSeparator
     * @default ' \u2014 '
     * @type {String}
     */
    dateSeparator: {
        value: ' \u2014 ',
        validator: Lang.isString
    },

    /**
     * Defines the date format.
     *
     * @attribute mask
     * @default '%m/%d/%Y'
     * @type {String}
     */
    mask: {
        value: '%m/%d/%Y',
        validator: Lang.isString
    },

    /**
     * Stores a trigger.
     *
     * @attribute trigger
     * @type {String}
     * @writeOnce
     */
    trigger: {
        validator: isString,
        writeOnce: true
    },

    /**
     * Extracts a value from a function.
     *
     * @attribute valueExtractor
     * @type {Function}
     */
    valueExtractor: {
        valueFn: '_valueExtractorFn',
        validator: Lang.isFunction
    },

    /**
     * Formats a value from a function.
     *
     * @attribute valueFormatter
     * @type {Function}
     */
    valueFormatter: {
        valueFn: '_valueFormatterFn',
        validator: Lang.isFunction
    }
};

A.DatePickerDelegate = DatePickerDelegate;

}, '3.1.0-deprecated.112', {"requires": ["aui-datatype-date-parse", "aui-event-input", "event-focus", "node-event-delegate"]});
