using System;
using Chernobyl.Mathematics.Vectors;
using Chernobyl.Measures;
using Chernobyl.Measures.Speed;
using Chernobyl.Measures.Time;
namespace Chernobyl.Mathematics.Measures
{
    /// 
    /// The speed at which an object is moving and in what direction.
    /// 
    public struct Velocity : IMeasurement, IEquatable
    {
        /// 
        /// Initializes a new instance of the  struct.
        /// 
        /// The direction in which an object is moving.
        /// This  will be normalized by this type.
        /// The speed component of the velocity in metres
        /// per second.
        public Velocity(Vector3d direction, Metres speed)
            : this()
        {
            direction.Normalize();
            Value = direction * speed.Value;
        }
        /// 
        /// Initializes a new instance of the  struct.
        /// 
        /// The direction and speed of the 
        /// velocity expressed as a  where the normalized
        /// vector is the direction and the vector's length is the speed in 
        /// meters per second.
        public Velocity(Vector3d directionAndSpeed)
            : this()
        {
            Value = directionAndSpeed;
        }
        /// 
        /// Performs an implicit conversion from  to 
        /// .
        /// 
        /// The velocity to convert.
        /// The  as a raw .
        public static implicit operator Vector3d(Velocity velocity)
        {
            return velocity.Value;
        }
        /// 
        /// Performs an implicit conversion from  to 
        /// .
        /// 
        /// The  to convert.
        /// The  as a .
        public static explicit operator Velocity(Vector3d vector)
        {
            return new Velocity(vector);
        }
        /// 
        /// Performs an implicit conversion from  to 
        /// .
        /// 
        /// The velocity to convert.
        /// The  in the form of speed.
        public static explicit operator Metres(Velocity velocity)
        {
            return velocity.Speed;
        }
        /// 
        /// Adds two  instances together.
        /// 
        /// The left side of the operand.
        /// The right side of the operand.
        /// The result of the addition.
        public static Velocity operator +(Velocity left, Velocity right)
        {
            return new Velocity(left.Value + right.Value);
        }
        /// 
        /// Subtracts two  instances from each other.
        /// 
        /// The left side of the operand.
        /// The right side of the operand.
        /// The result of the negation.
        public static Velocity operator -(Velocity left, Velocity right)
        {
            return new Velocity(left.Value - right.Value);
        }
        /// 
        /// Negates a .
        /// 
        /// The  to be negated.
        /// The result of the multiplication.
        public static Velocity operator -(Velocity velocity)
        {
            return new Velocity(-velocity.Value);
        }
        /// 
        /// Multiplies a  by a scalar.
        /// 
        /// The left side of the operand.
        /// The right side of the operand.
        /// The result of the multiplication.
        public static Velocity operator *(Velocity velocity, Metres time)
        {
            return new Velocity(velocity.Value * time.Value);
        }
        /// 
        /// Multiplies a  by a scalar.
        /// 
        /// The left side of the operand.
        /// The right side of the operand.
        /// The result of the multiplication.
        public static Velocity operator *(Metres time, Velocity velocity)
        {
            return new Velocity(time.Value * velocity.Value);
        }
        /// 
        /// Divides a  by a scalar.
        /// 
        /// The left side of the operand.
        /// The right side of the operand.
        /// The result of the division.
        public static Velocity operator /(Velocity velocity, Metres time)
        {
            return new Velocity(velocity.Value * time.Value);
        }
        /// 
        /// Checks if two  instances are equal.
        /// 
        /// The left side of the operand.
        /// The right side of the operand.
        /// True if they are equal, false if otherwise.
        public static bool operator ==(Velocity left, Velocity right)
        {
            return left.Equals(right);
        }
        /// 
        /// Checks if two  instances are not equal.
        /// 
        /// The left side of the operand.
        /// The right side of the operand.
        /// True if they are not equal, false if otherwise.
        public static bool operator !=(Velocity left, Velocity right)
        {
            return !left.Equals(right);
        }
        /// 
        /// Gets the hash code of the .
        /// 
        /// The hash code of the .
        public override int GetHashCode()
        {
            return Value.GetHashCode();
        }
        /// 
        /// Indicates whether the current object is equal to another object of 
        /// the same type.
        /// 
        /// An object to compare with this object.
        /// True if the current object is equal to the 
        ///  parameter; otherwise, false.
        /// 
        public bool Equals(Velocity other)
        {
            return Value.Equals(other.Value);
        }
        /// 
        /// Checks this  for equality with object passed in.
        /// 
        /// The object to compare to.
        /// True if the object is equal to this ,
        /// false if otherwise.
        public override bool Equals(object obj)
        {
            return (obj is Velocity && Equals((Velocity)obj));
        }
        /// 
        /// Returns a  that represents this instance. For
        /// example, a velocity of (2.4, 22.4, 55.9) will be returned as 
        /// "(0.0398215899277352, 0.371668172658861, 0.927511198733498) at 
        /// 60.2688140869141 m/s".
        /// 
        /// A  that represents this instance.
        public override string ToString()
        {
            return Direction + " at " + Speed;
        }
        /// 
        /// The direction in which an object is moving as a normalized (unit)
        /// vector.
        /// 
        public Vector3d Direction
        {
            get
            {
                Vector3d result = Value;
                result.Normalize();
                return result;
            }
        }
        /// 
        /// The speed component of the velocity in metres per second.
        /// 
        public Metres Speed { get { return (Metres)Value.Length; } }
        /// 
        /// The raw value of the velocity as a .
        /// 
        public Vector3d Value { get; private set; }
    }
}