using System;
using System.Globalization;
using System.Text;

namespace skyscraper5.Skyscraper.Drawing
{
	public class Polygon
	{
		public Polygon(string polygonString)
		{
			string[] separated = polygonString.Split('\t');
			polygonPoints = new PointF[separated.Length];
			for (int i = 0; i < separated.Length; i++)
			{
				if (String.IsNullOrEmpty(separated[i]))
					continue;
				string[] components = separated[i].Split(',');
				polygonPoints[i] = new PointF(Double.Parse(components[0],CultureInfo.InvariantCulture), Double.Parse(components[1],CultureInfo.InvariantCulture));
			}
		}

		private PointF[] polygonPoints;

		public PointF[] GetCopyOfPoints()
		{
			PointF[] copy = new PointF[polygonPoints.Length];
			Array.Copy(polygonPoints,0,copy,0,polygonPoints.Length);
			return copy;
		}

		public string GetPolygonString()
		{
			StringBuilder sb = new StringBuilder();
			foreach (PointF point in polygonPoints)
			{
				sb.Append(point.X.ToString(CultureInfo.InvariantCulture));
				sb.Append(",");
				sb.Append(point.Y.ToString(CultureInfo.InvariantCulture));
				sb.Append('\t');
			}

			return sb.ToString().Trim('\t');
		}

		public override string ToString()
		{
			return String.Format("{0} points.", polygonPoints);
		}

		public bool Wraps(PointF positionOnEath)
		{
			int crossings = 0;
			PointF[] path = polygonPoints;

			//for each edge
			for (int i = 0; i < path.Length; i++)
			{
				PointF a = path[i];
				int j = i + 1;
				if (j >= path.Length)
					j = 0;

				PointF b = path[j];
				if (RayCrossesSegment(positionOnEath, a, b))
					crossings++;
			}

			return (crossings % 2 == 1);
		}

		private static bool RayCrossesSegment(PointF point, PointF a, PointF b)
		{
			double px = point.X;
			double py = point.Y;
			double ax = a.X;
			double ay = a.Y;
			double bx = b.X;
			double by = b.Y;
			if (ay > by)
			{
				ax = b.X;
				ay = b.Y;
				bx = a.X;
				by = a.Y;
			}
			// alter longitude to cater for 180 degree crossings
			if (px < 0)
				px += 360;
			if (ax < 0)
				ax += 360;
			if (bx < 0)
				bx += 360;

			if (py.Equals(ay) || py.Equals(by)) 
				py += 0.00000001;
			if ((py > by || py < ay) || (px > Math.Max(ax, bx))) 
				return false;
			if (px < Math.Min(ax, bx)) 
				return true;

			double red = (!ax.Equals(bx)) ? ((by - ay) / (bx - ax)) : Double.PositiveInfinity;
			double blue = (!ax.Equals(px)) ? ((py - ay) / (px - ax)) : Double.PositiveInfinity;
			return (blue >= red);
		}
	}
}
