"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ErrorSeriesDrawingProvider = void 0;
var vectorToArray_1 = require("../../../../utils/vectorToArray");
var Deleter_1 = require("../../../../Core/Deleter");
var Rect_1 = require("../../../../Core/Rect");
var AxisType_1 = require("../../../../types/AxisType");
var ErrorDirection_1 = require("../../../../types/ErrorDirection");
var ErrorMode_1 = require("../../../../types/ErrorMode");
var Pen2DCache_1 = require("../../../Drawing/Pen2DCache");
var WebGlRenderContext2D_1 = require("../../../Drawing/WebGlRenderContext2D");
var LogarithmicAxis_1 = require("../../Axis/LogarithmicAxis");
var NativeObject_1 = require("../../Helpers/NativeObject");
var constants_1 = require("../constants");
var BaseSeriesDrawingProvider_1 = require("./BaseSeriesDrawingProvider");
/**
 * Used internally - a drawing provider performs drawing for a {@link BaseBandRenderableSeries} using
 * our WebAssembly WebGL rendering engine
 */
var ErrorSeriesDrawingProvider = /** @class */ (function (_super) {
    __extends(ErrorSeriesDrawingProvider, _super);
    /**
     * Creates an instance of the {@link BandSeriesDrawingProvider}
     * @param webAssemblyContext The {@link TSciChart | SciChart 2D WebAssembly Context} containing native methods and
     * access to our WebGL2 Engine and WebAssembly numerical methods
     * @param parentSeries the parent {@link BaseBandRenderableSeries} which this drawing provider is attached to
     */
    function ErrorSeriesDrawingProvider(webAssemblyContext, parentSeries) {
        var _this = _super.call(this, webAssemblyContext, parentSeries) || this;
        _this.linesPenCache = new Pen2DCache_1.Pen2DCache(webAssemblyContext);
        _this.tempXVec = new _this.webAssemblyContext.SCRTDoubleVector();
        _this.tempYVec = new _this.webAssemblyContext.SCRTDoubleVector();
        return _this;
    }
    /**
     * @inheritDoc
     */
    ErrorSeriesDrawingProvider.prototype.onAttachSeries = function () {
        _super.prototype.onAttachSeries.call(this);
        this.args = new this.webAssemblyContext.SCRTLineDrawingParams();
        this.nativeDrawingProvider = new this.webAssemblyContext.SCRTLineSegmentDrawingProvider();
        var _a = this.parentSeries, stroke = _a.stroke, strokeThickness = _a.strokeThickness, opacity = _a.opacity, strokeDashArray = _a.strokeDashArray;
        (0, Pen2DCache_1.createPenInCache)(this.linesPenCache, stroke, strokeThickness, opacity, strokeDashArray);
    };
    /**
     * @inheritDoc
     */
    ErrorSeriesDrawingProvider.prototype.onDetachSeries = function () {
        _super.prototype.onDetachSeries.call(this);
    };
    /**
     * @inheritDoc
     */
    ErrorSeriesDrawingProvider.prototype.delete = function () {
        this.nativeDrawingProvider = (0, Deleter_1.deleteSafe)(this.nativeDrawingProvider);
        this.linesPenCache = (0, Deleter_1.deleteSafe)(this.linesPenCache);
        this.args = (0, Deleter_1.deleteSafe)(this.args);
        this.tempXVec = (0, Deleter_1.deleteSafe)(this.tempXVec);
        this.tempYVec = (0, Deleter_1.deleteSafe)(this.tempYVec);
        _super.prototype.delete.call(this);
    };
    /**
     * @inheritDoc
     */
    ErrorSeriesDrawingProvider.prototype.draw = function (renderContext, renderPassData) {
        var linesPen = (0, Pen2DCache_1.getScrtPenFromCache)(this.linesPenCache);
        if (!linesPen || linesPen.GetThickness() === 0.0) {
            return;
        }
        var pointSeries = renderPassData.pointSeries;
        var vertices = (0, NativeObject_1.getVectorColorVertex)(this.webAssemblyContext);
        // this.xLineCoordinates.clear();
        // this.yLineCoordinates.clear();
        // this.args.Reset();
        // this.args.SetLinesPen(linesPen);
        // this.args.isDigitalLine = this.parentSeries.isDigitalLine;
        // this.args.forceShaderMethod = true;
        // this.args.containsNaN = true;
        // this.args.lineGaps = this.webAssemblyContext.SCRTLineGapMode.DrawGaps;
        // this.args.verticalChart = renderPassData.isVerticalChart;
        // // Stroke paletting per point
        // this.applyStrokePaletting(linesPen);
        // if (this.palettingState.palettedColors) {
        //     this.args.SetPalettedColors(this.palettingState.palettedColors);
        // }
        // const nativeContext = renderContext.getNativeContext();
        var isCategoryAxis = renderPassData.xCoordinateCalculator.isCategoryCoordinateCalculator;
        var xValues = pointSeries.xValues;
        var xDrawValues = isCategoryAxis ? pointSeries.indexes : xValues;
        var yDrawValues = pointSeries.yValues;
        var hDrawValues = pointSeries.highValues;
        var lDrawValues = pointSeries.lowValues;
        var isVerticalDirection = this.parentSeries.errorDirection === ErrorDirection_1.EErrorDirection.Vertical;
        var dataPointWidthCalc = isVerticalDirection
            ? renderPassData.xCoordinateCalculator
            : renderPassData.yCoordinateCalculator;
        var dataPointWidthPx = this.parentSeries.getDataPointWidth(dataPointWidthCalc, this.parentSeries.dataPointWidth, this.parentSeries.dataPointWidthMode);
        var dataPointWidth = dataPointWidthCalc.getDataWidth(dataPointWidthPx);
        var halfRange = dataPointWidthPx * 0.5;
        var hasLogarithmicXAxis = this.parentSeries.xAxis.type === AxisType_1.EAxisType.LogarithmicAxis;
        var hasLogarithmicYAxis = this.parentSeries.yAxis.type === AxisType_1.EAxisType.LogarithmicAxis;
        var hasNegativeLogXAxis = this.parentSeries.xAxis.isNegative;
        var hasNegativeLogYAxis = this.parentSeries.yAxis.isNegative;
        var hasHighCap = this.parentSeries.errorMode !== ErrorMode_1.EErrorMode.Low;
        var hasLowCap = this.parentSeries.errorMode !== ErrorMode_1.EErrorMode.High;
        var dataPointsCount = xDrawValues.size();
        var xView = (0, vectorToArray_1.vectorToArrayViewF64)(xDrawValues, this.webAssemblyContext);
        var yView = (0, vectorToArray_1.vectorToArrayViewF64)(yDrawValues, this.webAssemblyContext);
        var hView = (0, vectorToArray_1.vectorToArrayViewF64)(hDrawValues, this.webAssemblyContext);
        var lView = (0, vectorToArray_1.vectorToArrayViewF64)(lDrawValues, this.webAssemblyContext);
        this.args.Reset();
        this.args.SetLinesPen(linesPen);
        this.args.forceShaderMethod = true;
        this.args.verticalChart = renderPassData.isVerticalChart;
        this.args.startIndex = 0;
        this.args.count = dataPointsCount;
        if (!hasLogarithmicYAxis) {
            if (isVerticalDirection) {
                // main line
                if (this.parentSeries.drawConnector) {
                    this.args.fourVectorsMode = true;
                    this.args.SetXValues(xDrawValues);
                    this.args.SetYValues(hasHighCap ? hDrawValues : yDrawValues);
                    this.args.SetZValues(xDrawValues);
                    this.args.SetWValues(hasLowCap ? lDrawValues : yDrawValues);
                    this.args.SetNativeContext(renderContext.getNativeContext());
                    this.args.SetXCoordinateCalculator(renderPassData.xCoordinateCalculator.nativeCalculator);
                    this.args.SetYCoordinateCalculator(renderPassData.yCoordinateCalculator.nativeCalculator);
                    this.nativeDrawingProvider.DrawLinesVec(this.args);
                }
                var capCount = this.prepareTempCapVectors(0, dataPointsCount, dataPointWidth, xDrawValues, lDrawValues, hDrawValues, true, hasHighCap, hasLowCap);
                this.drawCaps(renderContext, renderPassData, linesPen, capCount);
            }
            else {
                // main line
                if (this.parentSeries.drawConnector) {
                    this.args.fourVectorsMode = true;
                    this.args.SetXValues(hasHighCap ? hDrawValues : xDrawValues);
                    this.args.SetYValues(yDrawValues);
                    this.args.SetZValues(hasLowCap ? lDrawValues : xDrawValues);
                    this.args.SetWValues(yDrawValues);
                    this.args.SetNativeContext(renderContext.getNativeContext());
                    this.args.SetXCoordinateCalculator(renderPassData.xCoordinateCalculator.nativeCalculator);
                    this.args.SetYCoordinateCalculator(renderPassData.yCoordinateCalculator.nativeCalculator);
                    this.nativeDrawingProvider.DrawLinesVec(this.args);
                }
                var capCount = this.prepareTempCapVectors(0, dataPointsCount, dataPointWidth, yDrawValues, lDrawValues, hDrawValues, false, hasHighCap, hasLowCap);
                this.drawCaps(renderContext, renderPassData, linesPen, capCount);
            }
        }
        else {
            if (isVerticalDirection) {
                for (var i = 0; i < dataPointsCount; ++i) {
                    var xValue = xView[i];
                    var yValue = yView[i];
                    var highValue = hasHighCap ? hView[i] : yValue;
                    var lowValue = hasLowCap ? lView[i] : yValue;
                    var shouldDrawLowErrorToLimit = hasLogarithmicYAxis && !hasNegativeLogYAxis && lowValue <= 0;
                    if (shouldDrawLowErrorToLimit) {
                        lowValue = this.parentSeries.yAxis.visibleRange.min;
                    }
                    var shouldDrawHighErrorToLimit = hasLogarithmicYAxis && hasNegativeLogYAxis && highValue >= 0;
                    if (shouldDrawHighErrorToLimit) {
                        highValue = this.parentSeries.yAxis.visibleRange.max;
                    }
                    var xCoord = renderPassData.xCoordinateCalculator.getCoordinate(xValue);
                    var yCoord = renderPassData.yCoordinateCalculator.getCoordinate(yValue);
                    var highCoord = renderPassData.yCoordinateCalculator.getCoordinate(highValue);
                    var lowCoord = renderPassData.yCoordinateCalculator.getCoordinate(lowValue);
                    var capStart = xCoord - halfRange;
                    var capEnd = xCoord + halfRange;
                    // main line
                    if (this.parentSeries.drawConnector) {
                        this.addLineVertices(vertices, xCoord, isNaN(highValue) ? yCoord : highCoord, xCoord, isNaN(lowValue) ? yCoord : lowCoord);
                    }
                    if (hasHighCap && !shouldDrawHighErrorToLimit && this.parentSeries.drawWhiskers) {
                        // top whiskers
                        this.addLineVertices(vertices, capStart, highCoord, capEnd, highCoord);
                    }
                    if (hasLowCap && !shouldDrawLowErrorToLimit && this.parentSeries.drawWhiskers) {
                        // bottom whiskers
                        this.addLineVertices(vertices, capStart, lowCoord, capEnd, lowCoord);
                    }
                }
            }
            else {
                for (var i = 0; i < dataPointsCount; ++i) {
                    var xValue = xView[i];
                    var yValue = yView[i];
                    var highValue = hasHighCap ? hView[i] : xValue;
                    var lowValue = hasLowCap ? lView[i] : xValue;
                    var shouldDrawLowErrorToLimit = hasLogarithmicXAxis && !hasNegativeLogXAxis && lowValue <= 0;
                    if (shouldDrawLowErrorToLimit) {
                        lowValue = LogarithmicAxis_1.MIN_LOG_AXIS_VALUE;
                    }
                    var shouldDrawHighErrorToLimit = hasLogarithmicXAxis && hasNegativeLogXAxis && highValue >= 0;
                    if (shouldDrawHighErrorToLimit) {
                        highValue = -LogarithmicAxis_1.MIN_LOG_AXIS_VALUE;
                    }
                    var xCoord = renderPassData.xCoordinateCalculator.getCoordinate(xValue);
                    var yCoord = renderPassData.yCoordinateCalculator.getCoordinate(yValue);
                    var highCoord = renderPassData.xCoordinateCalculator.getCoordinate(highValue);
                    var lowCoord = renderPassData.xCoordinateCalculator.getCoordinate(lowValue);
                    var capStart = yCoord - halfRange;
                    var capEnd = yCoord + halfRange;
                    // main line
                    if (this.parentSeries.drawConnector) {
                        this.addLineVertices(vertices, isNaN(lowValue) ? xCoord : lowCoord, yCoord, isNaN(highValue) ? xCoord : highCoord, yCoord);
                    }
                    if (hasHighCap && !shouldDrawHighErrorToLimit && this.parentSeries.drawWhiskers) {
                        // top whiskers
                        this.addLineVertices(vertices, highCoord, capStart, highCoord, capEnd);
                    }
                    if (hasLowCap && !shouldDrawLowErrorToLimit && this.parentSeries.drawWhiskers) {
                        // bottom whiskers
                        this.addLineVertices(vertices, lowCoord, capStart, lowCoord, capEnd);
                    }
                }
            }
            var seriesViewRect = this.parentSeries.parentSurface.seriesViewRect;
            var clipRect = Rect_1.Rect.intersect(this.parentSeries.parentSurface.clipRect, seriesViewRect);
            renderContext.drawLinesNative(vertices, linesPen, WebGlRenderContext2D_1.ELineDrawMode.DiscontinuousLine, clipRect, seriesViewRect.x, seriesViewRect.y);
        }
    };
    /**
     * @inheritDoc
     */
    ErrorSeriesDrawingProvider.prototype.onDpiChanged = function (args) {
        _super.prototype.onDpiChanged.call(this, args);
        this.onSeriesPropertyChange(constants_1.PROPERTY.STROKE);
    };
    /**
     * @inheritDoc
     */
    ErrorSeriesDrawingProvider.prototype.onSeriesPropertyChange = function (propertyName) {
        _super.prototype.onSeriesPropertyChange.call(this, propertyName);
        var _a = this.parentSeries, stroke = _a.stroke, strokeThickness = _a.strokeThickness, opacity = _a.opacity, strokeDashArray = _a.strokeDashArray;
        if (propertyName === constants_1.PROPERTY.STROKE ||
            propertyName === constants_1.PROPERTY.STROKE_THICKNESS ||
            propertyName === constants_1.PROPERTY.OPACITY ||
            propertyName === constants_1.PROPERTY.STROKE_DASH_ARRAY) {
            (0, Pen2DCache_1.createPenInCache)(this.linesPenCache, stroke, strokeThickness, opacity, strokeDashArray);
        }
    };
    /**
     * To remove this and prepareTempMedianVectors() we need to update native SCRTLineSegmentDrawingProvider to support
     * input of three vectors xVals, yVals, x1Vals where x1Vals are treated as length of the line segment in X direction centered in x,y
     */
    ErrorSeriesDrawingProvider.prototype.prepareTempCapVectors = function (startIndex, count, dataPointWidth, xValues, lowValues, highValues, isVerticalErrorDirection, hasHighCap, hasLowCap) {
        var s = (hasHighCap ? 2 : 0) + (hasLowCap ? 2 : 0);
        this.tempXVec.resizeFast(count * s);
        this.tempYVec.resizeFast(count * s);
        var halfRange = dataPointWidth / 2;
        var xView = (0, vectorToArray_1.vectorToArrayViewF64)(xValues, this.webAssemblyContext);
        var tempXView = (0, vectorToArray_1.vectorToArrayViewF64)(isVerticalErrorDirection ? this.tempXVec : this.tempYVec, this.webAssemblyContext);
        var tempYView = (0, vectorToArray_1.vectorToArrayViewF64)(isVerticalErrorDirection ? this.tempYVec : this.tempXVec, this.webAssemblyContext);
        if (hasHighCap && hasLowCap) {
            var minView = (0, vectorToArray_1.vectorToArrayViewF64)(lowValues, this.webAssemblyContext);
            var maxView = (0, vectorToArray_1.vectorToArrayViewF64)(highValues, this.webAssemblyContext);
            for (var i = startIndex; i < startIndex + count; i++) {
                var x = xView[i];
                var min = minView[i];
                var max = maxView[i];
                var outI = i * 4;
                tempXView[outI] = x - halfRange;
                tempYView[outI] = max;
                tempXView[outI + 1] = x + halfRange;
                tempYView[outI + 1] = max;
                tempXView[outI + 2] = x - halfRange;
                tempYView[outI + 2] = min;
                tempXView[outI + 3] = x + halfRange;
                tempYView[outI + 3] = min;
            }
        }
        else {
            var maxView = (0, vectorToArray_1.vectorToArrayViewF64)(hasHighCap ? highValues : lowValues, this.webAssemblyContext);
            for (var i = startIndex; i < startIndex + count; i++) {
                var x = xView[i];
                var max = maxView[i];
                var outI = i * 2;
                tempXView[outI] = x - halfRange;
                tempYView[outI] = max;
                tempXView[outI + 1] = x + halfRange;
                tempYView[outI + 1] = max;
            }
        }
        return count * s;
    };
    ErrorSeriesDrawingProvider.prototype.drawCaps = function (renderContext, renderPassData, linesPen, count) {
        if (!linesPen)
            return;
        this.args.Reset();
        this.args.SetLinesPen(linesPen);
        this.args.forceShaderMethod = true;
        this.args.forceClamp = true;
        // WARNING! Here we always set verticalChart = false because caps are drawn after the connector
        // and vertical chart has already been applied. Setting it here to True will do another 90 deg rotation
        // Another option would be to call 
        // renderContext.setTranslationRotationAndClip(clipRect, seriesViewRect.x, seriesViewRect.y);
        this.args.verticalChart = false;
        this.args.SetXValues(this.tempXVec);
        this.args.SetYValues(this.tempYVec);
        this.args.SetXCoordinateCalculator(renderPassData.xCoordinateCalculator.nativeCalculator);
        this.args.SetYCoordinateCalculator(renderPassData.yCoordinateCalculator.nativeCalculator);
        this.args.SetNativeContext(renderContext.getNativeContext());
        this.args.count = count;
        this.args.startIndex = 0;
        this.args.SetNativeContext(renderContext.getNativeContext());
        this.args.SetXValues(this.tempXVec);
        this.args.SetYValues(this.tempYVec);
        this.args.SetXCoordinateCalculator(renderPassData.xCoordinateCalculator.nativeCalculator);
        this.args.SetYCoordinateCalculator(renderPassData.yCoordinateCalculator.nativeCalculator);
        // TODO: Do we need to provide paletting support for caps and whiskers? If yes, how it should work?
        this.nativeDrawingProvider.DrawLinesVec(this.args);
    };
    ErrorSeriesDrawingProvider.prototype.addLineVertices = function (vertices, x1, y1, x2, y2) {
        var isVerticalChart = this.parentSeries.xAxis.isVerticalChart;
        if (isVerticalChart) {
            vertices.push_back((0, NativeObject_1.getVertex)(this.webAssemblyContext, y1, x1));
            vertices.push_back((0, NativeObject_1.getVertex)(this.webAssemblyContext, y2, x2));
        }
        else {
            vertices.push_back((0, NativeObject_1.getVertex)(this.webAssemblyContext, x1, y1));
            vertices.push_back((0, NativeObject_1.getVertex)(this.webAssemblyContext, x2, y2));
        }
    };
    return ErrorSeriesDrawingProvider;
}(BaseSeriesDrawingProvider_1.BaseSeriesDrawingProvider));
exports.ErrorSeriesDrawingProvider = ErrorSeriesDrawingProvider;
