﻿using System;

namespace Oni
{
    internal struct Vector2 : IEquatable<Vector2>
    {
        public float X;
        public float Y;

        public Vector2(float x, float y)
        {
            X = x;
            Y = y;
        }

        public Vector2(float all)
        {
            X = all;
            Y = all;
        }

        public static Vector2 operator +(Vector2 v1, Vector2 v2) => new Vector2
        {
            X = v1.X + v2.X,
            Y = v1.Y + v2.Y
        };

        public static Vector2 operator -(Vector2 v1, Vector2 v2) => new Vector2
        {
            X = v1.X - v2.X,
            Y = v1.Y - v2.Y
        };

        public static float Dot(Vector2 v1, Vector2 v2) => v1.X * v2.X + v1.Y * v2.Y;

        public static Vector2 Normalize(Vector2 v) => v * (1.0f / v.Length());

        public void Normalize()
        {
            float f = 1.0f / Length();

            X *= f;
            Y *= f;
        }

        public float Length() => FMath.Sqrt(X * X + Y * Y);

        public static Vector2 operator *(Vector2 v, float s)
        {
            v.X *= s;
            v.Y *= s;

            return v;
        }

        public static Vector2 operator *(float s, Vector2 v)
        {
            v.X *= s;
            v.Y *= s;

            return v;
        }

        public static Vector2 operator /(Vector2 v, float s) => v * (1.0f / s);

        public static Vector2 Min(Vector2 v1, Vector2 v2) => new Vector2
        {
            X = (v1.X < v2.X) ? v1.X : v2.X,
            Y = (v1.Y < v2.Y) ? v1.Y : v2.Y
        };

        public static Vector2 Max(Vector2 v1, Vector2 v2) => new Vector2
        {
            X = (v1.X > v2.X) ? v1.X : v2.X,
            Y = (v1.Y > v2.Y) ? v1.Y : v2.Y
        };

        public static bool operator ==(Vector2 v1, Vector2 v2) => v1.X == v2.X && v1.Y == v2.Y;
        public static bool operator !=(Vector2 v1, Vector2 v2) => v1.X != v2.X || v1.Y != v2.Y;
        public bool Equals(Vector2 other) => X == other.X && Y == other.Y;
        public override bool Equals(object obj) => obj is Vector2 && Equals((Vector2)obj);
        public override int GetHashCode() => X.GetHashCode() ^ Y.GetHashCode();

        public override string ToString() => $"{{{X} {Y}}}";

        private static Vector2 zero = new Vector2(0.0f, 0.0f);
        private static Vector2 one = new Vector2(1.0f, 1.0f);
        private static Vector2 unitX = new Vector2(1.0f, 0.0f);
        private static Vector2 unitY = new Vector2(0.0f, 1.0f);

        public static Vector2 Zero => zero;
        public static Vector2 One => one;
        public static Vector2 UnitX => unitX;
        public static Vector2 UnitY => unitY;
    }
}
