using System;
namespace TransportGame.Primitives
{
    /// 
    /// A line segment
    /// 
    public struct LineSegment
    {
        #region Properties
        /// 
        /// X coordinate of first point
        /// 
        public float X0 { get; private set; }
        /// 
        /// Y coordinate of first point
        /// 
        public float Y0 { get; private set; }
        /// 
        /// X coordinate of second point
        /// 
        public float X1 { get; private set; }
        /// 
        /// Y coordinate of second point
        /// 
        public float Y1 { get; private set; }
        /// 
        /// Gets the first point
        /// 
        public Vector2 P0
        {
            get
            {
                return new Vector2(X0, Y0);
            }
        }
        
        /// 
        /// Gets the second point
        /// 
        public Vector2 P1
        {
            get
            {
                return new Vector2(X1, Y1);
            }
        }
        /// 
        /// Gets the length of the segment
        /// 
        public float Length
        {
            get
            {
                return (P1 - P0).Length;
            }
        }
        /// 
        /// Gets the length squared of the segment
        /// 
        public float LengthSq
        {
            get
            {
                return (P1 - P0).LengthSq;
            }
        }
        /// 
        /// Gets the direction vector of the segment
        /// 
        public Vector2 Direction
        {
            get
            {
                return (P1 - P0).Normalized;
            }
        }
        #endregion
        #region Constructors
        /// 
        /// Initializes line segment
        /// 
        /// First point
        /// Second point
        public LineSegment(Vector2 p0, Vector2 p1)
            : this()
        {
            X0 = p0.X; Y0 = p0.Y;
            X1 = p1.X; Y1 = p1.Y;
        }
        /// 
        /// Initializes line segment
        /// 
        /// X coordinate of first segment
        /// Y coordinate of first segment
        /// X coordinate of second segment
        /// Y coordinate of second segment
        public LineSegment(float x0, float y0, float x1, float y1)
            : this()
        {
            X0 = x0; Y0 = y0;
            X1 = x1; Y1 = y1;
        }
        #endregion
        #region Operations
        /// 
        /// Calculates the intersection between two line segments.
        /// 
        /// 
        /// Ignores case where intersection is a line.
        /// 
        /// First line segment
        /// Second line segment
        /// Intersection point, or null if segments don't intersect.
        public static Vector2? Intersect(LineSegment a, LineSegment b)
        {
            float s1x = a.X1 - a.X0, s1y = a.Y1 - a.Y0;
            float s2x = b.X1 - b.X0, s2y = b.Y1 - b.Y0;
            float det = (-s2x * s1y + s1x * s2y);
            // Avoid division by zero
            // Note: this is an edge case, the vectors might be parallel or colliniar
            if (det == 0) return null;
            float s = (-s1y * (a.X0 - b.X0) + s1x * (a.Y0 - b.Y0)) / det;
            float t = (s2x * (a.Y0 - b.Y0) - s2y * (a.X0 - b.X0)) / det;
            // Collision detected
            if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
                return new Vector2(a.X0 + t * s1x, a.Y0 + t * s1y);
            // No collision
            return null;
        }
        /// 
        /// Calculates the distance from a point p to a line segment
        /// 
        /// Point
        /// Distance
        public float Distance(Vector2 p)
        {
            float det = (Y1 - Y0) * p.X - (X1 - X0) * p.Y + X1 * Y0 - Y1 * X0;
            return Math.Abs(det) / Length;
        }
        #endregion
        #region ToString
        /// 
        /// Gets string representation of line segment
        /// 
        /// 
        public override string ToString()
        {
            return string.Format("({0}, {1})->({2}, {3})", X0, Y0, X1, Y1);
        }
        #endregion
    }
}