﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Mortar;

namespace Tilar.Math
{
    public class Vector2
    {
        private float x;
        private float y;

        public float X
        {
            get { return x; }
            set { x = value; }
        }
        public float Y
        {
            get { return y; }
            set { y = value; }
        }
        public float Length
        {
            get { return (float)System.Math.Sqrt(x * x + y * y); }
        }

        public Vector2()
        {
            this.x = 0;
            this.y = 0;
        }
        public Vector2(float x, float y)
        {
            this.x = x;
            this.y = y;
        }
        public Vector2(Vector2 v)
        {
            this.x = v.x;
            this.y = v.y;
        }

        public void Normalize()
        {
            float invLength = 1.0f / (float)System.Math.Sqrt(x * x + y * y);
            x *= invLength;
            y *= invLength;
        }
        /*
        public Vector3 ToWorldSpace(Camera camera, float windowWidth, float windowHeight)
        {
            Vector4 data = new Vector4();
            Matrix4 mvp = new Matrix4();
            Matrix4 view = camera.ModelView;
            Matrix4 projection = camera.Projection;

            //Setup the matrices
            mvp = view * projection;

            //Calculate the world space
            data.X = 2.0f * (this.x / windowWidth) - 1.0f;
            data.Y = 2.0f * (this.y / windowHeight) - 1.0f;
            data.Z = 0;
            data.W = 1.0f;

            Matrix4 transposed = new Matrix4(data).Transposed();
            Matrix4 result = mvp.Inverted() * transposed;

            data.X = result.M00;
            data.Y = result.M10;
            data.Z = result.M20;
            data.W = result.M30;

            //Perspective division
            data.W = 1.0f / data.W;
            data.X *= data.W;
            data.Y *= data.W;
            data.Z *= data.W;

            return new Vector3(data.X,data.Y,data.Z);
        }
        */
        public Vector3 ToWorldSpace(Camera camera, Rectangle viewport)
        {
            Matrix4 mvp = camera.Projection * camera.ModelView;

            Vector4 tmp = new Vector4(this.x, viewport.Height - this.y, 0, 1);
            tmp.X = ((tmp.X - viewport.X) / viewport.Width) * 2.0f - 1.0f;
            tmp.Y = ((tmp.Y - viewport.Y) / viewport.Height) * 2.0f - 1.0f;

            Matrix4 transposed = new Matrix4(tmp).Transposed();
            Matrix4 result = mvp.Inverted() * transposed;

            Vector4 obj = new Vector4(result.M00, result.M10, result.M20, result.M30);
            obj.W = 1.0f / obj.W;
            obj.X *= obj.W;
            obj.Y *= obj.W;
            obj.Z *= obj.W;

            return new Vector3(obj.X, obj.Y, obj.Z);
        }
        public static Vector2 operator +(Vector2 a, Vector2 b)
        {
            return new Vector2(a.x + b.x, a.y + b.y);
        }
        public static Vector2 operator +(Vector2 a, float b)
        {
            return new Vector2(a.x + b, a.y + b);
        }
        public static Vector2 operator +(float b, Vector2 a)
        {
            return new Vector2(a.x + b, a.y + b);
        }

        public static Vector2 operator -(Vector2 a, Vector2 b)
        {
            return new Vector2(a.x - b.x, a.y - b.y);
        }
        public static Vector2 operator -(Vector2 a, float b)
        {
            return new Vector2(a.x - b, a.y - b);
        }
        public static Vector2 operator -(float b, Vector2 a)
        {
            return new Vector2(a.x - b, a.y - b);
        }

        public static Vector2 operator *(Vector2 a, Vector2 b)
        {
            return new Vector2(a.x * b.x, a.y * b.y);
        }
        public static Vector2 operator *(Vector2 a, float b)
        {
            return new Vector2(a.x * b, a.y * b);
        }
        public static Vector2 operator *(float b, Vector2 a)
        {
            return new Vector2(a.x * b, a.y * b);
        }

        public static Vector2 operator /(Vector2 a, Vector2 b)
        {
            return new Vector2(a.x / b.x, a.y / b.y);
        }
        public static Vector2 operator /(Vector2 a, float b)
        {
            return new Vector2(a.x / b, a.y / b);
        }
        public static Vector2 operator /(float b, Vector2 a)
        {
            return new Vector2(a.x / b, a.y / b);
        }

        public static bool operator ==(Vector2 a, Vector2 b)
        {
            return a.x == b.x && a.y == b.y;
        }
        public static bool operator !=(Vector2 a, Vector2 b)
        {
            return a.x != b.x && a.y != b.y;
        }

        public override string ToString()
        {
            return x + " " + y;
        }
        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
}
