// https://evanw.github.io/lightgl.js/docs/vector.html

import DirtyPool from '../core/dirtypool'

const { sin, cos, sqrt, atan2, abs } = Math

const hypot = Math.hypot || function() {
    let y = 0
    const length = arguments.length

    for (let i = 0; i < length; i++) {
        if (arguments[i] === Infinity || arguments[i] === -Infinity) {
            return Infinity
        }
        y += arguments[i] * arguments[i]
    }
    return Math.sqrt(y)
}

export default class Vector {
    constructor (x = 0, y = 0) {
        this.x = x
        this.y = y
    }

    static of (x, y) {
        return new Vector(x, y)
    }

    xy (x, y) {
        this.x = x
        this.y = y
        return this
    }

    copy () {
        return Vector.of(this.x, this.y)
    }

    pool () {
        return pool.get().xy(this.x, this.y)
    }

    static resetPool () {
        pool.reset()
    }

    dot (v) {
        return this.x * v.x + this.y * v.y
    }

    length () {
        // this.l = this.l || hypot(this.x, this.y)
        // return this.l
        return hypot(this.x, this.y)
    }

    unit () {
        return this.divide(this.length())
    }

    add (vec) {
        this.x += vec.x
        this.y += vec.y
        return this
    }

    addXY (x, y) {
        this.x += x
        this.y += y
        return this
    }

    subtract (vec) {
        this.x -= vec.x
        this.y -= vec.y
        return this
    }

    multiply (l) {
        this.x *= l
        this.y *= l
        return this
    }

    divide (l) {
        this.x /= l
        this.y /= l
        return this
    }

    rotate(angle) {
        const x = this.x * cos(angle) - this.y * sin(angle)
        const y = this.x * sin(angle) + this.y * cos(angle)

        this.x = x
        this.y = y

        return this
    }

    limit (max) {
        const l = this.length()
        if (l > max) {
            this.divide(l).multiply(max)
        }
        return this
    }

    angle () {
        return atan2(this.y , this.x)
    }

    static intersect1 (v1, v2, v3 ,v4) {
        const a1 = v2.y - v1.y
        const b1 = v1.x - v2.x
        const c1 = (v2.x * v1.y) - (v1.x * v2.y)

        const r3 = ((a1 * v3.x) + (b1 * v3.y) + c1)
        const r4 = ((a1 * v4.x) + (b1 * v4.y) + c1)

        if ((r3 != 0) && (r4 != 0) && ((r3 * r4) >= 0.00000000000001)) {
            return null
        }

        const a2 = v4.y - v3.y
        const b2 = v3.x - v4.x;
        const c2 = (v4.x * v3.y) - (v3.x * v4.y);

        const r1 = (a2 * v1.x) + (b2 * v1.y) + c2;
        const r2 = (a2 * v2.x) + (b2 * v2.y) + c2;

        if ((r1 != 0) && (r2 != 0) && ((r1 * r2) >= 0.00000000000001)) {
            return null
        }


        const denom = (a1 * b2) - (a2 * b1);

        if (denom == 0) {
            return null
        }

        const offset = denom < 0 ? -denom / 2 : denom / 2

        const numx = (b1 * c2) - (b2 * c1)
        const x = numx < 0 ? (numx - offset) / denom : (numx + offset) / denom

        const numy = (a2 * c1) - (a1 * c2)
        const y = numy < 0 ? (numy - offset) / denom : (numy + offset) / denom

        return Vector.of(x, y)
    }

    static intersect (v1, v2, v3 ,v4) {
        const denominator = ((v4.y - v3.y) * (v2.x - v1.x)) - ((v4.x - v3.x) * (v2.y - v1.y))
        if (denominator === 0) {
            return null
        }

        const a = v1.y - v3.y
        const b = v1.x - v3.x

        const numerator1 = ((v4.x - v3.x) * a) - ((v4.y - v3.y) * b)
        const numerator2 = ((v2.x - v1.x) * a) - ((v2.y - v1.y) * b)

        const r1 = numerator1 / denominator
        const r2 = numerator2 / denominator

        const onLine1 = (r1 > 0 && r1 < 1)
        const onLine2 = (r2 > 0 && r2 < 1)

        if (!onLine1 || !onLine2) return null

        return Vector.of(v1.x + (a * (v2.x - v1.x)), v1.y + (a * (v2.y - v1.y)))
    }
}

const pool = new DirtyPool(100, () => new Vector())
