export class Rectangle {
    array: [number, number, number, number];

    constructor(array: [number, number, number, number]) {
        this.array = array;
    }

    static from_meta(meta: Rectangular): Rectangle {
        return new Rectangle([meta.x, meta.y, meta.width, meta.height]);
    }

    get x() { return this.array[0]; }

    set x(x: number) { this.array[0] = x; }

    get y() { return this.array[1]; }

    set y(y: number) { this.array[1] = y; }

    get width(): number { return this.array[2]; }

    set width(width: number) { this.array[2] = width; }

    get height() { return this.array[3]; }

    set height(height: number) { this.array[3] = height; }

    apply(other: Rectangle): this {
        this.x += other.x;
        this.y += other.y;
        this.width += other.width;
        this.height += other.height;
        return this;
    }

    clamp(other: Rectangular) {
        this.x = Math.max(other.x, this.x);
        this.y = Math.max(other.y, this.y);

        let tend = this.x + this.width,
            oend = other.x + other.width;
        if (tend > oend) {
            this.width = oend - this.x;
        }

        tend = this.y + this.height;
        oend = other.y + other.height;
        if (tend > oend) {
            this.height = oend - this.y;
        }
    }

    clone(): Rectangle {
        return new Rectangle([
            this.array[0],
            this.array[1],
            this.array[2],
            this.array[3]
        ]);
    }

    contains(other: Rectangular): boolean {
        return (
            this.x <= other.x &&
            this.y <= other.y &&
            this.x + this.width >= other.x + other.width &&
            this.y + this.height >= other.y + other.height
        );
    }

    diff(other: Rectangular): Rectangle {
        return new Rectangle([
            other.x - this.x,
            other.y - this.y,
            other.width - this.width,
            other.height - this.height
        ]);
    }

    eq(other: Rectangular): boolean {
        return (
            this.x == other.x &&
            this.y == other.y &&
            this.width == other.width &&
            this.height == other.height
        );
    }

    fmt(): string {
        return `Rect(${[this.x, this.y, this.width, this.height]})`;
    }

    intersects(other: Rectangular): boolean {
        return (this.x < (other.x + other.width) && (this.x + this.width) > other.x)
            && (this.y < (other.y + other.height) && (this.y + this.height) > other.y);
    }
}
