"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.tanh = exports.splitNumber = exports.sign = exports.round = exports.lerpAngleDegrees = exports.lerp = exports.isOdd = exports.isEven = exports.isCircleIntersectingRectangle = exports.inRectangle = exports.getCircleDiscretizedPoints = exports.getAngleDifference = exports.clamp = void 0;
const isaac_typescript_definitions_1 = require("isaac-typescript-definitions");
const direction_1 = require("./direction");
/**
 * Helper function to normalize a number, ensuring that it is within a certain range.
 *
 * - If `num` is less than `min`, then it will be clamped to `min`.
 * - If `num` is greater than `max`, then it will be clamped to `max`.
 */
function clamp(num, min, max) {
    return Math.max(min, Math.min(num, max));
}
exports.clamp = clamp;
function getAngleDifference(angle1, angle2) {
    const subtractedAngle = angle1 - angle2;
    return ((subtractedAngle + 180) % 360) - 180;
}
exports.getAngleDifference = getAngleDifference;
/**
 * Helper function to get an array of equidistant points on the circumference around a circle.
 * Useful for equally distributing things in a circle pattern.
 *
 * @param centerPos A position that represents the center of the center to get the points from.
 * @param radius The radius of the circle.
 * @param numPoints The number of points on the circumference of the circle to get.
 * @param xMultiplier An optional multiplier to get the points around an oval. Default is 1.
 * @param yMultiplier An optional multiplier to get the points around an oval. Default is 1.
 * @param initialDirection By default, the first point on the circle will be on the top center, but
 *                         this can be optionally changed by specifying this argument.
 */
function getCircleDiscretizedPoints(centerPos, radius, numPoints, xMultiplier = 1, yMultiplier = 1, initialDirection = isaac_typescript_definitions_1.Direction.UP) {
    const vector = (0, direction_1.directionToVector)(initialDirection);
    const initialPosition = vector.mul(radius);
    const positions = [];
    for (let i = 0; i < numPoints; i++) {
        const rotatedPosition = initialPosition.Rotated((i * 360) / numPoints);
        rotatedPosition.X *= xMultiplier;
        rotatedPosition.Y *= yMultiplier;
        const positionFromCenter = centerPos.add(rotatedPosition);
        positions.push(positionFromCenter);
    }
    return positions;
}
exports.getCircleDiscretizedPoints = getCircleDiscretizedPoints;
/**
 * Helper function to check if a given position is within a given rectangle.
 *
 * This is an inclusive check, meaning that it will return true if the position is on the border of
 * the rectangle.
 */
function inRectangle(position, topLeft, bottomRight) {
    return (position.X >= topLeft.X &&
        position.X <= bottomRight.X &&
        position.Y >= topLeft.Y &&
        position.Y <= bottomRight.Y);
}
exports.inRectangle = inRectangle;
/**
 * From: https://www.geeksforgeeks.org/check-if-any-point-overlaps-the-given-circle-and-rectangle/
 */
function isCircleIntersectingRectangle(circleCenter, circleRadius, rectangleTopLeft, rectangleBottomRight) {
    const nearestX = Math.max(rectangleTopLeft.X, Math.min(circleCenter.X, rectangleBottomRight.X));
    const nearestY = Math.max(rectangleTopLeft.Y, Math.min(circleCenter.Y, rectangleBottomRight.Y));
    const nearestPointToCircleOnRectangle = Vector(nearestX, nearestY);
    const distanceToCenterOfCircle = nearestPointToCircleOnRectangle.Distance(circleCenter);
    return distanceToCenterOfCircle <= circleRadius;
}
exports.isCircleIntersectingRectangle = isCircleIntersectingRectangle;
function isEven(num) {
    // This is benchmarked to be faster than using the modulus operator by 3%.
    return (num & 1) === 0;
}
exports.isEven = isEven;
function isOdd(num) {
    // This is benchmarked to be faster than using the modulus operator by 3%.
    return (num & 1) === 1;
}
exports.isOdd = isOdd;
function lerp(a, b, pos) {
    return a + (b - a) * pos;
}
exports.lerp = lerp;
function lerpAngleDegrees(aStart, aEnd, percent) {
    return aStart + getAngleDifference(aStart, aEnd) * percent;
}
exports.lerpAngleDegrees = lerpAngleDegrees;
/**
 * If rounding fails, this function returns 0.
 *
 * From: http://lua-users.org/wiki/SimpleRound
 *
 * @param num The number to round.
 * @param numDecimalPlaces Optional. Default is 0.
 */
function round(num, numDecimalPlaces = 0) {
    const roundedString = string.format(`%.${numDecimalPlaces}f`, num);
    const roundedNum = tonumber(roundedString);
    return roundedNum ?? 0;
}
exports.round = round;
/** @returns 1 if n is positive, -1 if n is negative, or 0 if n is 0. */
function sign(n) {
    if (n > 0) {
        return 1;
    }
    if (n < 0) {
        return -1;
    }
    return 0;
}
exports.sign = sign;
/**
 * Breaks a number into chunks of a given size. This is similar to the `String.split` method, but
 * for a number instead of a string.
 *
 * For example, `splitNumber(90, 25)` would return an array with four elements:
 *
 * - [1, 25]
 * - [26, 50]
 * - [51, 75]
 * - [76, 90]
 *
 * @param num The number to split into chunks. This must be a positive integer.
 * @param size The size of each chunk. This must be a positive integer.
 * @param startAtZero Whether to start at 0. Defaults to false. If true, the chunks will start at 0
 *                    instead of 1.
 */
function splitNumber(num, size, startAtZero = false) {
    if (num <= 0) {
        error(`The number to split needs to be a positive number and is instead: ${num}`);
    }
    if (size <= 0) {
        error(`The size to split needs to be a positive number and is instead: ${num}`);
    }
    const chunks = [];
    let start = startAtZero ? 0 : 1;
    while (start <= num) {
        const end = Math.min(start + size - 1, num);
        chunks.push([start, end]);
        start += size;
    }
    return chunks;
}
exports.splitNumber = splitNumber;
function tanh(x) {
    return (Math.exp(x) - Math.exp(-x)) / (Math.exp(x) + Math.exp(-x));
}
exports.tanh = tanh;
