#include "Math.hh"

namespace Core
{
    Vector2::Vector2() : x(0), y(0)
    {
    }

    Vector2::Vector2(float x, float y) : x(x), y(y)
    {
    }

    Vector2 Vector2::operator+(Vector2 const &other)
    {
        return Vector2(this->x+other.x, this->y+other.y);
    }

    Vector2 Vector2::operator-(Vector2 const &other)
    {
        return Vector2(this->x-other.x, this->y-other.y);
    }

    Vector2 Vector2::operator*(Vector2 const &other)
    {
        return Vector2(this->x*other.x, this->y*other.y);
    }

    Vector2 Vector2::operator/(Vector2 const &other)
    {
        // TODO(Eero): Add Zero checks
        return Vector2(this->x/other.x, this->y/other.y);
    }

    Vector2& Vector2::operator+=(Vector2 const &other)
    {
        this->x += other.x;
        this->y += other.y;
        return *this;
    }

    Vector2& Vector2::operator-=(Vector2 const &other)
    {
        this->x -= other.x;
        this->y -= other.y;
        return *this;
    }

    Vector2& Vector2::operator*=(Vector2 const &other)
    {
        this->x *= other.x;
        this->y *= other.y;
        return *this;
    }

    Vector2& Vector2::operator/=(Vector2 const &other)
    {
        // TODO(Eero): Add Zero checks
        this->x /= other.x;
        this->y /= other.y;
        return *this;
    }

    bool Vector2::operator==(Vector2 const &other)
    {
        return (this->x == other.x && this->y == other.y) ? true : false;
    }

    bool Vector2::operator!=(Vector2 const &other)
    {
        return (this->x != other.x || this->y != other.y) ? true : false;
    }

    Vector2 Vector2::operator*(float const &scalar)
    {
        return Vector2(scalar * this->x, scalar * this->y);
    }

    Vector3::Vector3() : x(0), y(0), z(0), w(1)
    {
    }

    Vector3::Vector3(float x, float y, float z) : x(x), y(y), z(z), w(1)
    {
    }

    Vector3::Vector3(float x, float y, float z, float w) : x(x), y(y), z(z), w(w)
    {
    }

    Vector3 Vector3::operator+(Vector3 const &other)
    {
        return Vector3(this->x+other.x, this->y+other.y, this->z+other.z);
    }

    Vector3 Vector3::operator-(Vector3 const &other)
    {
        return Vector3(this->x-other.x, this->y-other.y, this->z-other.z);
    }

    Vector3 Vector3::operator*(Vector3 const &other)
    {
        return Vector3(this->x*other.x, this->y*other.y, this->z*other.z);
    }

    Vector3 Vector3::operator/(Vector3 const &other)
    {
        // TODO(Eero): Add Zero checks
        return Vector3(this->x/other.x, this->y/other.y, this->z/other.z);
    }

    Vector3& Vector3::operator+=(Vector3 const &other)
    {
        this->x += other.x;
        this->y += other.y;
        this->z += other.z;
        return *this;
    }

    Vector3& Vector3::operator-=(Vector3 const &other)
    {
        this->x -= other.x;
        this->y -= other.y;
        this->z -= other.z;
        return *this;
    }

    Vector3& Vector3::operator*=(Vector3 const &other)
    {
        this->x *= other.x;
        this->y *= other.y;
        this->z *= other.z;
        return *this;
    }

    Vector3& Vector3::operator/=(Vector3 const &other)
    {
        // TODO(Eero): Add Zero checks
        this->x /= other.x;
        this->y /= other.y;
        this->z /= other.z;
        return *this;
    }

    bool Vector3::operator==(Vector3 const &other)
    {
        return (
            this->x == other.x 
            && this->y == other.y 
            && this->z == other.z 
            && this->w == other.w // TODO(Eero): Is w check required?
        ) ? true : false;
    }

    bool Vector3::operator!=(Vector3 const &other)
    {
        return (
            this->x != other.x 
            || this->y != other.y 
            || this->z != other.z 
            || this->w != other.w // TODO(Eero): Is w check required?
        ) ? true : false;
    }

    Vector3 Vector3::operator*(float const &scalar)
    {
        return Vector3(scalar * this->x, scalar * this->y, scalar * this->z);
    }

} // namespace Core