"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.PolarAxisRenderer = void 0;
var Rect_1 = require("../../../../Core/Rect");
var TextPosition_1 = require("../../../../types/TextPosition");
var logger_1 = require("../../../../utils/logger");
var parseColor_1 = require("../../../../utils/parseColor");
var WebGlRenderContext2D_1 = require("../../../Drawing/WebGlRenderContext2D");
var labelHelper_1 = require("../../Helpers/labelHelper");
var NativeObject_1 = require("../../Helpers/NativeObject");
var polarChartHelper_1 = require("../../Helpers/polarChartHelper");
var DpiHelper_1 = require("../../TextureManager/DpiHelper");
var DpiHelper_2 = require("../../TextureManager/DpiHelper");
var AxisRenderer_1 = require("../AxisRenderer");
var PolarLabelMode_1 = require("./types/PolarLabelMode");
/**
 * Draws a polar axis using our WebGL Rendering engine
 */
var PolarAxisRenderer = /** @class */ (function (_super) {
    __extends(PolarAxisRenderer, _super);
    function PolarAxisRenderer() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    /** @inheritDoc */
    PolarAxisRenderer.prototype.layout = function (rect) {
        this.outerRadius = rect.width;
    };
    /** @inheritDoc */
    PolarAxisRenderer.prototype.measure = function (isHorizontalAxis, labelStyle, majorTickLabels, ticksSize, labelProvider, drawLabels, drawTicks, labelInfos) {
        var pAxis = this.parentAxis;
        var ctx = this.measureTextCanvas.getContext("2d");
        this.desiredTicksSize = drawTicks ? ticksSize : 0;
        if (drawLabels) {
            if (pAxis.isAngular) {
                if (pAxis.isInnerAxis) {
                    this.desiredHeight = 0;
                    this.desiredWidth = 0;
                }
                else {
                    if (pAxis.polarLabelMode === PolarLabelMode_1.EPolarLabelMode.Parallel) {
                        this.desiredHeight =
                            labelProvider.getMaxLabelHeightForHorizontalAxis(majorTickLabels, ctx, labelStyle, labelInfos) +
                                this.desiredTicksSize;
                        this.desiredWidth = this.desiredHeight;
                    }
                    else if (pAxis.polarLabelMode === PolarLabelMode_1.EPolarLabelMode.Perpendicular) {
                        this.desiredHeight =
                            labelProvider.getMaxLabelWidthForVerticalAxis(majorTickLabels, ctx, labelStyle, labelInfos) +
                                this.desiredTicksSize;
                        this.desiredWidth = this.desiredHeight;
                    }
                    else {
                        this.desiredHeight =
                            labelProvider.getMaxLabelHeightForHorizontalAxis(majorTickLabels, ctx, labelStyle, labelInfos) +
                                this.desiredTicksSize;
                        this.desiredWidth =
                            labelProvider.getMaxLabelWidthForVerticalAxis(majorTickLabels, ctx, labelStyle, labelInfos) +
                                this.desiredTicksSize;
                    }
                }
            }
        }
    };
    /** @inheritDoc */
    PolarAxisRenderer.prototype.drawLabels = function (renderContext, axisAlignment, isInnerAxis, tickLabels, tickCoords, axisOffset, labelStyle, isVerticalChart, isFlippedCoordinates, labelProvider, labelInfos) {
        if (DpiHelper_1.DebugForDpi) {
            console.log("AxisRenderer.drawLabels. fontSize: ".concat(labelStyle.fontSize));
        }
        var _a = this, viewRect = _a.viewRect, textureManager = _a.textureManager;
        var nativeContext = renderContext.getNativeContext();
        var ctx;
        var padding = labelStyle.padding, alignment = labelStyle.alignment, multilineAlignment = labelStyle.multilineAlignment;
        var axis = this.parentAxis;
        // TODO probably need to intersect with surface.clipRect
        var svr = axis.parentSurface.seriesViewRect;
        renderContext.resetAndClip(svr);
        // for debug
        var labelRects = [];
        var textColor = (0, parseColor_1.parseColorToUIntArgb)(labelStyle.color);
        var nativeFont = labelProvider.useNativeText ? renderContext.getFont(labelStyle, true) : null;
        var textBounds = labelProvider.useNativeText ? (0, NativeObject_1.getTextBounds)(this.webAssemblyContext) : null;
        ctx = this.getMeasureContext();
        if (!nativeFont) {
            if (axis.polarLabelMode !== PolarLabelMode_1.EPolarLabelMode.Horizontal) {
                throw new Error("Original text drawing only supports EPolarLabelMode.Horizontal.  To use rotated labels, set useNativeText: true");
            }
        }
        //??
        tickCoords = tickCoords.map(function (t) { return t - axisOffset; });
        var mlaNative = (0, TextPosition_1.convertMultiLineAlignment)(multilineAlignment, this.webAssemblyContext);
        var nativeLineSpacing = labelProvider.lineSpacing;
        var lineHeight = this.calculateLineHightForNativeFont(nativeFont, textBounds);
        var vec = new this.webAssemblyContext.TSRVector2();
        if (axis.isAngular) {
            var labelWidthPadding = (labelStyle.padding.left + labelStyle.padding.right) / 2;
            var labelHeights = [];
            var labelWidths = [];
            if (!labelProvider.useCache && labelProvider.useNativeText) {
                // Scenario with disabled cache, for testing purpose only
                for (var _i = 0, tickLabels_1 = tickLabels; _i < tickLabels_1.length; _i++) {
                    var label = tickLabels_1[_i];
                    nativeFont.CalculateStringBounds(label !== null && label !== void 0 ? label : "", textBounds, nativeLineSpacing);
                    labelHeights.push(textBounds.m_fHeight);
                    labelWidths.push(textBounds.m_fWidth);
                }
            }
            else if (labelProvider.useNativeText) {
                labelHeights = labelInfos.map(function (l) { return l.textHeight; });
                labelWidths = labelInfos.map(function (l) { return l.textWidth; });
            }
            else {
                // Not Native text supports only horizontal mode
                labelHeights = tickLabels.map(function (label, i) { return labelProvider.getLabelHeight(ctx, label, labelStyle, labelInfos === null || labelInfos === void 0 ? void 0 : labelInfos[i]); });
                labelWidths = tickLabels.map(function (label, i) { return labelProvider.getLabelWidth(ctx, label, labelStyle, labelInfos === null || labelInfos === void 0 ? void 0 : labelInfos[i]); });
            }
            var radius = isInnerAxis
                ? this.outerRadius * Math.min(axis.otherAxis.lengthScale, 1) - this.desiredTicksSize
                : this.outerRadius * Math.min(axis.otherAxis.lengthScale, 1) + this.desiredTicksSize;
            var transform = axis.getTransform();
            var cardinalAngle = 10; // * Math.PI / 180;  // Special handling around cardinal points
            var tickCount = polarChartHelper_1.polarChartHelper.checkPolarLabelsOverlap(tickCoords) ? tickCoords.length - 1 : tickCoords.length;
            for (var index = 0; index < tickCount; index++) {
                var angle = tickCoords[index];
                var labelText = tickLabels[index];
                var labelHeight = labelHeights[index];
                var labelWidth = labelWidths[index];
                var labelRadius = radius;
                if (axis.polarLabelMode === PolarLabelMode_1.EPolarLabelMode.Parallel) {
                    // This shows how we use paddings for outer and inner labels for Native Text for the Parallel mode
                    // paddingTop
                    // outerLabel
                    // paddingBottom
                    // radius
                    // paddingTop
                    // innerLabel
                    // paddingBottom
                    var paddingFromRadius = isInnerAxis ? -labelStyle.padding.top : labelStyle.padding.bottom;
                    // multiply by 0.5 because calculation distance to the center of the label
                    labelRadius = radius + (isInnerAxis ? -1 : 1) * 0.5 * labelHeight + paddingFromRadius;
                }
                else if (axis.polarLabelMode === PolarLabelMode_1.EPolarLabelMode.Perpendicular) {
                    var shift = Math.cos(angle + axis.startAngle) < 0 ? (isInnerAxis ? 0 : 1) : isInnerAxis ? -1 : 0;
                    // add shift to respect different orientation
                    labelRadius = radius + shift * labelWidth + (isInnerAxis ? -1 : 1) * labelWidthPadding;
                }
                else if (axis.polarLabelMode === PolarLabelMode_1.EPolarLabelMode.Horizontal) {
                    // This is the only mode which works both for Native and NOT Native text
                    if (labelProvider.useNativeText) {
                        labelRadius = radius + (isInnerAxis ? -labelStyle.padding.top : labelStyle.padding.bottom);
                    }
                }
                transform.TransformPoint(labelRadius, angle, vec);
                angle += axis.startAngle;
                var xCoord = vec.x;
                var yCoord = vec.y;
                var rxc = 0;
                var ryc = 0;
                if (axis.polarLabelMode === PolarLabelMode_1.EPolarLabelMode.Horizontal) {
                    if (isInnerAxis) {
                        angle = angle + Math.PI;
                    }
                    var aDeg = Math.round((angle * 180) / Math.PI);
                    // if within 10% from cardinal points
                    var isCardinal = Math.abs(aDeg) % 90 < cardinalAngle || Math.abs(aDeg) % 90 > 90 - cardinalAngle;
                    // To make it return always positive number
                    var quadrant = ((((aDeg + cardinalAngle) / 90) % 4) + 4) % 4;
                    if (isCardinal) {
                        if (quadrant < 1) {
                            yCoord -= labelHeight / 2;
                        }
                        else if (quadrant < 2) {
                            xCoord -= labelWidth / 2;
                            yCoord -= labelHeight;
                        }
                        else if (quadrant < 3) {
                            xCoord -= labelWidth;
                            yCoord -= labelHeight / 2;
                        }
                        else {
                            xCoord -= labelWidth / 2;
                        }
                    }
                    else {
                        if (Math.cos(angle) < 0) {
                            xCoord -= labelWidth;
                        }
                        if (Math.sin(angle) > 0) {
                            yCoord -= labelHeight;
                        }
                    }
                }
                else if (axis.polarLabelMode === PolarLabelMode_1.EPolarLabelMode.Parallel) {
                    rxc = xCoord + svr.left;
                    ryc = yCoord + svr.top;
                    // adjusting the angel
                    xCoord -= labelWidth / 2;
                    if (Math.sin(angle) >= 0) {
                        yCoord -= labelHeight / 2;
                    }
                    else {
                        yCoord += labelHeight / 2 - lineHeight;
                    }
                }
                else if (axis.polarLabelMode === PolarLabelMode_1.EPolarLabelMode.Perpendicular) {
                    rxc = xCoord + svr.left;
                    ryc = yCoord + svr.top;
                    yCoord -= labelHeight / 2;
                }
                var rotationRad = labelHelper_1.labelHelper.getPolarLabelRotation(axis.polarLabelMode, angle);
                try {
                    if (nativeFont) {
                        var tx = xCoord + svr.left; // + padding.left;
                        var ty = yCoord + svr.top + lineHeight; // + padding.top;
                        var _b = labelProvider.adjustLabel(index, labelText, labelWidth, labelHeight, tx, ty, rxc, ryc, rotationRad), text = _b.text, x = _b.x, y = _b.y, rx = _b.rx, ry = _b.ry, rotationRadians = _b.rotationRadians, color = _b.color;
                        if (this.drawDebug) {
                            labelRects.push(Rect_1.Rect.create(x, y, labelWidth, labelHeight));
                        }
                        nativeFont.DrawStringAdvanced(text !== null && text !== void 0 ? text : "", color !== null && color !== void 0 ? color : textColor, Math.round(x), Math.round(y), (0, NativeObject_1.getVector4)(this.webAssemblyContext, rx, ry, rotationRadians, 0), mlaNative, nativeLineSpacing);
                    }
                    else {
                        var cachedLabelInfo = labelInfos === null || labelInfos === void 0 ? void 0 : labelInfos[index];
                        var _c = cachedLabelInfo
                            ? { bitmapTexture: cachedLabelInfo.bitmapTexture, textureHeight: cachedLabelInfo.textureHeight, textureWidth: cachedLabelInfo.textureWidth }
                            : labelProvider.getCachedLabelTexture(labelText, textureManager, labelStyle), bitmapTexture = _c.bitmapTexture, textureHeight = _c.textureHeight, textureWidth = _c.textureWidth;
                        var _d = labelProvider.adjustLabel(index, labelText, labelWidth, labelHeight, xCoord + svr.left, yCoord + svr.top, 0, 0, 0), x = _d.x, y = _d.y;
                        if (bitmapTexture) {
                            renderContext.drawTexture(bitmapTexture, Math.round(x), Math.round(y), textureWidth, textureHeight);
                            if (!labelProvider.useCache) {
                                bitmapTexture.delete();
                            }
                        }
                    }
                }
                catch (err) {
                    logger_1.Logger.debug(err);
                    // webgl context probably lost.  Clear the label cache
                    labelProvider.delete();
                }
            }
        }
        else {
            var _e = polarChartHelper_1.polarChartHelper.calcLabelPosition(isInnerAxis, axis.otherAxis.flippedCoordinates, axis.startAngle, axis.otherAxis.totalAngle), isAntiClockWiseLabelPosition = _e.isAntiClockWise, labelRotation = _e.labelRotation, axisStartAngle = _e.startAngle;
            var angle = axisStartAngle;
            var transform = axis.getTransform();
            var labelHeights = [];
            var labelWidths = [];
            if (!labelProvider.useCache && labelProvider.useNativeText) {
                for (var _f = 0, tickLabels_2 = tickLabels; _f < tickLabels_2.length; _f++) {
                    var label = tickLabels_2[_f];
                    nativeFont.CalculateStringBounds(label !== null && label !== void 0 ? label : "", textBounds, nativeLineSpacing);
                    labelHeights.push(textBounds.m_fHeight + labelStyle.padding.top + labelStyle.padding.bottom);
                    labelWidths.push(textBounds.m_fWidth + labelStyle.padding.left + labelStyle.padding.right);
                }
            }
            else {
                labelHeights = tickLabels.map(function (label, i) { return labelProvider.getLabelHeight(ctx, label, labelStyle, labelInfos === null || labelInfos === void 0 ? void 0 : labelInfos[i]); });
                labelWidths = tickLabels.map(function (label, i) { return labelProvider.getLabelWidth(ctx, label, labelStyle, labelInfos === null || labelInfos === void 0 ? void 0 : labelInfos[i]); });
            }
            var tickSize = this.desiredTicksSize;
            for (var index = 0; index < tickCoords.length; index++) {
                var radius = tickCoords[index] + axisOffset;
                var labelText = tickLabels[index];
                var labelWidth = labelWidths[index];
                var labelHeight = labelHeights[index];
                transform.TransformPoint(radius, labelRotation, vec);
                var xCoord = vec.x;
                var yCoord = vec.y;
                if (isAntiClockWiseLabelPosition) {
                    angle = axisStartAngle + Math.PI;
                }
                xCoord += (Math.sin(angle) / 2 - 0.5) * labelWidth;
                xCoord += Math.sin(angle) * tickSize;
                var a = (angle < 0 ? 2 * Math.PI - angle : angle) % (2 * Math.PI);
                var yadj = a < Math.PI ? a / Math.PI : 2 - a / Math.PI;
                //console.log(labelText, aDeg, radius, xCoord, ((Math.sin(angle) / 2) - 0.5) * labelWidth, yCoord, yadj);
                yCoord -= yadj * labelHeight;
                yCoord += Math.cos(angle) * tickSize;
                if (this.drawDebug) {
                    labelRects.push(Rect_1.Rect.create(xCoord, yCoord, labelWidth, labelHeight));
                }
                try {
                    if (nativeFont) {
                        var tx = xCoord + svr.left + padding.left;
                        var ty = yCoord + svr.top + lineHeight + padding.top;
                        var _g = labelProvider.adjustLabel(index, labelText, labelWidth, labelHeight, tx, ty, tx, ty, 0), text = _g.text, x = _g.x, y = _g.y, rx = _g.rx, ry = _g.ry, rotationRadians = _g.rotationRadians, color = _g.color;
                        nativeFont.DrawStringAdvanced(text !== null && text !== void 0 ? text : "", color !== null && color !== void 0 ? color : textColor, Math.round(x), Math.round(y), (0, NativeObject_1.getVector4)(this.webAssemblyContext, rx, ry, rotationRadians, 0), mlaNative, nativeLineSpacing);
                    }
                    else {
                        var cachedLabelInfo = labelInfos === null || labelInfos === void 0 ? void 0 : labelInfos[index];
                        var _h = cachedLabelInfo
                            ? { bitmapTexture: cachedLabelInfo.bitmapTexture, textureHeight: cachedLabelInfo.textureHeight, textureWidth: cachedLabelInfo.textureWidth }
                            : labelProvider.getCachedLabelTexture(labelText, textureManager, labelStyle), bitmapTexture = _h.bitmapTexture, textureHeight = _h.textureHeight, textureWidth = _h.textureWidth;
                        if (bitmapTexture) {
                            var _j = labelProvider.adjustLabel(index, labelText, labelWidth, labelHeight, xCoord + svr.left, yCoord + svr.top, 0, 0, 0), x = _j.x, y = _j.y;
                            renderContext.drawTexture(bitmapTexture, Math.round(x), Math.round(y), textureWidth, textureHeight);
                            if (!labelProvider.useCache) {
                                bitmapTexture.delete();
                            }
                        }
                    }
                }
                catch (err) {
                    logger_1.Logger.debug(err);
                    // webgl context probably lost.  Clear the label cache
                    labelProvider.delete();
                }
            }
        }
        vec.delete();
        if (this.drawDebug) {
            this.drawLabelViewRects(renderContext, new Rect_1.Rect(0, 0, 0, 0), labelRects);
        }
        if (nativeFont) {
            nativeFont.End();
        }
    };
    /** @inheritDoc */
    PolarAxisRenderer.prototype.drawTicks = function (renderContext, axisAlignment, isInnerAxis, tickCoords, axisOffset, pen, tickStyle) {
        var _a, _b, _c, _d;
        if (!tickCoords || tickCoords.length === 0)
            return;
        var leftPad = DpiHelper_2.DpiHelper.PIXEL_RATIO * ((_b = (_a = this.parentAxis.parentSurface.padding) === null || _a === void 0 ? void 0 : _a.left) !== null && _b !== void 0 ? _b : 0);
        var topPad = DpiHelper_2.DpiHelper.PIXEL_RATIO * ((_d = (_c = this.parentAxis.parentSurface.padding) === null || _c === void 0 ? void 0 : _c.top) !== null && _d !== void 0 ? _d : 0);
        var axis = this.parentAxis;
        var tickSize = tickStyle.tickSize;
        var transform = axis.getTransform();
        var clipRect = Rect_1.Rect.intersect(this.parentAxis.parentSurface.viewRect, this.parentAxis.parentSurface.seriesViewRect);
        if (axis.isAngular) {
            var otherAxisOffset = axis.otherAxis.offset;
            var startRadius_1 = axis.otherAxis.axisLength + otherAxisOffset;
            var endRadius_1 = isInnerAxis
                ? startRadius_1 - tickSize * DpiHelper_2.DpiHelper.PIXEL_RATIO
                : startRadius_1 + tickSize * DpiHelper_2.DpiHelper.PIXEL_RATIO;
            var vertices_1 = (0, NativeObject_1.getVectorColorVertex)(this.webAssemblyContext);
            var vertex_1 = (0, NativeObject_1.getVertex)(this.webAssemblyContext, 0, 0);
            var vec_1 = (0, NativeObject_1.getVector2)(this.webAssemblyContext);
            tickCoords.forEach(function (tc) {
                transform.TransformPoint(startRadius_1, tc, vec_1);
                vertex_1.SetPosition(vec_1.x, vec_1.y);
                vertices_1.push_back(vertex_1);
                transform.TransformPoint(endRadius_1, tc, vec_1);
                vertex_1.SetPosition(vec_1.x, vec_1.y);
                vertices_1.push_back(vertex_1);
            });
            renderContext.drawLinesNative(vertices_1, pen, WebGlRenderContext2D_1.ELineDrawMode.DiscontinuousLine, clipRect, leftPad, topPad);
        }
        else {
            var vertices_2 = (0, NativeObject_1.getVectorColorVertex)(this.webAssemblyContext);
            var vertex_2 = (0, NativeObject_1.getVertex)(this.webAssemblyContext, 0, 0);
            var vec_2 = (0, NativeObject_1.getVector2)(this.webAssemblyContext);
            var _e = polarChartHelper_1.polarChartHelper.calcTickDirection(isInnerAxis, axis.otherAxis.flippedCoordinates, axis.startAngle, axis.otherAxis.totalAngle), direction = _e.direction, tickRotation_1 = _e.tickRotation, startAngle = _e.startAngle;
            var sinTick_1 = direction * Math.sin(startAngle) * tickSize;
            var cosTick_1 = direction * Math.cos(startAngle) * tickSize;
            tickCoords.forEach(function (tc) {
                transform.TransformPoint(tc, tickRotation_1, vec_2);
                vertex_2.SetPosition(vec_2.x, vec_2.y);
                vertices_2.push_back(vertex_2);
                vertex_2.SetPosition(vec_2.x + sinTick_1, vec_2.y + cosTick_1);
                vertices_2.push_back(vertex_2);
            });
            renderContext.drawLinesNative(vertices_2, pen, WebGlRenderContext2D_1.ELineDrawMode.DiscontinuousLine, clipRect, leftPad, topPad);
        }
    };
    return PolarAxisRenderer;
}(AxisRenderer_1.AxisRenderer));
exports.PolarAxisRenderer = PolarAxisRenderer;
