"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var MathUtils = tslib_1.__importStar(require("./MathUtils"));
var Vector2 = /** @class */ (function () {
    function Vector2(x, y) {
        this.x = x;
        this.y = y;
    }
    //#region constructor
    /**
     * Factory acting as constructor for Vector2
     * @param x
     * @param y
     */
    Vector2.create = function (x, y) {
        if (x === void 0) { x = 0; }
        if (y === void 0) { y = 0; }
        return { x: x, y: y };
    };
    //#endregion constructor
    //#region Copy/Clone
    /**
     * Clone function for Vector2
     * @param input
     */
    Vector2.clone = function (input) {
        return { x: input.x, y: input.y };
    };
    /**
     * Copy Vector2 vector
     * @param input
     */
    Vector2.copy = function (from, to) {
        to.x = from.x;
        to.y = from.y;
    };
    //#endregion Copy/Clone
    //#region IsEqual (compare)
    /**
     * Compare two Vector2's on equality (with optional deviation)
     * @param first
     * @param second
     * @param deviation
     */
    Vector2.isEqual = function (first, second, deviation) {
        if (deviation === void 0) { deviation = 0; }
        var diff = Vector2.sub(first, second);
        return Math.abs(diff.x) <= deviation && Math.abs(diff.y) <= deviation;
    };
    //#endregion IsEqual (compare)
    //#region Absolute vector
    /**
     * Creates a new Vector2 with absolute values of components
     * @param input
     */
    Vector2.absoluteComponents = function (input) {
        return { x: Math.abs(input.x), y: Math.abs(input.y) };
    };
    //#endregion Absolute vector
    //#region Normalize vector
    /**
     * Returns normalized Vector2
     * @param vector
     */
    Vector2.normalize = function (vector, length) {
        if (length === void 0) { length = 1.0; }
        var magnitude = Vector2.magnitude(vector);
        if (magnitude === 0) {
            return undefined;
        }
        return Vector2.scalarMultiply(length / magnitude, vector);
    };
    /**
     * Normalizes Vector2 vector
     * @param vector
     */
    Vector2.normalizeInPlace = function (vector, length) {
        if (length === void 0) { length = 1.0; }
        var magnitude = Vector2.magnitude(vector);
        if (magnitude === 0) {
            return;
        }
        Vector2.scalarMultiplyInPlace(length / magnitude, vector);
    };
    //#endregion Normalize vector
    //#region Simple Algebra (addition + substraction)
    /**
     * Returns sum of given Vector2s
     * @param vectors
     */
    Vector2.add = function () {
        var vectors = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            vectors[_i] = arguments[_i];
        }
        var result = Vector2.create();
        var len = vectors.length;
        for (var idx = 0; idx < len; idx++) {
            var vector = vectors[idx];
            result.x += vector.x;
            result.y += vector.y;
        }
        return result;
    };
    /**
     * Sums up given Vector2s and saves it into the first
     * @param vectors
     */
    Vector2.addOnFirst = function () {
        var vectors = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            vectors[_i] = arguments[_i];
        }
        var len = vectors.length;
        if (len > 0) {
            var result = vectors[0];
            var vector = void 0;
            for (var idx = 1; idx < len; idx++) {
                vector = vectors[idx];
                result.x += vector.x;
                result.y += vector.y;
            }
            return result;
        }
        return undefined;
    };
    /**
     * Subtracts second from first Vector2
     * @param first
     * @param second
     */
    Vector2.sub = function (first, second) {
        return { x: first.x - second.x, y: first.y - second.y };
    };
    /**
     * Subtracts given Vector2s from first and saves it into the first
     * @param vectors
     */
    Vector2.subOnFirst = function () {
        var vectors = [];
        for (var _i = 0; _i < arguments.length; _i++) {
            vectors[_i] = arguments[_i];
        }
        var len = vectors.length;
        if (len > 0) {
            var result = vectors[0];
            var vector = void 0;
            for (var idx = 1; idx < len; idx++) {
                vector = vectors[idx];
                result.x -= vector.x;
                result.y -= vector.y;
            }
            return result;
        }
        return undefined;
    };
    //#endregion Simple Algebra
    //#region Products (inner/dot + cross3 + matrix4)
    /**
     * Returns inner product of first and second Vector2
     * @param first
     * @param second
     */
    Vector2.innerProduct = function (first, second) {
        return first.x * second.x + first.y * second.y;
    };
    //#endregion Products (inner + cross + matrix)
    //#region Scalar (addition + multiplication)
    /**
     * Returns Vector2 with offset
     * @param offset
     * @param vector
     */
    Vector2.scalarAdd = function (offset, vector) {
        return {
            x: offset + vector.x,
            y: offset + vector.y,
        };
    };
    /**
     * Adds offset on Vector2 vector
     * @param offset
     * @param vector
     */
    Vector2.scalarAddInPlace = function (offset, vector) {
        vector.x += offset;
        vector.y += offset;
    };
    /**
     * Returns scaled Vector2
     * @param scalar
     * @param vector
     */
    Vector2.scalarMultiply = function (scalar, vector) {
        return {
            x: scalar * vector.x,
            y: scalar * vector.y,
        };
    };
    /**
     * Scales Vector2 vector
     * @param scalar
     * @param vector
     */
    Vector2.scalarMultiplyInPlace = function (scalar, vector) {
        vector.x *= scalar;
        vector.y *= scalar;
    };
    //#endregion Scalar
    //#region Magnitude (length)
    /**
     * Returns magnitude (length) of Vector2
     * @param vector
     */
    Vector2.magnitude = function (vector) {
        return Math.sqrt(vector.x * vector.x + vector.y * vector.y);
    };
    /**
     * Returns squared magnitude of Vector2
     * @param vector
     */
    Vector2.magnitudeSquared = function (vector) {
        return vector.x * vector.x + vector.y * vector.y;
    };
    //#endregion Magnitude (length)
    //#region Distance
    /**
     * Returns distance between first and second Vector2
     * @param first
     * @param second
     */
    Vector2.distance = function (first, second) {
        var x = first.x - second.x;
        var y = first.y - second.y;
        return Math.sqrt(x * x + y * y);
    };
    //#endregion Distance
    //#region Min/Max
    /**
     * Returns first parameter with the maximum entries from other Vector2 parameters
     * @param input
     * @oaram vectors
     */
    Vector2.maximizeInPlace = function (input) {
        var vectors = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            vectors[_i - 1] = arguments[_i];
        }
        for (var i = 0, il = vectors.length; i < il; ++i) {
            var v = vectors[i];
            input.x = Math.max(input.x, v.x);
            input.y = Math.max(input.y, v.y);
        }
    };
    /**
     * Returns first parameter with the minimum entries from other Vector2 parameters
     * @param input
     * @oaram vectors
     */
    Vector2.minimizeInPlace = function (input) {
        var vectors = [];
        for (var _i = 1; _i < arguments.length; _i++) {
            vectors[_i - 1] = arguments[_i];
        }
        for (var i = 0, il = vectors.length; i < il; ++i) {
            var v = vectors[i];
            input.x = Math.min(input.x, v.x);
            input.y = Math.min(input.y, v.y);
        }
    };
    //#endregion Min/Max
    //#region Reverse (Negation)
    /**
     * Returns a Vector2 with negated components
     * @param vector
     */
    Vector2.reverse = function (vector) {
        return {
            x: -vector.x,
            y: -vector.y,
        };
    };
    /**
     * Negates components of Vector2 vector
     * @param vector
     */
    Vector2.reverseInPlace = function (vector) {
        vector.x = -vector.x;
        vector.y = -vector.y;
        return vector;
    };
    //#endregion Reverse (Negation)
    //#region Angle / Rotation
    /**
     * calculate angle (in radians) between two direction vectors (Vector2)
     * @param v
     * @param w
     */
    Vector2.angleBetween = function (v, w) {
        var magW = Math.sqrt(w.x * w.x + w.y * w.y);
        var magV = Math.sqrt(v.x * v.x + v.y * v.y);
        var dotVW = v.x * w.x + v.y * w.y;
        var theta = dotVW / (magW * magV);
        return Math.acos(MathUtils.clamp(theta, -1, 1));
    };
    //#endregion Angle / Rotation
    //#region Convenience (Stringify + HasInvalidEntries)
    /** Convenience function to stringify Vector2 */
    Vector2.stringify = function (v, precision) {
        if (precision === void 0) { precision = 3; }
        return ("{x: " + v.x.toFixed(precision) + ", y: " + v.y.toFixed(precision) + "}");
    };
    /** Convenience function to check if Vector2 has invalid entries (no Not-a-Number, on infinite values) */
    Vector2.hasInvalidEntries = function (v) {
        var product = v.x * v.y;
        return isNaN(product) || !isFinite(product);
    };
    return Vector2;
}());
exports.Vector2 = Vector2;
