"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.hitTestHelpersRectangleSeries = void 0;
var ColumnMode_1 = require("../../../../types/ColumnMode");
var vectorToArray_1 = require("../../../../utils/vectorToArray");
function testIsYHit(yValues, y1Values, yCoordinateCalculator, yHitCoord, defaultY1, resPointIndex, columnYMode) {
    var yValue = yValues ? yValues.get(resPointIndex) : 1;
    var y1Value = y1Values ? y1Values.get(resPointIndex) : defaultY1;
    var top = yValue;
    var bottom = y1Value;
    switch (columnYMode) {
        case ColumnMode_1.EColumnYMode.TopBottom:
            break;
        case ColumnMode_1.EColumnYMode.TopHeight:
            bottom = yValue - y1Value;
            break;
        case ColumnMode_1.EColumnYMode.CenterHeight:
            var halfHeight = y1Value / 2;
            top = yValue + halfHeight;
            bottom = yValue - halfHeight;
            break;
    }
    var topCoord = yCoordinateCalculator.getCoordinate(top);
    var bottomCoord = yCoordinateCalculator.getCoordinate(bottom);
    var maxYValue = Math.max(topCoord, bottomCoord);
    var minYValue = Math.min(topCoord, bottomCoord);
    return minYValue <= yHitCoord && yHitCoord <= maxYValue;
}
/**
 * Hit-test function for BoxSeries or PolarColumnSeries
 * Only for sorted data without overlapping columns only for columnXMode = EColumnMode.Mid or EColumnMode.Start
 * Using binary search, time complexity O(log(N))
 */
function hitTestForBoxSorted(wasmContext, xCoordinateCalculator, yCoordinateCalculator, xValues, yValues, y1Values, xHitCoord, yHitCoord, defaultY1, columnCoordWidth, columnXMode, columnYMode, isPolar) {
    var _a;
    var xHitValue = xCoordinateCalculator.getDataValue(xHitCoord);
    var hitValuesArray = [[xHitValue, xHitCoord]];
    if (isPolar) {
        var xHitCoordMinus2Pi = xHitCoord - 2 * Math.PI;
        var xHitValueMinus2Pi = xCoordinateCalculator.getDataValue(xHitCoordMinus2Pi);
        hitValuesArray.push([xHitValueMinus2Pi, xHitCoordMinus2Pi]);
        var xHitCoordPlus2Pi = xHitCoord + 2 * Math.PI;
        var xHitValuePlus2Pi = xCoordinateCalculator.getDataValue(xHitCoordPlus2Pi);
        hitValuesArray.push([xHitValuePlus2Pi, xHitCoordPlus2Pi]);
    }
    var xVectorSize = xValues.size();
    var xOffsetDirection = xCoordinateCalculator.isFlipped ? -1 : 1;
    var xCoordOffset = columnXMode === ColumnMode_1.EColumnMode.Mid ? 0 : columnCoordWidth / 2;
    var xValueOffset = xCoordinateCalculator.getDataWidth(xCoordOffset);
    var getNearestXIndexFn = function (xHitValue$, xHitCoord$) {
        var xIndex$ = wasmContext.NumberUtil.FindIndex(xValues, xHitValue$ - xValueOffset, wasmContext.SCRTFindIndexSearchMode.Nearest, true);
        if (xIndex$ === -1)
            return { index: -1, dist: Number.MAX_VALUE, xCoord: undefined, xHitCoord: undefined };
        var xCoord$ = xCoordinateCalculator.getCoordinate(xValues.get(xIndex$));
        var dist$ = Math.abs(xCoord$ + xOffsetDirection * xCoordOffset - xHitCoord$);
        return { index: xIndex$, dist: dist$, xCoord: xCoord$, xHitCoord: xHitCoord$ };
    };
    var resIndex = -1;
    var resDist = Number.MAX_VALUE;
    var resXCoord = undefined;
    var resXHitCoord = undefined;
    hitValuesArray.forEach(function (_a) {
        var value = _a[0], coord = _a[1];
        var r = getNearestXIndexFn(value, coord);
        if (r.index >= 0 && r.dist < resDist) {
            resIndex = r.index;
            resDist = r.dist;
            resXCoord = r.xCoord;
            resXHitCoord = r.xHitCoord;
        }
    });
    if (resIndex === -1)
        return { isHit: false, nearestPointIndex: -1, isWithinDataBounds: false };
    var isXHit = resDist <= columnCoordWidth / 2;
    var isYHit = testIsYHit(yValues, y1Values, yCoordinateCalculator, yHitCoord, defaultY1, resIndex, columnYMode);
    var isWithinDataBounds = false;
    if (resIndex > 0 && resIndex < xVectorSize - 1) {
        isWithinDataBounds = true;
    }
    if (xValues.size() <= 1) {
        isWithinDataBounds = isXHit;
    }
    else {
        if (xCoordinateCalculator.isFlipped) {
            if (resIndex === 0 && (resXHitCoord <= resXCoord + xOffsetDirection * xCoordOffset || isXHit)) {
                isWithinDataBounds = true;
            }
            if (resIndex === xVectorSize - 1 &&
                (resXHitCoord >= resXCoord + xOffsetDirection * xCoordOffset || isXHit)) {
                isWithinDataBounds = true;
            }
        }
        else {
            if (resIndex === 0 && (resXHitCoord >= resXCoord + xOffsetDirection * xCoordOffset || isXHit)) {
                isWithinDataBounds = true;
            }
            if (resIndex === xVectorSize - 1 &&
                (resXHitCoord <= resXCoord + xOffsetDirection * xCoordOffset || isXHit)) {
                isWithinDataBounds = true;
            }
        }
    }
    var isCategoryAxis = xCoordinateCalculator.isCategoryCoordinateCalculator;
    var xValue = isCategoryAxis ? resIndex : xValues.get(resIndex);
    var yValue = yValues.get(resIndex);
    var x1Value = undefined;
    var y1Value = (_a = y1Values === null || y1Values === void 0 ? void 0 : y1Values.get) === null || _a === void 0 ? void 0 : _a.call(y1Values, resIndex);
    return {
        nearestPointIndex: resIndex,
        isHit: isXHit && isYHit,
        isWithinDataBounds: isWithinDataBounds,
        xValue: xValue,
        yValue: yValue,
        x1Value: x1Value,
        y1Value: y1Value
    };
}
/**
 * Hit-test function for BoxSeries or PolarColumnSeries
 * Iterates over all data points, time complexity O(N)
 */
function hitTestForBoxUnsorted(wasmContext, xCoordinateCalculator, yCoordinateCalculator, xValues, x1Values, yValues, y1Values, xHitCoord, yHitCoord, defaultY1, columnCoordWidth, columnXMode, columnYMode, isVertical, isPolar) {
    var _a, _b;
    var xVectorSize = xValues.size();
    var halfColumn = columnCoordWidth / 2;
    var resIndex = -1;
    var resCoordDist = Number.MAX_VALUE;
    var resIsHit = false;
    var resXHitCoord = undefined;
    var resLeftDataBoundCoord = Number.MAX_VALUE;
    var resRightDataBoundCoord = Number.NEGATIVE_INFINITY;
    var calcDistFn = function (left$, right$, val$) {
        var a = right$ - val$;
        var b = val$ - left$;
        return a >= 0 && b >= 0 ? 0 : Math.min(Math.abs(a), Math.abs(b));
    };
    var testIsXHitFn = function (left$, right$) {
        var r = calcDistFn(left$, right$, xHitCoord);
        var dist$ = r;
        var xHitCoord$ = xHitCoord;
        if (isPolar && !isVertical) {
            var xHitCoordMinus2Pi = xHitCoord - 2 * Math.PI;
            var xHitCoordPlus2Pi = xHitCoord + 2 * Math.PI;
            [xHitCoordMinus2Pi, xHitCoordPlus2Pi].forEach(function (c) {
                var r = calcDistFn(left$, right$, c);
                if (r < dist$) {
                    dist$ = r;
                    xHitCoord$ = c;
                }
            });
        }
        return { xCoordDist: dist$, xHitCoord: xHitCoord$, isHit: dist$ === 0 };
    };
    var updateResValuesFn = function (left$, right$, index$) {
        // Calculating data bounds
        if (left$ < resLeftDataBoundCoord)
            resLeftDataBoundCoord = left$;
        if (right$ > resRightDataBoundCoord)
            resRightDataBoundCoord = right$;
        var isYHit$ = testIsYHit(yValues, y1Values, yCoordinateCalculator, yHitCoord, defaultY1, index$, columnYMode);
        var _a = testIsXHitFn(left$, right$), isXHit$ = _a.isHit, xCoordDist$ = _a.xCoordDist, xHitCoord$ = _a.xHitCoord;
        var isBothHit$ = isXHit$ && isYHit$;
        if (resIsHit) {
            if (isBothHit$ && xCoordDist$ < resCoordDist) {
                resIndex = index$;
                resCoordDist = xCoordDist$;
                resXHitCoord = xHitCoord$;
            }
        }
        else {
            if (isBothHit$) {
                resIsHit = true;
                resIndex = index$;
                resCoordDist = xCoordDist$;
                resXHitCoord = xHitCoord$;
            }
            else {
                if (xCoordDist$ < resCoordDist) {
                    resIndex = index$;
                    resCoordDist = xCoordDist$;
                    resXHitCoord = xHitCoord$;
                }
            }
        }
    };
    var isFlippedX = xCoordinateCalculator.isFlipped;
    var xVectorView = (0, vectorToArray_1.vectorToArrayViewF64)(xValues, wasmContext);
    var x1VectorView = x1Values ? (0, vectorToArray_1.vectorToArrayViewF64)(x1Values, wasmContext) : undefined;
    switch (columnXMode) {
        case ColumnMode_1.EColumnMode.Mid:
            for (var i = 0; i < xVectorSize; i++) {
                var xValue_1 = xVectorView[i];
                var xCoord = xCoordinateCalculator.getCoordinate(xValue_1);
                var left = xCoord - halfColumn;
                var right = xCoord + halfColumn;
                updateResValuesFn(left, right, i);
            }
            break;
        case ColumnMode_1.EColumnMode.Start:
            for (var i = 0; i < xVectorSize; i++) {
                var xValue_2 = xVectorView[i];
                var xCoord = xCoordinateCalculator.getCoordinate(xValue_2);
                var left = isFlippedX ? xCoord - columnCoordWidth : xCoord;
                var right = isFlippedX ? xCoord : xCoord + columnCoordWidth;
                updateResValuesFn(left, right, i);
            }
            break;
        // case EColumnMode.Width:
        //     let xSum = 0;
        //     for (let i = 0; i < xVectorSize; i++) {
        //         const xValue = xVectorView[i];
        //         const xLeft = xSum;
        //         const xRight = xSum + xValue;
        //         xSum += xValue;
        //         const left = xCoordinateCalculator.getCoordinate(xLeft);
        //         const right = xCoordinateCalculator.getCoordinate(xRight);
        //         isFlippedX ? updateResValuesFn(right, left, i) : updateResValuesFn(left, right, i);
        //     }
        //     break;
        case ColumnMode_1.EColumnMode.MidWidth:
            for (var i = 0; i < xVectorSize; i++) {
                var xValue_3 = xVectorView[i];
                var width = x1VectorView[i];
                var left = xCoordinateCalculator.getCoordinate(xValue_3 - width / 2);
                var right = xCoordinateCalculator.getCoordinate(xValue_3 + width / 2);
                isFlippedX ? updateResValuesFn(right, left, i) : updateResValuesFn(left, right, i);
            }
            break;
        case ColumnMode_1.EColumnMode.StartWidth:
            for (var i = 0; i < xVectorSize; i++) {
                var xValue_4 = xVectorView[i];
                var width = x1VectorView[i];
                var left = xCoordinateCalculator.getCoordinate(xValue_4);
                var right = xCoordinateCalculator.getCoordinate(xValue_4 + width);
                isFlippedX ? updateResValuesFn(right, left, i) : updateResValuesFn(left, right, i);
            }
            break;
        case ColumnMode_1.EColumnMode.StartEnd:
            for (var i = 0; i < xVectorSize; i++) {
                var leftValue = xVectorView[i];
                var rightValue = x1VectorView[i];
                var left = xCoordinateCalculator.getCoordinate(leftValue);
                var right = xCoordinateCalculator.getCoordinate(rightValue);
                isFlippedX ? updateResValuesFn(right, left, i) : updateResValuesFn(left, right, i);
            }
            break;
    }
    if (resIndex === -1)
        return { isHit: false, nearestPointIndex: -1, isWithinDataBounds: false };
    var isCategoryAxis = xCoordinateCalculator.isCategoryCoordinateCalculator;
    var xValue = isCategoryAxis ? resIndex : xValues.get(resIndex);
    var yValue = yValues.get(resIndex);
    var x1Value = isCategoryAxis ? resIndex : (_a = x1Values === null || x1Values === void 0 ? void 0 : x1Values.get) === null || _a === void 0 ? void 0 : _a.call(x1Values, resIndex);
    var y1Value = (_b = y1Values === null || y1Values === void 0 ? void 0 : y1Values.get) === null || _b === void 0 ? void 0 : _b.call(y1Values, resIndex);
    return {
        isHit: resCoordDist === 0 &&
            testIsYHit(yValues, y1Values, yCoordinateCalculator, yHitCoord, defaultY1, resIndex, columnYMode),
        nearestPointIndex: resIndex,
        isWithinDataBounds: resLeftDataBoundCoord <= resXHitCoord && resXHitCoord <= resRightDataBoundCoord,
        xValue: xValue,
        x1Value: x1Value,
        yValue: yValue,
        y1Value: y1Value
    };
}
/**
 * Hit-tests BoxSeries and Polar Column Series
 */
function hitTestForBox(wasmContext, xCoordinateCalculator, yCoordinateCalculator, xValues, x1Values, yValues, y1Values, xHitCoord, yHitCoord, defaultY1, columnCoordWidth, columnXMode, columnYMode, isVertical, isSorted, isPolar) {
    if (isVertical) {
        return hitTestForBoxUnsorted(wasmContext, xCoordinateCalculator, yCoordinateCalculator, xValues, x1Values, yValues, y1Values, xHitCoord, yHitCoord, defaultY1, columnCoordWidth, columnXMode, columnYMode, true, isPolar);
    }
    if (isSorted && (columnXMode === ColumnMode_1.EColumnMode.Mid || columnXMode === ColumnMode_1.EColumnMode.Start)) {
        return hitTestForBoxSorted(wasmContext, xCoordinateCalculator, yCoordinateCalculator, xValues, yValues, y1Values, xHitCoord, yHitCoord, defaultY1, columnCoordWidth, columnXMode, columnYMode, isPolar);
    }
    else {
        return hitTestForBoxUnsorted(wasmContext, xCoordinateCalculator, yCoordinateCalculator, xValues, x1Values, yValues, y1Values, xHitCoord, yHitCoord, defaultY1, columnCoordWidth, columnXMode, columnYMode, false, isPolar);
    }
}
exports.hitTestHelpersRectangleSeries = {
    hitTestForBoxSorted: hitTestForBoxSorted,
    hitTestForBoxUnsorted: hitTestForBoxUnsorted,
    hitTestForBox: hitTestForBox
};
