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),

    ACTIVE_INPUT = 'activeInput',
    BLUR = 'blur',
    CLICK = 'click',
    CONTAINER = 'container',
    DATE_SEPARATOR = 'dateSeparator',
    DATEPICKER_SELECTION = 'datepickerSelection',
    FOCUS = 'focus',
    MASK = 'mask',
    MOUSEDOWN = 'mousedown',
    SELECTION_CHANGE = 'selectionChange',
    TRIGGER = 'trigger',
    VALUE_EXTRACTOR = 'valueExtractor',
    VALUE_FORMATTER = 'valueFormatter';

/**
 * A base class for DatePickerDelegate.
 *
 * @class A.DatePickerDelegate
 * @param config {Object} 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 AutosizeIframe class. Lifecycle.
     *
     * @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(
            SELECTION_CHANGE, {
                defaultFn: instance._defSelectionChangeFn
            }
        );
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method getSelectedDates
     * @param node
     */
    getSelectedDates: function(node) {
        var instance = this,
            activeInput = node || instance.get(ACTIVE_INPUT),
            selectedDates = null;

        if (activeInput) {
            selectedDates = activeInput.getData(DATEPICKER_SELECTION);
        }

        return selectedDates;
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method getParsedDatesFromInputValue
     * @param opt_value
     */
    getParsedDatesFromInputValue: function(opt_value) {
        var instance = this,
            valueExtractor = instance.get(VALUE_EXTRACTOR),
            parsedDates = valueExtractor.call(instance, opt_value);

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

        return null;
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method useInputNode
     */
    useInputNode: function() {},

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @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(ACTIVE_INPUT),
            valueFormatter = instance.get(VALUE_FORMATTER);

        valueFormatter.call(instance, selection);

        activeInput.setData(DATEPICKER_SELECTION, selection);
    },

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

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

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

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method _formatDate
     * @param event
     * @protected
     */
    _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;

        instance._focusActiveCalendar();
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method _onceUserInteractionRelease
     * @param event
     * @protected
     */
    _onceUserInteractionRelease: function(event) {
        var instance = this;

        instance.useInputNodeOnce(event.currentTarget);

        instance._userInteractionInProgress = false;
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method _onUserInteractionRelease
     * @param event
     * @protected
     */
    _onUserInteractionRelease: function(event) {
        var instance = this;

        instance.useInputNode(event.currentTarget);

        instance._userInteractionInProgress = false;
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method _valueExtractorFn
     * @protected
     */
    _valueExtractorFn: function() {
        return function(opt_value) {
            var instance = this,
                activeInput = instance.get(ACTIVE_INPUT),
                activeInputValue = Lang.trim(opt_value || activeInput.val()),
                dateSeparator = instance.get(DATE_SEPARATOR),
                mask = instance.get(MASK),
                dates;

            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;
        };
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method _valueFormatterFn
     * @protected
     */
    _valueFormatterFn: function() {
        return function(dates) {
            var instance = this,
                activeInput = instance.get(ACTIVE_INPUT),
                dateSeparator = instance.get(DATE_SEPARATOR),
                values = [];

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

            activeInput.val(values.join(dateSeparator));
        };
    }
};

/**
 * TODO. Wanna help? Please send a Pull Request.
 *
 * @property DatePickerDelegate.ATTRS
 * @type Object
 * @static
 */
DatePickerDelegate.ATTRS = {

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

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @attribute container
     * @writeOnce
     */
    container: {
        setter: A.one,
        value: _DOCUMENT,
        writeOnce: true
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @attribute dateSeparator
     * @default ' \u2014 '
     * @type String
     */
    dateSeparator: {
        value: ' \u2014 ',
        validator: Lang.isString
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @attribute mask
     * @default '%m/%d/%Y'
     * @type String
     */
    mask: {
        value: '%m/%d/%Y',
        validator: Lang.isString
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @attribute content
     * @type String
     */
    trigger: {
        validator: isString,
        writeOnce: true
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @attribute valueExtractor
     * @type Function
     */
    valueExtractor: {
        valueFn: '_valueExtractorFn',
        validator: Lang.isFunction
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @attribute valueFormatter
     * @type Function
     */
    valueFormatter: {
        valueFn: '_valueFormatterFn',
        validator: Lang.isFunction
    }
};

A.DatePickerDelegate = DatePickerDelegate;

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