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

namespace Vortex.Drawing {

	//this part contains miscelaneous things for drawing helping
	public sealed partial class Canvas2D {
		///<summary>Cached prepared ellipse offsets</summary>
		private Vector2[] _preparedEllipseOffsets;

		/// <summary>
		/// Prepares the ellipse offsets fit to bounding rect. This method reuse the same array to avoid collection overhead
		/// </summary>
		/// <param name="rect">The rect.</param>
		private Vector2[] PrepareEllipseOffsets(Rect boundingRect) {
			Vector2[] sourceOffsets = EllipseDrawInfo.EllipseSegments;
			
			if (_preparedEllipseOffsets == null || _preparedEllipseOffsets.Length != sourceOffsets.Length) {
				_preparedEllipseOffsets = new Vector2[sourceOffsets.Length];
			}

			Vector2 offset = boundingRect.LeftTop;
			Vector2 size = boundingRect.Size;

			for (int n = 0; n < sourceOffsets.Length; ++n) {
				_preparedEllipseOffsets[n] = sourceOffsets[n] * size + offset;
			}

			return _preparedEllipseOffsets;
		}

		/// <summary>
		/// Class which contains information for rendering ellipses
		/// </summary>
		static class EllipseDrawInfo {
			public const int ELLIPSE_SEGMENTS = 64;
			private static Vector2[] _ellipseSegments;
			private static VertexFragment _ellipseFragment = new VertexFragment(ELLIPSE_SEGMENTS, ELLIPSE_SEGMENTS * 2, PrimitiveType.LineList);
			private static VertexFragment _filledEllipseFragment = new VertexFragment(ELLIPSE_SEGMENTS + 1, ELLIPSE_SEGMENTS * 3, PrimitiveType.TriangleList);

			static EllipseDrawInfo() {
				_ellipseSegments = new Vector2[ELLIPSE_SEGMENTS];
				float angle = 0.0f, angleStep = (float)(MathHelper.Pi * 2 / (double)ELLIPSE_SEGMENTS);
				for (int n = 0; n < ELLIPSE_SEGMENTS; ++n) {
					_ellipseSegments[n] = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle)) * Vector2.Unit.Half + Vector2.Unit.Half;
					angle += angleStep;
				}
			}

			/// <summary>
			/// Gets segments for building ellipses.
			/// </summary>
			/// <value>The ellipse segments.</value>
			public static Vector2[] EllipseSegments {
				get { return _ellipseSegments; }
			}

			/// <summary>
			/// Gets the ellipse fragment to used for request vertices.
			/// </summary>
			/// <value>The ellipse fragment.</value>
			public static VertexFragment EllipseFragment {
				get { return _ellipseFragment; }
			}

			/// <summary>
			/// Gets the filled ellipse fragment to used for request vertices.
			/// </summary>
			/// <value>The filled ellipse fragment.</value>
			public static VertexFragment FilledEllipseFragment {
				get { return _filledEllipseFragment; }
			}
		}

		#region Helper Methods

		/// <summary>
		/// Populates the quad indices into index location fragment.
		/// </summary>
		/// <param name="location">The fragment location.</param>
		private static unsafe void PopulateQuadIndices(ref FragmentLocation location) {
			location.Indices[0] = location.BaseIndex;
			location.Indices[1] = (ushort)(location.BaseIndex + 1);
			location.Indices[2] = (ushort)(location.BaseIndex + 2);
			location.Indices[3] = location.BaseIndex;
			location.Indices[4] = (ushort)(location.BaseIndex + 2);
			location.Indices[5] = (ushort)(location.BaseIndex + 3);
		}

		/// <summary>
		/// Transforms 2 vertices at one call
		/// </summary>
		/// <param name="t">The _transform.</param>
		/// <param name="v">The vertices.</param>
		private static unsafe void Transform2Vertices(ref Transform2D t, Vertex2D* v) {
			v[0].XY = new Vector2(
				t.M11 * v[0].XY.X + t.M12 * v[0].XY.Y + t.TX,
				t.M21 * v[0].XY.X + t.M22 * v[0].XY.Y + t.TY
			);

			v[1].XY = new Vector2(
				t.M11 * v[1].XY.X + t.M12 * v[1].XY.Y + t.TX,
				t.M21 * v[1].XY.X + t.M22 * v[1].XY.Y + t.TY
			);
			/*
			Transform2D.Multiply(ref transform, ref vertices[0].XY, out vertices[0].XY);
			Transform2D.Multiply(ref transform, ref vertices[1].XY, out vertices[1].XY);
			*/
		}

		/// <summary>
		/// Transforms 4 vertices at one call
		/// </summary>
		/// <param name="t">The _transform.</param>
		/// <param name="v">The vertices.</param>
		private static unsafe void Transform4Vertices(ref Transform2D t, Vertex2D* v) {
			//+3% of performance
			v[0].XY = new Vector2(
				t.M11 * v[0].XY.X + t.M12 * v[0].XY.Y + t.TX,
				t.M21 * v[0].XY.X + t.M22 * v[0].XY.Y + t.TY
			);

			v[1].XY = new Vector2(
				t.M11 * v[1].XY.X + t.M12 * v[1].XY.Y + t.TX,
				t.M21 * v[1].XY.X + t.M22 * v[1].XY.Y + t.TY
			);

			v[2].XY = new Vector2(
				t.M11 * v[2].XY.X + t.M12 * v[2].XY.Y + t.TX,
				t.M21 * v[2].XY.X + t.M22 * v[2].XY.Y + t.TY
			);

			v[3].XY = new Vector2(
				t.M11 * v[3].XY.X + t.M12 * v[3].XY.Y + t.TX,
				t.M21 * v[3].XY.X + t.M22 * v[3].XY.Y + t.TY
			);		
			/*
			Transform2D.Multiply(ref t, ref v[0].XY, out v[0].XY);
			Transform2D.Multiply(ref t, ref v[1].XY, out v[1].XY);
			Transform2D.Multiply(ref t, ref v[2].XY, out v[2].XY);
			Transform2D.Multiply(ref t, ref v[3].XY, out v[3].XY);			
			 */
		}

		/// <summary>
		/// Transforms any number of vertices at one call
		/// </summary>
		/// <param name="t">The _transform.</param>
		/// <param name="count">The count of vertices to transform.</param>
		/// <param name="v">The vertices.</param>
		private static unsafe void TransformVertices(ref Transform2D t, int count, Vertex2D* v) {
			for (int n = 0; n < count; ++n) {
				//Transform2D.Multiply(ref transform, ref vertices[n].XY, out vertices[n].XY);
				v[0].XY = new Vector2(
					t.M11 * v->XY.X + t.M12 * v->XY.Y + t.TX,
					t.M21 * v->XY.X + t.M22 * v->XY.Y + t.TY
				);
				v++;
			}
		}

		/// <summary>
		/// Transforms any number of vertices at one call
		/// </summary>
		/// <param name="t">The _transform.</param>
		/// <param name="count">The count of vertices to transform.</param>
		/// <param name="v">The vertices.</param>
		/// <param name="offset">Additional offset to apply after transformation.</param>
		private static unsafe void TransformVertices(ref Transform2D t, int count, Vertex2D* v, Vector2 offset) {
			for (int n = 0; n < count; ++n) {
				//Transform2D.Multiply(ref transform, ref vertices[n].XY, out vertices[n].XY);
				v[0].XY = new Vector2(
					t.M11 * v->XY.X + t.M12 * v->XY.Y + t.TX + offset.X,
					t.M21 * v->XY.X + t.M22 * v->XY.Y + t.TY + offset.Y
				);
				v++;
			}
		}

		#endregion
	}
}
