/**
 * This mixin defines certain config options, properties, and APIs to be used
 * by Components that implement accessible traits according to WAI-ARIA 1.0 specification.
 *
 * @private
 */
Ext.define('Ext.mixin.Accessible', {
    extend: 'Ext.Mixin',
    
    mixinConfig: {
        id: 'accessible'
    },
    
    /**
     * @cfg {String} [ariaLabel] ARIA label for this Component. It is best to use
     * {@link #ariaLabelledBy} option instead, because screen readers prefer
     * `aria-labelledby` attribute to `aria-label`. {@link #ariaLabel} and
     * {@link #ariaLabelledBy} config options are mutually exclusive.
     */
    
    /**
     * @cfg {String} [ariaLabelledBy] DOM selector for a child element that is to be used
     * as label for this Component, set in `aria-labelledby` attribute.
     * If the selector is by `#id`, the label element can be any existing element,
     * not necessarily a child of the main Component element.
     *
     * {@link #ariaLabelledBy} and {@link #ariaLabel} config options are
     * mutually exclusive, and `ariaLabelledBy` has the higher precedence.
     */
    
    /**
     * @cfg {String} [ariaDescribedBy] DOM selector for a child element that is to be used
     * as description for this Component, set in `aria-describedby` attribute.
     * The selector works the same way as {@link #ariaLabelledBy}.
     */
    
    config: {
        /**
         * @cfg {Object} ariaAttributes An object containing ARIA attributes to be set
         * on this Component's ARIA element. Use this to set the attributes that cannot be
         * determined by the Component's state, such as `aria-live`, `aria-flowto`, etc.
         *
         * **Note** that this config is only meaningful at the Component rendering time,
         * and setting it after that will do nothing.
         */
        ariaAttributes: {
            $value: null,
            lazy: true
        }
    },
    
    /**
     * @property {String} [ariaRole] ARIA role for this Component, defaults to no role.
     * With no role, no other ARIA attributes are set.
     *
     * @readonly
     */
    
    /**
     * @property {Object} [ariaRenderAttributes] **Instance specific** ARIA attributes
     * to render into Component's ariaEl. This object is only used during rendering,
     * and is discarded afterwards.
     *
     * @private
     */
    
    privates: {
        /**
         * Find component(s) that label or describe this component,
         * and return the id(s) of their ariaEl elements.
         *
         * @param {Function/String/String[]} [reference] Component reference,
         * or array of component references, or a function that should return
         * the proper attribute string. The function will be called in the
         * context of the labelled component.
         *
         * @return {Ext.Element} Element id string, or null
         * @private
         */
        getAriaLabelEl: function(selector) {
            var ids = [],
                refHolder, i, len, cmp, result;
            
            if (selector) {
                if (Ext.isFunction(selector)) {
                    return selector.call(this);
                }
                else {
                    if (!Ext.isArray(selector)) {
                        selector = [selector];
                    }
                    
                    refHolder = this.lookupReferenceHolder();
                    
                    if (refHolder) {
                        for (i = 0, len = selector.length; i < len; i++) {
                            cmp = refHolder.lookupReference(selector[i]);
                            
                            if (cmp) {
                                ids.push(cmp.ariaEl.id);
                            }
                        }
                    }
                }
            }
        
            return ids.length ? ids.join(' ') : null;
        }
    }
});
