/**
 * @abstract
 * @class Ext.chart.series.Cartesian
 * @extends Ext.chart.series.Series
 *
 * Common base class for series implementations that plot values using cartesian coordinates.
 *
 * @constructor
 */
Ext.define('Ext.chart.series.Cartesian', {
    extend: 'Ext.chart.series.Series',
    config: {
        /**
         * @cfg {String} xField
         * The field used to access the x axis value from the items from the data source.
         */
        xField: null,

        /**
         * @cfg {String|String[]} yField
         * The field(s) used to access the y-axis value(s) of the items from the data source.
         */
        yField: null,

        /**
         * @cfg {Ext.chart.axis.Axis|Number|String}
         * xAxis The chart axis the series is bound to in the 'X' direction.
         * Normally, this would be set automatically by the series.
         * For charts with multiple x-axes, this defines which x-axis is used by the series.
         * It refers to either axis' ID or the (zero-based) index of the axis
         * in the chart's {@link Ext.chart.AbstractChart#axes axes} config.
         */
        xAxis: null,

        /**
         * @cfg {Ext.chart.axis.Axis|Number|String}
         * yAxis The chart axis the series is bound to in the 'Y' direction.
         * Normally, this would be set automatically by the series.
         * For charts with multiple y-axes, this defines which y-axis is used by the series.
         * It refers to either axis' ID or the (zero-based) index of the axis
         * in the chart's {@link Ext.chart.AbstractChart#axes axes} config.
         */
        yAxis: null
    },

    directions: ['X', 'Y'],

    /**
     * @private
     *
     * Tells which store record fields should be used for a specific axis direction. E.g. for
     *
     *     fieldCategory<direction>: ['<fieldConfig1>', '<fieldConfig2>', ...]
     *
     * the field names from the following configs will be used:
     *
     *     series.<fieldConfig1>Field, series.<fieldConfig2>Field, ...
     *
     * See {@link Ext.chart.series.StackedCartesian#getFields}.
     *
     */
    fieldCategoryX: ['X'],
    fieldCategoryY: ['Y'],

    applyXAxis: function(newAxis, oldAxis) {
        return this.getChart().getAxis(newAxis) || oldAxis;
    },

    applyYAxis: function(newAxis, oldAxis) {
        return this.getChart().getAxis(newAxis) || oldAxis;
    },

    updateXAxis: function(axis) {
        axis.processData(this);
    },

    updateYAxis: function(axis) {
        axis.processData(this);
    },

    coordinateX: function() {
        return this.coordinate('X', 0, 2);
    },

    coordinateY: function() {
        return this.coordinate('Y', 1, 2);
    },

    getItemForPoint: function(x, y) {
        var me = this,
            sprite = me.getSprites()[0],
            store = me.getStore(),
            point;

        if (sprite && !me.getHidden()) {
            point = sprite.getNearestDataPoint(x, y);
        }

        return point
            ? {
                series: me,
                sprite: sprite,
                category: me.getItemInstancing() ? 'items' : 'markers',
                index: point.index,
                record: store.getData().items[point.index],
                field: me.getYField(),
                distance: point.distance
            }
            : null;
    },

    createSprite: function() {
        var me = this,
            sprite = me.callParent(),
            chart = me.getChart(),
            xAxis = me.getXAxis();

        sprite.setAttributes({
            flipXY: chart.getFlipXY(),
            xAxis: xAxis
        });

        if (sprite.setAggregator && xAxis && xAxis.getAggregator) {
            if (xAxis.getAggregator) {
                sprite.setAggregator({ strategy: xAxis.getAggregator() });
            }
            else {
                sprite.setAggregator({});
            }
        }

        return sprite;
    },

    getSprites: function() {
        var me = this,
            chart = this.getChart(),
            sprites = me.sprites;

        if (!chart) {
            return Ext.emptyArray;
        }

        if (!sprites.length) {
            me.createSprite();
        }

        return sprites;
    },

    getXRange: function() {
        return [this.dataRange[0], this.dataRange[2]];
    },

    getYRange: function() {
        return [this.dataRange[1], this.dataRange[3]];
    }
});