/**
 * Text Field {@link Ext.field.Text#triggers trigger} widget.
 */
Ext.define('Ext.field.trigger.Trigger', {
    extend: 'Ext.Widget',
    xtype: 'trigger',
    alias: 'trigger.trigger',
 
    requires: [
        'Ext.util.TapRepeater'
    ],
 
    mixins: [
        'Ext.mixin.Factoryable'
    ],
 
    factoryConfig: {
        defaultType: 'trigger',
        aliasPrefix: 'trigger.'
    },
 
    config: {
        /**
         * @cfg {Ext.field.Text} 
         * The text field that created this trigger
         * @private
         */
        field: null,
 
        /**
         * @cfg {String} [group]
         * The name of an optional group trigger that this trigger belongs to.  If no trigger
         * Exists by that name one will automatically be created.  A group trigger is a
         * special trigger that contains other triggers.  Those triggers' elements are
         * appended to the group trigger's element in the DOM.
         *
         * The {@link #weight} of grouped triggers is relative to other triggers in the group.
         */
        group: null,
 
        /**
         * @cfg {Function/String} [handler=undefined]
         * Function to run when trigger is clicked or tapped.
         * @controllable
         */
        handler: null,
 
        /**
         * @cfg {Boolean/Object}
         * `true` to attach a {@link Ext.util.TapRepeater tap repeater} to the trigger,
         * or a config object for a tap repeater.
         */
        repeat: null,
 
        /**
         * @cfg {'left'/'right'} [side='right']
         * The side of the text field's input to render the trigger on.
         */
        side: null,
 
        /**
         * @cfg {Object} [scope]
         * Execution context for the {@link #handler} function.
         */
        scope: null,
 
        /**
         * The triggers contained in this trigger (only applicable for trigger groups)
         * @private
         */
        triggers: null,
 
        weight: null
    },
 
    classCls: Ext.baseCSSPrefix + 'trigger',
    interactiveCls: Ext.baseCSSPrefix + 'interactive',
    groupedCls: Ext.baseCSSPrefix + 'grouped',
 
    template: [{
        reference: 'iconElement',
        classList: [
            Ext.baseCSSPrefix + 'icon-el',
            Ext.baseCSSPrefix + 'font-icon'
        ]
    }],
 
    statics: {
        /**
         * Sorts an array of triggers in place by weight
         * @param {Ext.field.Trigger[]} triggers 
         * @return {Ext.field.Trigger[]} 
         * @private
         * @static
         */
        sort: function(triggers) {
            Ext.Array.sort(triggers, this.weightComparator);
            return triggers;
        },
 
        /**
         * Comparison function for sorting an array of triggers in ascending order
         * @param {Ext.form.field.Trigger} triggerA 
         * @param {Ext.form.field.Trigger} triggerB 
         * @return {Number} 
         * @private
         * @static
         */
        weightComparator: function(triggerA, triggerB) {
            return (triggerA.getWeight() || 0) - (triggerB.getWeight() || 0);
        }
    },
 
    constructor: function(config) {
        var me = this,
            element, repeat;
 
        me.callParent([config]);
 
        element = me.element;
        repeat = me.getRepeat();
 
        if (repeat) {
            me.repeater = new Ext.util.TapRepeater(Ext.apply({
                el: element
            }, repeat));
 
            me.repeater.on('tap', 'onClick', this);
        } else {
            element.on('click', 'onClick', this);
        }
    },
 
    doDestroy: function() {
        var triggers = this.getTriggers(),
            i, ln;
 
        if (triggers) {
            for (= 0, ln = triggers.length; i < ln; i++) {
                triggers[i].destroy();
            }
        }
 
        this.setTriggers(null);
        Ext.destroyMembers(this, 'repeater');
        this.callParent();
    },
 
    onClick: function(e) {
        var me = this,
            handler = me.getHandler(),
            field = me.getField();
 
        // TODO: skip this if readonly? !editable?
        if (handler) {
            Ext.callback(handler, me.getScope(), [field, me, e], null, field);
        }
    },
 
    updateHandler: function(handler) {
        this.toggleCls(this.interactiveCls, !!handler);
    },
 
    updateGroup: function(group) {
        if (!this.isConfiguring) {
            this.getField().syncTriggers();
        }
    },
 
    updateSide: function() {
        if (!this.isConfiguring) {
            this.getField().syncTriggers();
        }
    },
 
    updateTriggers: function(triggers) {
        var me = this,
            dom = me.element.dom,
            iconElement = me.iconElement,
            i, ln;
 
        me.toggleCls(me.groupedCls, !!(triggers && triggers.length));
 
        if (triggers) {
            // group triggers do not have icons of their own, so we can safely remove the iconElement
            if (iconElement) {
                iconElement.destroy();
                me.iconElement = null;
                Ext.Array.remove(me.referenceList, 'iconElement');
            }
 
            for (= 0, ln = triggers.length; i < ln; i++) {
                dom.appendChild(triggers[i].element.dom);
            }
        }
    }
 
});