using System;
using System.Collections.Generic;
using System.Text;

namespace HumanLikeBattleRobots.Logic
{
    public struct Vec2f
    {
        public float X;
        public float Y;

        public static Vec2f Zero = new Vec2f(0.0f, 0.0f);

        public Vec2f(float X, float Y)
        {
            this.X = X;
            this.Y = Y;
        }

        public Vec2f(float angle)
        {
            Vec2f angleVector = new Vec2f((float)Math.Cos(angle),
                (float)Math.Sin(angle));
            angleVector.Normalize();
            this.X = angleVector.X;
            this.Y = angleVector.Y;
        }

        public static Vec2f operator +(Vec2f Value1, Vec2f Value2)
        {
            return new Vec2f(Value1.X + Value2.X, Value1.Y + Value2.Y);
        }
        public static Vec2f operator +(Vec2f Value1, float Value2)
        {
            return new Vec2f(Value1.X + Value2, Value1.Y + Value2);
        }
        
        public static Vec2f operator -(Vec2f Value1, Vec2f Value2)
        {
            return new Vec2f(Value1.X - Value2.X, Value1.Y - Value2.Y);
        }
        public static Vec2f operator -(Vec2f Value1, float Value2)
        {
            return new Vec2f(Value1.X - Value2, Value1.Y - Value2);
        }

        public static Vec2f operator *(Vec2f Value1, Vec2f Value2)
        {
            return new Vec2f(Value1.X * Value2.X, Value1.Y * Value2.Y);
        }
        public static Vec2f operator *(Vec2f Value1, float Value2)
        {
            return new Vec2f(Value1.X * Value2, Value1.Y * Value2);
        }
        
        public static Vec2f operator /(Vec2f Value1, Vec2f Value2)
        {
            return new Vec2f(Value1.X / Value2.X, Value1.Y / Value2.Y);
        }
        public static Vec2f operator /(Vec2f Value1, float Value2)
        {
            return new Vec2f(Value1.X / Value2, Value1.Y / Value2);
        }

        public static bool operator ==(Vec2f Value1, Vec2f Value2)
        {
            return (Value1.X == Value2.X && Value1.Y == Value2.Y);
        }

        public static bool operator !=(Vec2f Value1, Vec2f Value2)
        {
            return (Value1.X != Value2.X || Value1.Y != Value2.Y);
        }

        public float Length()
        {
            return (float)Math.Sqrt(this.X * this.X + this.Y * this.Y);
        }        

        public float Distance(Vec2f APoint)
        {
            return (float)Math.Sqrt(Math.Pow(APoint.X - this.X, 2.0f) + Math.Pow(APoint.Y - this.Y, 2.0f));
        }
           
        public Vec2f Normalize()
        {
            if ((Math.Abs(this.X) > 0.0001f) || (Math.Abs(this.Y) > 0.0001))
            {
                float d = 1.0f / this.Length();
                return new Vec2f(d * this.X, d * this.Y);
            }
            else
                return Zero;                
        }

        public float Angle()
        {
            return (float)(Math.Atan2(Y, X));
        }

        public float Angle360()
        {
            return (float)(Angle() * 180.0f / Math.PI);
        }

        public void Fade(double Value)
        {
            if (Math.Abs(this.X) < Math.Abs(Value) || this.X == 0)
                this.X = 0;
            else
                this.X = (float)(Math.Abs(this.X) - Math.Abs(Value)) * Math.Sign(this.X);
            if (Math.Abs(this.Y) < Math.Abs(Value) || this.Y == 0)
                this.Y = 0;
            else
                this.Y = (float)(Math.Abs(this.Y) - Math.Abs(Value)) * Math.Sign(this.Y);
        }

        public Vec2f Rotate(double angle)
        {
            Vec2f newVec2f;
            newVec2f.X = this.X * (float)Math.Cos(angle) - this.Y * (float)Math.Sin(angle);
            newVec2f.Y = this.X * (float)Math.Sin(angle) + this.Y * (float)Math.Cos(angle);
            return newVec2f;
        }

        public Vec2f Rotate360(float angle360)
        {
            Vec2f newVec2f;

            newVec2f.X = this.X * (float)Math.Cos(angle360 * Math.PI / 180) -
                this.Y * (float)Math.Sin(angle360 * Math.PI / 180);
            newVec2f.Y = this.X * (float)Math.Sin(angle360 * Math.PI / 180) +
                this.Y * (float)Math.Cos(angle360 * Math.PI / 180);

            return newVec2f;
        }

        public float AngleBetween(Vec2f other)
        {
            float fi = (this.X * other.X + this.Y * other.Y) / this.Length() / other.Length();
            return (float)Math.Acos(fi);
        }
    }
}
