import { PRNG } from "../GlobalVariables/GlobalVariables";

export class Point2D
{
    #x = 0;
    #y = 0;
    /**
     * Point2D object
     * @param {Number} x 
     * @param {Number} y 
     */
    constructor(x = 0, y = 0)
    {
        this.#x = Math.floor(x);
        this.#y = Math.floor(y);
    }

    getX() {
        return this.#x;
    };

    setX(x) {
        this.#x = x;
    };

    getY() {
        return this.#y;
    };

    setY(y) {
        this.#y = y;
    };

    /**
     * 
     * @param {Point2D} a 
     * @param {Point2D} b 
     */
    static isEqual(a, b)
    {
        return (a.getX() === b.getX() && a.getY() === b.getY());
    }
}

export class PointInt2D
{
    #x = 0;
    #y = 0;
    /**
     * PointInt2D object
     * @param {Number} x 
     * @param {Number} y 
     */
    constructor(x = 0, y = 0)
    {
        this.setX(x);
        this.setY(y);
    }

    getX() {
        return this.#x;
    };

    setX(x) {
        this.#x = Math.trunc(x);
        if(this.#x === -0) this.#x = 0;
    };

    getY() {
        return this.#y;
    };

    setY(y) {
        this.#y = Math.trunc(y);
        if(this.#y === -0) this.#y = 0;
    };

    /**
     * 
     * @param {Number} x 
     */
    divideBy(x)
    {
        if(x !== 0)
        {
            this.#x = Math.trunc(this.#x / x);
            this.#y = Math.trunc(this.#y / x);
            return true;
        }
        return false;
    };

    multiplyBy(x)
    {
        this.#x = Math.trunc(this.#x * x);
        this.#y = Math.trunc(this.#y * x);
    }

    /**
     * 
     * @param {PointInt2D} a 
     * @param {PointInt2D} b 
     */
    static isEqual(a, b)
    {
        return (a.getX() === b.getX() && a.getY() === b.getY());
    }
}

/**
 * 
 * @param {Point2D} pointA 
 * @param {Point2D} pointB 
 * @param {Number} a 
 * @returns 
 */
export function interpolate2D(pointA, pointB, a) {
    return (new Point2D(interpolate(pointA.getX(), pointB.getX(), a), interpolate(pointA.getY(), pointB.getY(), a)));
}

/**
 * 
 * @param {Number} num 
 * @param {Number} min 
 * @param {Number} max 
 * @returns 
 */
export function clampNumber(num, min, max) {
    return Math.min(Math.max(num, min), max);
}

/**
 * 
 * @param {Point2D} point 
 * @param {Point2D} min 
 * @param {Point2D} max 
 * @returns 
 */
export function clamp2D(point, min, max) {
    return new Point2D(Math.min(Math.max(point.getX(), min.getX()), max.getX()), 
    Math.min(Math.max(point.getY(), min.getY()), max.getY()));
}

/**
 * 
 * @param {Number} x 
 * @param {Number} y 
 * @param {Number} a 
 * @returns 
 */
export function interpolate(x, y, a) {
    return x * (1 - a) + y * a;
}

/**
 * careful with delta time! it can be laggy
 * @param {Number} x 
 * @param {Number} y 
 * @param {Number} a 
 * @returns 
 */
export function interpolateCos(x, y, a) {
    let m = (1-Math.cos(a*Math.PI))/2;
    return (x*(1-m)+y*m);
}

/**
 * 'lin', 'cos'
 * @param {Number} x 
 * @param {Number} y 
 * @param {Number} a 
 * @param {String} f 
 */
export function interpolateWith(x, y, a, f) {
    switch (f) {
        case 'lin':
            return interpolate(x, y, a);
        case 'cos':
            return interpolateCos(x, y, a);
        default:
            return interpolate(x, y, a);
    }
}

/**
 * 
 * @param {Number} x value between a and b
 * @param {Number} a minRange
 * @param {Number} b maxRange
 * @param {Number} c desiredMaxRange
 * @param {Number} d desiredMinRange
 * @returns 
 */
export function mapRange(x, a, b, c, d) {
    return (x-a)/(b-a) * (d-c) + c;
}

/**
 * Returns a random integer between min (inclusive) and max (inclusive).
 * The value is no lower than min (or the next integer greater than min
 * if min isn't an integer) and no greater than max (or the next integer
 * lower than max if max isn't an integer).
 * @param {Number} min 
 * @param {Number} max 
 * @returns 
 */
export function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(PRNG() * (max - min + 1)) + min;
}

/**
 * 
 * @param {Array} array 
 * @returns 
 */
export function selectRandom(array) {
    if(array.length < 1) return null;
    return array[getRandomInt(0, array.length - 1)];
}

/**
 * 
 * @param {Number} val 
 * @param {Number} by 
 * @returns 
 */
export function integerDivision(val, by){
    return (val - val % by) / by;
}