/**
 * @class Ext.chart.series.sprite.CandleStick
 * @extends Ext.chart.series.sprite.Aggregative
 * 
 * CandleStick series sprite.
 */
Ext.define('Ext.chart.series.sprite.CandleStick', {
    alias: 'sprite.candlestickSeries',
    extend: 'Ext.chart.series.sprite.Aggregative',
    inheritableStatics: {
        def: {
            processors: {
                raiseStyle: function (n, o) {
                    return Ext.merge({}, o || {}, n);
                },
                dropStyle: function (n, o) {
                    return Ext.merge({}, o || {}, n);
                },
 
                /**
                 * @cfg {Number} [barWidth=15] The bar width of the candles.
                 */
                barWidth: 'number',
 
                /**
                 * @cfg {Number} [padding=3] The amount of padding between candles.
                 */
                padding: 'number',
 
                /**
                 * @cfg {String} [ohlcType='candlestick'] Determines whether candlestick or ohlc is used.
                 */
                ohlcType: 'enums(candlestick,ohlc)'
            },
            defaults: {
                raiseStyle: {
                    strokeStyle: 'green',
                    fillStyle: 'green'
                },
                dropStyle: {
                    strokeStyle: 'red',
                    fillStyle: 'red'
                },
                planar: false,
                barWidth: 15,
                padding: 3,
                lineJoin: 'miter',
                miterLimit: 5,
                ohlcType: 'candlestick'
            },
 
            triggers: {
                raiseStyle: 'raiseStyle',
                dropStyle: 'dropStyle'
            },
 
            updaters: {
                raiseStyle: function () {
                    this.raiseTemplate && this.raiseTemplate.setAttributes(this.attr.raiseStyle);
                },
                dropStyle: function () {
                    this.dropTemplate && this.dropTemplate.setAttributes(this.attr.dropStyle);
                }
            }
        }
    },
 
    candlestick: function (ctx, open, high, low, close, mid, halfWidth) {
        var minOC = Math.min(open, close),
            maxOC = Math.max(open, close);
        ctx.moveTo(mid, low);
        ctx.lineTo(mid, maxOC);
 
        ctx.moveTo(mid + halfWidth, maxOC);
        ctx.lineTo(mid + halfWidth, minOC);
        ctx.lineTo(mid - halfWidth, minOC);
        ctx.lineTo(mid - halfWidth, maxOC);
        ctx.closePath();
 
        ctx.moveTo(mid, high);
        ctx.lineTo(mid, minOC);
    },
 
    ohlc: function (ctx, open, high, low, close, mid, halfWidth) {
        ctx.moveTo(mid, high);
        ctx.lineTo(mid, low);
        ctx.moveTo(mid, open);
        ctx.lineTo(mid - halfWidth, open);
        ctx.moveTo(mid, close);
        ctx.lineTo(mid + halfWidth, close);
    },
 
    constructor: function () {
        this.callParent(arguments);
        this.raiseTemplate = new Ext.draw.sprite.Rect({parent: this});
        this.dropTemplate = new Ext.draw.sprite.Rect({parent: this});
    },
 
    getGapWidth: function () {
        var attr = this.attr,
            barWidth = attr.barWidth,
            padding = attr.padding;
        return barWidth + padding;
    },
 
    renderAggregates: function (aggregates, start, end, surface, ctx, clip) {
        var me = this,
            attr = this.attr,
            dataX = attr.dataX,
            matrix = attr.matrix,
            xx = matrix.getXX(),
            yy = matrix.getYY(),
            dx = matrix.getDX(),
            dy = matrix.getDY(),
            barWidth = attr.barWidth / xx,
            template,
            ohlcType = attr.ohlcType,
            halfWidth = Math.round(barWidth * 0.5 * xx),
            opens = aggregates.open,
            closes = aggregates.close,
            maxYs = aggregates.maxY,
            minYs = aggregates.minY,
            startIdxs = aggregates.startIdx,
            open, high, low, close, mid,
            i,
            pixelAdjust = attr.lineWidth * surface.devicePixelRatio / 2;
 
        pixelAdjust -= Math.floor(pixelAdjust);
        ctx.save();
        template = this.raiseTemplate;
        template.useAttributes(ctx, clip);
        ctx.beginPath();
        for (= start; i < end; i++) {
            if (opens[i] <= closes[i]) {
                open = Math.round(opens[i] * yy + dy) + pixelAdjust;
                high = Math.round(maxYs[i] * yy + dy) + pixelAdjust;
                low = Math.round(minYs[i] * yy + dy) + pixelAdjust;
                close = Math.round(closes[i] * yy + dy) + pixelAdjust;
                mid = Math.round(dataX[startIdxs[i]] * xx + dx) + pixelAdjust;
                me[ohlcType](ctx, open, high, low, close, mid, halfWidth);
            }
        }
        ctx.fillStroke(template.attr);
        ctx.restore();
 
        ctx.save();
        template = this.dropTemplate;
        template.useAttributes(ctx, clip);
        ctx.beginPath();
        for (= start; i < end; i++) {
            if (opens[i] > closes[i]) {
                open = Math.round(opens[i] * yy + dy) + pixelAdjust;
                high = Math.round(maxYs[i] * yy + dy) + pixelAdjust;
                low = Math.round(minYs[i] * yy + dy) + pixelAdjust;
                close = Math.round(closes[i] * yy + dy) + pixelAdjust;
                mid = Math.round(dataX[startIdxs[i]] * xx + dx) + pixelAdjust;
                me[ohlcType](ctx, open, high, low, close, mid, halfWidth);
            }
        }
        ctx.fillStroke(template.attr);
        ctx.restore();
    }
});