module ecs_utils.math.vector;

import ecs_utils.utils;

struct vec2
{
    this(float v) @nogc nothrow
    {
        x = v;
        y = v;
    }
    
    this(float x, float y) @nogc nothrow
    {
        this.x = x;
        this.y = y;
    }

    union
    {
        struct
        {
            float x;
            float y;
        }
        float[2] data;
    }

    vec2 opBinary(string op)(vec2 v)
    {
        static if (op == "+") return vec2(x + v.x, y + v.y);
        else static if (op == "-") return vec2(x - v.x, y - v.y);
        else static if (op == "*") return vec2(x * v.x, y * v.y);
        else static if (op == "/") return vec2(x / v.x, y / v.y);
        else static assert(0, "Operator "~op~" not implemented");
    }

    vec2 opBinary(string op)(float v)
    {
        static if (op == "+") return vec2(x + v, y + v);
        else static if (op == "-") return vec2(x - v, y - v);
        else static if (op == "*") return vec2(x * v, y * v);
        else static if (op == "/") return vec2(x / v, y / v);
        else static assert(0, "Operator "~op~" not implemented");
    }

    vec2 opUnary(string op)()if (op == "-")
    {
        return vec2(-x,-y);
    }

    ivec2 opCast()
    {
        return ivec2(cast(int)x,cast(int)y);
    }

    void opOpAssign(string op)(vec2 v)
    {
        static if (op == "+")
        {
            x += v.x;
            y += v.y;
        }
        else static if (op == "-")
        {
            x -= v.x;
            y -= v.y;
        }
        else static if (op == "*")
        {
            x *= v.x;
            y *= v.y;
        }
        else static if (op == "/")
        {
            x /= v.x;
            y /= v.y;
        }
        else static assert(0, "Operator "~op~" not implemented");
    }

    float length2()
    {
        return x*x + y*y;
    }

    float length()
    {
        return sqrtf(length2);
    }

    float fastSqrLength()
    {
        return rsqrt(length2);
    }

    vec2 normalize()
    {
        return this * fastSqrLength();
    }
}

float dot(vec2 a, vec2 b)
{
    return a.x*b.x + a.y*b.y;
}

struct vec4
{
    union
    {
        struct
        {
            float x;
            float y;
            float z;
            float w;
        }
        float[4] data;
    }

    this(float v) @nogc nothrow
    {
        x = v;
        y = v;
        z = v;
        w = v;
    }

    this(float x, float y, float z, float w) @nogc nothrow
    {
        this.x = x;
        this.y = y;
        this.z = z;
        this.w = w;
    }

    vec4 opBinary(string op)(float v)
    {
        static if (op == "+") return vec4(x + v, y + v, z + v, w + v);
        else static if (op == "-") return vec4(x - v, y - v, z - v, w - v);
        else static if (op == "*") return vec4(x * v, y * v, z * v, w * v);
        else static if (op == "/") return vec4(x / v, y / v, z / v, w / v);
        else static assert(0, "Operator "~op~" not implemented");
    }
}

struct ivec2
{
    union
    {
        struct
        {
            int x;
            int y;
        }
        int[2] data;
    }
    
    this(int v) @nogc nothrow
    {
        x = v;
        y = v;
    }

    this(int x, int y) @nogc nothrow
    {
        this.x = x;
        this.y = y;
    }

    ivec2 opBinary(string op, T)(T v)
    {
        static if (op == "+") return ivec2(x + v, y + v);
        else static if (op == "-") return ivec2(x - v, y - v);
        else static if (op == "*") return ivec2(x * v, y * v);
        else static if (op == "/") return ivec2(x / v, y / v);
        else static assert(0, "Operator "~op~" not implemented");
    }

    vec2 opCast()
    {
        return vec2(x,y);
    }
}

struct ivec4
{
    union
    {
        struct
        {
            int x;
            int y;
            int z;
            int w;
        }
        int[4] data;
    }

    this(int v) @nogc nothrow
    {
        x = v;
        y = v;
        z = v;
        w = v;
    }
    
    this(int x, int y, int z, int w) @nogc nothrow
    {
        this.x = x;
        this.y = y;
        this.z = z;
        this.w = w;
    }
}