"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.BoxAnnotation = void 0;
var app_1 = require("../../../constants/app");
var Deleter_1 = require("../../../Core/Deleter");
var Guard_1 = require("../../../Core/Guard");
var Point_1 = require("../../../Core/Point");
var Rect_1 = require("../../../Core/Rect");
var SurfaceType_1 = require("../../../types/SurfaceType");
var XyDirection_1 = require("../../../types/XyDirection");
var pointUtil_1 = require("../../../utils/pointUtil");
var translate_1 = require("../../../utils/translate");
var BrushCache_1 = require("../../Drawing/BrushCache");
var Pen2DCache_1 = require("../../Drawing/Pen2DCache");
var DpiHelper_1 = require("../TextureManager/DpiHelper");
var AnnotationBase_1 = require("./AnnotationBase");
var annotationHelpers_1 = require("./annotationHelpers");
var constants_1 = require("./constants");
var EAnnotationType_1 = require("./types/EAnnotationType");
var RenderContextAnnotationBase_1 = require("./RenderContextAnnotationBase");
/**
 * @summary The {@link BoxAnnotation} provides an {@link AnnotationBase | Annotation} which draws a rectangle or box over the {@link SciChartSurface}
 * @description
 * To add a {@link BoxAnnotation} to a {@link SciChartSurface}, use the following code:
 * ```ts
 * const sciChartSurface: SciChartSurface;
 * const boxAnnotation = new BoxAnnotation( { x1: 1, x2: 2, y1: 3, y2: 4, fill: "#FF000077", stroke: "#FF0000"});
 * sciChartSurface.annotations.add(boxAnnotation);
 * ```
 * @remarks Uses the fast WebGL/WebAssembly {@link WebGL2RenderingContext} for rendering
 */
var BoxAnnotation = /** @class */ (function (_super) {
    __extends(BoxAnnotation, _super);
    /**
     * Create an instance of a BoxAnnotation
     * @param options Optional parameters of type {@link IBoxAnnotationOptions} which configure the annotation upon construction
     */
    function BoxAnnotation(options) {
        var _this = this;
        var _a, _b, _c;
        _this = _super.call(this, options) || this;
        /** @inheritDoc */
        _this.type = EAnnotationType_1.EAnnotationType.RenderContextBoxAnnotation;
        _this.surfaceTypes = [
            SurfaceType_1.ESurfaceType.SciChartSurfaceType,
            SurfaceType_1.ESurfaceType.SciChartPolarSurfaceType
        ];
        _this.strokeThicknessProperty = 1;
        _this.stroke = (_a = options === null || options === void 0 ? void 0 : options.stroke) !== null && _a !== void 0 ? _a : "#ffffff";
        _this.strokeThickness = (_b = options === null || options === void 0 ? void 0 : options.strokeThickness) !== null && _b !== void 0 ? _b : 1;
        _this.fill = (_c = options === null || options === void 0 ? void 0 : options.fill) !== null && _c !== void 0 ? _c : "#777777";
        return _this;
    }
    Object.defineProperty(BoxAnnotation.prototype, "stroke", {
        /**
         * Gets stroke for the outline of the {@link BoxAnnotation}
         * @remarks Acceptable values include RGB format e.g. ```#FF0000```, RGBA format e.g. ```#FF000077`` and RGBA format e.g. ```rgba(255,0,0,0.5)```
         */
        get: function () {
            return this.strokeProperty;
        },
        /**
         * Sets the stroke for the outline of the {@link BoxAnnotation}
         * @remarks Acceptable values include RGB format e.g. ```#FF0000```, RGBA format e.g. ```#FF000077`` and RGBA format e.g. ```rgba(255,0,0,0.5)```
         */
        set: function (htmlColorCode) {
            this.strokeProperty = htmlColorCode;
            this.notifyPropertyChanged(constants_1.PROPERTY.STROKE);
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BoxAnnotation.prototype, "strokeThickness", {
        /**
         * Gets the strokeThickness for the outline of the {@link BoxAnnotation}
         */
        get: function () {
            return this.strokeThicknessProperty;
        },
        /**
         * Sets the strokeThickness for the outline of the {@link BoxAnnotation}
         */
        set: function (value) {
            this.strokeThicknessProperty = value;
            this.notifyPropertyChanged(constants_1.PROPERTY.STROKE_THICKNESS);
        },
        enumerable: false,
        configurable: true
    });
    Object.defineProperty(BoxAnnotation.prototype, "fill", {
        /**
         * Gets the fill for the {@link BoxAnnotation}
         * @remarks Acceptable values include RGB format e.g. ```#FF0000```, RGBA format e.g. ```#FF000077`` and RGBA format e.g. ```rgba(255,0,0,0.5)```
         */
        get: function () {
            return this.fillProperty;
        },
        /**
         * Sets the fill for the {@link BoxAnnotation}
         * @remarks Acceptable values include RGB format e.g. ```#FF0000```, RGBA format e.g. ```#FF000077`` and RGBA format e.g. ```rgba(255,0,0,0.5)```
         */
        set: function (htmlColorCode) {
            this.fillProperty = htmlColorCode;
            this.notifyPropertyChanged(constants_1.PROPERTY.FILL);
        },
        enumerable: false,
        configurable: true
    });
    /** @inheritDoc */
    BoxAnnotation.prototype.delete = function () {
        this.strokePenCache = (0, Deleter_1.deleteSafe)(this.strokePenCache);
        this.fillBrushCache = (0, Deleter_1.deleteSafe)(this.fillBrushCache);
        this.nativeDrawingProvider = (0, Deleter_1.deleteSafe)(this.nativeDrawingProvider);
        this.xValues = (0, Deleter_1.deleteSafe)(this.xValues);
        this.yValues = (0, Deleter_1.deleteSafe)(this.yValues);
    };
    /** @inheritDoc */
    BoxAnnotation.prototype.drawWithContext = function (renderContext, xCalc, yCalc, seriesViewRect, surfaceViewRect, chartViewRect) {
        Guard_1.Guard.notNull(renderContext, "renderContext");
        Guard_1.Guard.notNull(xCalc, "xCalc");
        Guard_1.Guard.notNull(yCalc, "yCalc");
        var strokePen = this.stroke && this.strokeThickness ? (0, Pen2DCache_1.getWebGlPenFromCache)(this.strokePenCache) : undefined;
        var fillBrush = this.fill ? (0, BrushCache_1.getWebGlBrushFromCache)(this.fillBrushCache) : undefined;
        var _a = this.convertPolarToCartesian(this.getX1Coordinate(xCalc, yCalc), this.getY1Coordinate(xCalc, yCalc)), x1 = _a.x, y1 = _a.y;
        var _b = this.convertPolarToCartesian(this.getX2Coordinate(xCalc, yCalc), this.getY2Coordinate(xCalc, yCalc)), x2 = _b.x, y2 = _b.y;
        this.setAnnotationBorders(x1, x2, y1, y2);
        var rect = Rect_1.Rect.createWithPoints(new Point_1.Point(x1, y1), new Point_1.Point(x2, y2));
        // Temporary HAX! drawRect is rubbish with large strokeThickness, whereas the columnDrawingProvider does a nice
        // outlined rectangle, but the code is ugly.  In 2.3 we will improve the native drawRect to do the outline properly.
        if (!app_1.IS_TEST_ENV) {
            var clipRect = this.getClippingRect(this.clipping, seriesViewRect, surfaceViewRect, chartViewRect);
            if (this.strokeThickness > 0) {
                this.drawWithProvider(renderContext, strokePen.scrtPen, fillBrush.scrtBrush, xCalc, yCalc, rect, seriesViewRect, clipRect);
            }
            else {
                renderContext.drawRect(rect, seriesViewRect, clipRect, strokePen, fillBrush, false, this.strokeThickness);
            }
        }
        this.updateAdornerInner();
    };
    /** @inheritDoc */
    BoxAnnotation.prototype.onAttach = function (scs) {
        _super.prototype.onAttach.call(this, scs);
        this.nativeDrawingProvider = new scs.webAssemblyContext2D.SCRTColumnSeriesDrawingProvider();
        if (!this.strokePenCache) {
            this.strokePenCache = new Pen2DCache_1.Pen2DCache(scs.webAssemblyContext2D);
        }
        (0, Pen2DCache_1.createPenInCache)(this.strokePenCache, this.stroke, this.strokeThickness, this.opacity);
        if (!this.fillBrushCache) {
            this.fillBrushCache = new BrushCache_1.BrushCache(scs.webAssemblyContext2D);
        }
        (0, BrushCache_1.createBrushInCache)(this.fillBrushCache, this.fill, this.opacity);
    };
    BoxAnnotation.prototype.onDragStarted = function (args) {
        _super.prototype.onDragStarted.call(this, args);
        var _a = this.getAnnotationBorders(false, true), x1 = _a.x1, x2 = _a.x2, y1 = _a.y1, y2 = _a.y2;
        var _b = annotationHelpers_1.annotationHelpers.calcNewApex(x1, y1, x2, y2, this.isVerticalChart), x1y1 = _b.x1y1, x2y1 = _b.x2y1, x1y2 = _b.x1y2, x2y2 = _b.x2y2;
        var xyMousePoint = (0, translate_1.translateFromCanvasToSeriesViewRect)(new Point_1.Point(args.mousePoint.x, args.mousePoint.y), this.parentSurface.seriesViewRect, true);
        if (x1y1 && this.canDragPoint(AnnotationBase_1.EDraggingGripPoint.x1y1)) {
            var dist = (0, pointUtil_1.calcDistance)(x1y1.x, x1y1.y, xyMousePoint.x, xyMousePoint.y);
            if (dist < this.annotationsGripsRadius * DpiHelper_1.DpiHelper.PIXEL_RATIO) {
                this.adornerDraggingPoint = AnnotationBase_1.EDraggingGripPoint.x1y1;
                return true;
            }
        }
        if (x2y1 && this.canDragPoint(AnnotationBase_1.EDraggingGripPoint.x2y1)) {
            var dist = (0, pointUtil_1.calcDistance)(x2y1.x, x2y1.y, xyMousePoint.x, xyMousePoint.y);
            if (dist < this.annotationsGripsRadius * DpiHelper_1.DpiHelper.PIXEL_RATIO) {
                this.adornerDraggingPoint = AnnotationBase_1.EDraggingGripPoint.x2y1;
                return true;
            }
        }
        if (x1y2 && this.canDragPoint(AnnotationBase_1.EDraggingGripPoint.x1y2)) {
            var dist = (0, pointUtil_1.calcDistance)(x1y2.x, x1y2.y, xyMousePoint.x, xyMousePoint.y);
            if (dist < this.annotationsGripsRadius * DpiHelper_1.DpiHelper.PIXEL_RATIO) {
                this.adornerDraggingPoint = AnnotationBase_1.EDraggingGripPoint.x1y2;
                return true;
            }
        }
        if (x2y2 && this.canDragPoint(AnnotationBase_1.EDraggingGripPoint.x2y2)) {
            var dist = (0, pointUtil_1.calcDistance)(x2y2.x, x2y2.y, xyMousePoint.x, xyMousePoint.y);
            if (dist < this.annotationsGripsRadius * DpiHelper_1.DpiHelper.PIXEL_RATIO) {
                this.adornerDraggingPoint = AnnotationBase_1.EDraggingGripPoint.x2y2;
                return true;
            }
        }
        if (xyMousePoint && this.canDragPoint(AnnotationBase_1.EDraggingGripPoint.Body)) {
            if (this.clickToSelect(args)) {
                this.adornerDraggingPoint = AnnotationBase_1.EDraggingGripPoint.Body;
                return true;
            }
        }
        return false;
    };
    BoxAnnotation.prototype.calcDragDistance = function (xyValues) {
        if (!this.prevValue) {
            this.prevValue = xyValues;
            return;
        }
        if (this.adornerDraggingPoint === AnnotationBase_1.EDraggingGripPoint.Body) {
            this.x1 = this.x1 - (this.prevValue.x - xyValues.x);
            this.x2 = this.x2 - (this.prevValue.x - xyValues.x);
            this.y1 = this.y1 - (this.prevValue.y - xyValues.y);
            this.y2 = this.y2 - (this.prevValue.y - xyValues.y);
        }
        else if (this.adornerDraggingPoint === AnnotationBase_1.EDraggingGripPoint.x1y1) {
            if (this.resizeDirections === XyDirection_1.EXyDirection.XDirection) {
                this.x1 -= this.prevValue.x - xyValues.x;
            }
            else if (this.resizeDirections === XyDirection_1.EXyDirection.YDirection) {
                this.y1 -= this.prevValue.y - xyValues.y;
            }
            else {
                this.x1 -= this.prevValue.x - xyValues.x;
                this.y1 -= this.prevValue.y - xyValues.y;
            }
        }
        else if (this.adornerDraggingPoint === AnnotationBase_1.EDraggingGripPoint.x2y2) {
            if (this.resizeDirections === XyDirection_1.EXyDirection.XDirection) {
                this.x2 -= this.prevValue.x - xyValues.x;
            }
            else if (this.resizeDirections === XyDirection_1.EXyDirection.YDirection) {
                this.y2 -= this.prevValue.y - xyValues.y;
            }
            else {
                this.x2 -= this.prevValue.x - xyValues.x;
                this.y2 -= this.prevValue.y - xyValues.y;
            }
        }
        else if (this.adornerDraggingPoint === AnnotationBase_1.EDraggingGripPoint.x2y1) {
            if (this.resizeDirections === XyDirection_1.EXyDirection.XDirection) {
                this.x2 -= this.prevValue.x - xyValues.x;
            }
            else if (this.resizeDirections === XyDirection_1.EXyDirection.YDirection) {
                this.y1 -= this.prevValue.y - xyValues.y;
            }
            else {
                this.x2 -= this.prevValue.x - xyValues.x;
                this.y1 -= this.prevValue.y - xyValues.y;
            }
        }
        else if (this.adornerDraggingPoint === AnnotationBase_1.EDraggingGripPoint.x1y2) {
            if (this.resizeDirections === XyDirection_1.EXyDirection.XDirection) {
                this.x1 -= this.prevValue.x - xyValues.x;
            }
            else if (this.resizeDirections === XyDirection_1.EXyDirection.YDirection) {
                this.y2 -= this.prevValue.y - xyValues.y;
            }
            else {
                this.x1 -= this.prevValue.x - xyValues.x;
                this.y2 -= this.prevValue.y - xyValues.y;
            }
        }
        this.prevValue = xyValues;
    };
    BoxAnnotation.prototype.onDpiChanged = function (args) {
        _super.prototype.onDpiChanged.call(this, args);
        this.notifyPropertyChanged(constants_1.PROPERTY.STROKE);
    };
    BoxAnnotation.prototype.toJSON = function () {
        var json = _super.prototype.toJSON.call(this);
        var options = {
            fill: this.fill,
            stroke: this.stroke,
            strokeThickness: this.strokeThickness
        };
        Object.assign(json.options, options);
        return json;
    };
    BoxAnnotation.prototype.checkIsClickedOnAnnotationInternal = function (x, y) {
        var _a = this.getAnnotationBorders(true), x1 = _a.x1, x2 = _a.x2, y1 = _a.y1, y2 = _a.y2;
        return (0, pointUtil_1.testIsInBounds)(x, y, x1, y2, x2, y1);
    };
    BoxAnnotation.prototype.notifyPropertyChanged = function (propertyName) {
        _super.prototype.notifyPropertyChanged.call(this, propertyName);
        var strokePenRelatedProperties = [
            constants_1.PROPERTY.STROKE,
            constants_1.PROPERTY.STROKE_THICKNESS,
            constants_1.PROPERTY.STROKE_DASH_ARRAY,
            constants_1.PROPERTY.OPACITY
        ];
        if (this.strokePenCache && strokePenRelatedProperties.includes(propertyName)) {
            (0, Pen2DCache_1.createPenInCache)(this.strokePenCache, this.stroke, this.strokeThickness, this.opacity);
        }
        var fillBrushRelatedProperties = [constants_1.PROPERTY.FILL, constants_1.PROPERTY.OPACITY];
        if (this.fillBrushCache && fillBrushRelatedProperties.includes(propertyName)) {
            (0, BrushCache_1.createBrushInCache)(this.fillBrushCache, this.fill, this.opacity);
        }
    };
    BoxAnnotation.prototype.updateAdornerInner = function () {
        this.deleteAdorner();
        if (this.isSelected) {
            var _a = this.getAdornerAnnotationBorders(true, true), x1 = _a.x1, x2 = _a.x2, y1 = _a.y1, y2 = _a.y2;
            var svgString = this.svgStringAdornerTemplate(x1, y1, x2, y2);
            var clippedSvgString = this.applySvgClipping(svgString, this.adornerClipping);
            this.svgAdorner = annotationHelpers_1.annotationHelpers.createSvg(clippedSvgString, this.svgAdornerRoot);
        }
    };
    BoxAnnotation.prototype.svgStringAdornerTemplate = function (x1, y1, x2, y2) {
        var colorLine = this.selectionBoxStroke;
        var width = x2 - x1;
        var height = y2 - y1;
        var svg = "<svg xmlns=\"http://www.w3.org/2000/svg\">\n        <rect x=\"".concat(x1, "\" y=\"").concat(y1, "\" width=\"").concat(width, "\" height=\"").concat(height, "\" stroke=\"").concat(colorLine, "\" stroke-width=\"").concat(this.selectionBoxThickness, "px\" fill=\"none\" />\n        ");
        var grips = this.getAdornerAnnotationBorders(false, true);
        if (this.canDragPoint(AnnotationBase_1.EDraggingGripPoint.x1y1)) {
            svg += this.getAnnotationGripSvg(grips.x1, grips.y1);
        }
        if (this.canDragPoint(AnnotationBase_1.EDraggingGripPoint.x2y2)) {
            svg += this.getAnnotationGripSvg(grips.x2, grips.y2);
        }
        if (this.canDragPoint(AnnotationBase_1.EDraggingGripPoint.x2y1)) {
            svg += this.getAnnotationGripSvg(grips.x2, grips.y1);
        }
        if (this.canDragPoint(AnnotationBase_1.EDraggingGripPoint.x1y2)) {
            svg += this.getAnnotationGripSvg(grips.x1, grips.y2);
        }
        svg += "</svg>";
        return svg;
    };
    BoxAnnotation.prototype.drawWithProvider = function (renderContext, linesPen, fillBrush, xCalc, yCalc, rect, viewRect, clipRect) {
        var webAssemblyContext = this.parentSurface.webAssemblyContext2D;
        var args = new webAssemblyContext.SCRTColumnDrawingParams();
        args.forceShaderMethod = true;
        args.verticalChart = this.isVerticalChart;
        args.zeroLineY = this.isVerticalChart ? yCalc.getDataValue(rect.left) : yCalc.getDataValue(rect.bottom);
        args.columnWidth = this.isVerticalChart ? rect.height : rect.width;
        args.clipCoordinates = false; // Prevent stroke drawing at top or bottom when box is partially off the chart
        // ISSUE: If the strokeThickness property is not provided,
        // the fill will be disappeared with large zoom (when the column width will be small or zero)
        // if (args.columnWidth === 0 && this.strokeThickness === 0) {
        //     strokePenCache = this.strokePenFillColoredCache;
        // }
        if (linesPen) {
            args.SetLinesPen(linesPen);
        }
        if (fillBrush) {
            args.SetFillBrush(fillBrush);
        }
        args.viewportWidth = viewRect.width;
        args.viewportHeight = viewRect.height;
        var xMid = this.isVerticalChart ? (rect.top + rect.bottom) / 2 : (rect.left + rect.right) / 2;
        var xVal = xCalc.getDataValue(xMid);
        if (!this.xValues) {
            this.xValues = new webAssemblyContext.SCRTDoubleVector(1);
        }
        else {
            this.xValues.clear();
        }
        this.xValues.push_back(xVal);
        var yVal = this.isVerticalChart ? yCalc.getDataValue(rect.right) : yCalc.getDataValue(rect.top);
        if (!this.yValues) {
            this.yValues = new webAssemblyContext.SCRTDoubleVector(1);
        }
        else {
            this.yValues.clear();
        }
        this.yValues.push_back(yVal);
        args.count = 1;
        var webGlRenderContext = renderContext;
        var nativeContext = webGlRenderContext.getNativeContext();
        webGlRenderContext.setTranslationRotationAndClip(clipRect, viewRect.x, viewRect.y);
        args.SetNativeContext(nativeContext);
        args.SetXValues(this.xValues);
        args.SetYValues(this.yValues);
        args.SetXCoordinateCalculator(xCalc.nativeCalculator);
        args.SetYCoordinateCalculator(yCalc.nativeCalculator);
        this.nativeDrawingProvider.DrawPointsVec(args);
        args.delete();
    };
    return BoxAnnotation;
}(RenderContextAnnotationBase_1.RenderContextAnnotationBase));
exports.BoxAnnotation = BoxAnnotation;
