/**
 * A chart {@link Ext.AbstractPlugin plugin} that adds ability to listen to chart series
 * items events. Item event listeners are passed two parameters: the target item and the
 * event itself. The item object has the following properties:
 *
 * * **category** - the category the item falls under: 'items' or 'markers'
 * * **field** - the store field used by this series item
 * * **index** - the index of the series item
 * * **record** - the store record associated with this series item
 * * **series** - the series the item belongs to
 * * **sprite** - the sprite used to represents this series item
 *
 * For example:
 *
 *     Ext.create('Ext.chart.CartesianChart', {
 *         plugins: {
 *             chartitemevents: {
 *                 moveEvents: true
 *             }
 *         },
 *         store: {
 *             fields: ['pet', 'households', 'total'],
 *             data: [
 *                 {pet: 'Cats', households: 38, total: 93},
 *                 {pet: 'Dogs', households: 45, total: 79},
 *                 {pet: 'Fish', households: 13, total: 171}
 *             ]
 *         },
 *         axes: [{
 *             type: 'numeric',
 *             position: 'left'
 *         }, {
 *             type: 'category',
 *             position: 'bottom'
 *         }],
 *         series: [{
 *             type: 'bar',
 *             xField: 'pet',
 *             yField: 'households',
 *             listeners: {
 *                 itemmousemove: function (series, item, event) {
*                      console.log('itemmousemove', item.category, item.field);
 *                 }
 *             }
 *         }, {
 *             type: 'line',
 *             xField: 'pet',
 *             yField: 'total',
 *             marker: true
 *         }],
 *         listeners: { // Listen to itemclick events on all series.
 *             itemclick: function (chart, item, event) {
 *                 console.log('itemclick', item.category, item.field);
 *             }
 *         }
 *     });
 *
 */
Ext.define('Ext.chart.plugin.ItemEvents', {
    extend: 'Ext.plugin.Abstract',
    alias: 'plugin.chartitemevents',
 
    /**
     * @cfg {Boolean} [moveEvents=false]
     * If `itemmousemove`, `itemmouseover` or `itemmouseout` event listeners are attached
     * to the chart, the plugin will detect those and will hit test series items on
     * every move. However, if the above item events are attached on the series level
     * only, this config has to be set to true, as the plugin won't perform a similar
     * detection on every series.
     */
    moveEvents: false,
 
    mouseMoveEvents: {
        mousemove: true,
        mouseover: true,
        mouseout: true
    },
 
    itemMouseMoveEvents: {
        itemmousemove: true,
        itemmouseover: true,
        itemmouseout: true
    },
 
    init: function (chart) {
        var handleEvent = 'handleEvent';
 
        this.chart = chart;
 
        chart.addElementListener({
            click: handleEvent,
            tap: handleEvent,
            dblclick: handleEvent,
            mousedown: handleEvent,
            mousemove: handleEvent,
            mouseup: handleEvent,
            mouseover: handleEvent,
            mouseout: handleEvent,
            // run our handlers before user code
            priority: 1001,
            scope: this
        });
    },
 
    hasItemMouseMoveListeners: function () {
        var listeners = this.chart.hasListeners,
            name;
        for (name in this.itemMouseMoveEvents) {
            if (name in listeners) {
                return true;
            }
        }
        return false;
    },
 
    handleEvent: function (e) {
        var me = this,
            chart = me.chart,
            isMouseMoveEvent = e.type in me.mouseMoveEvents,
            lastItem = me.lastItem,
            chartXY, item;
 
        if (isMouseMoveEvent && !me.hasItemMouseMoveListeners() && !me.moveEvents) {
            return;
        }
 
        chartXY = chart.getEventXY(e);
        item = chart.getItemForPoint(chartXY[0], chartXY[1]);
 
        if (isMouseMoveEvent && !Ext.Object.equals(item, lastItem)) {
            if (lastItem) {
                chart.fireEvent('itemmouseout', chart, lastItem, e);
                lastItem.series.fireEvent('itemmouseout', lastItem.series, lastItem, e);
            }
            if (item) {
                chart.fireEvent('itemmouseover', chart, item, e);
                item.series.fireEvent('itemmouseover', item.series, item, e);
            }
        }
 
        if (item) {
            chart.fireEvent('item' + e.type, chart, item, e);
            item.series.fireEvent('item' + e.type, item.series, item, e);
        }
 
        me.lastItem = item;
    }
});