using Sandbox.ModAPI;
using System;
using UIFun.Definition;
using VRage.Game;
using VRage.Utils;
using VRageMath;
using VRageRender;
using BlendTypeEnum = VRageRender.MyBillboard.BlendTypeEnum;

namespace UIFun
{
	static class VersionHelper
	{
		const int POOLSIZE = 4;
		static int billboardPoolIndex = 0;

		const int TRIBILLBOARD_SIZE_STEP = 256;
		static MyTriangleBillboard[][] triBillboardPoolBuffer = new MyTriangleBillboard[POOLSIZE][];
		static MyTriangleBillboard[] triBillboardPool;
		static int triBillboardIndex = 0;

		const int BILLBOARD_SIZE_STEP = 1024;
		static MyBillboard[][] billboardPool = new MyBillboard[POOLSIZE][];
		static MyBillboard[] currentBillboardPool;
		static int billboardIndex = 0;

		internal static void StartRender()
		{
			//not sure if i can put in a different step. below will cause a hitch. 
			if(billboardPool[0] == null)
			{
				for(int i = 0; i < POOLSIZE; i++)
				{
					billboardPool[i] = new MyBillboard[BILLBOARD_SIZE_STEP];
				}
			}
			currentBillboardPool = billboardPool[billboardPoolIndex];
			
			if (triBillboardPoolBuffer[0] == null)
			{
				for (int i = 0; i < POOLSIZE; i++)
				{
					triBillboardPoolBuffer[i] = new MyTriangleBillboard[TRIBILLBOARD_SIZE_STEP];
				}
			}
			triBillboardPool = triBillboardPoolBuffer[billboardPoolIndex];
			billboardPoolIndex = (billboardPoolIndex + 1) % POOLSIZE;

			// if were near the limit we will expand the pool
			if (billboardIndex >= currentBillboardPool.Length)
			{
				Array.Resize(ref currentBillboardPool, currentBillboardPool.Length * 2);
			}

			if (triBillboardIndex >= triBillboardPool.Length)
			{
				Array.Resize(ref triBillboardPool, triBillboardPool.Length * 2);
			}

			billboardIndex = 0;
			triBillboardIndex = 0;
		}

		internal static void EndRender()
		{

		}

		internal static void Close()
		{
			billboardPool = null;
			triBillboardPool = null;
		}

		static MyBillboard GetOrAllocate()
		{
			int curbillboard = billboardIndex;

			billboardIndex++;

			if (curbillboard >= currentBillboardPool.Length)
				return new MyBillboard();
			if (currentBillboardPool[curbillboard] == null)
			{
				currentBillboardPool[curbillboard] = new MyBillboard();
			}
			return currentBillboardPool[curbillboard];
		}

		static MyTriangleBillboard GetOrAllocateTri()
		{
			int curbillboard = triBillboardIndex;

			triBillboardIndex++;

			if (curbillboard >= triBillboardPool.Length)
				return new MyTriangleBillboard();
			if (triBillboardPool[curbillboard] == null)
			{
				triBillboardPool[curbillboard] = new MyTriangleBillboard();

			}
			return triBillboardPool[curbillboard];
		}

		internal static void AddBillboardOriented(MyStringId v1, Vector4 fontcolor, Vector3D textpos, Vector3D up, Vector3D left, float width, float height, Vector2 uvOff, Vector2 uvSize, float texturesize, BlendTypeEnum blend = BlendTypeEnum.Standard)
		{
			MyQuadD quad;
			Vector3 lv3, uv3;

			lv3 = (Vector3)left;
			uv3 = (Vector3)up;

			MyUtils.GetBillboardQuadOriented(out quad, ref textpos, width / 2f, height / 2f, ref lv3, ref uv3);

			MyBillboard billboard = GetOrAllocate();
			billboard.UVOffset = uvOff / texturesize;
			billboard.UVSize = uvSize / texturesize;
			billboard.LocalType = MyBillboard.LocalTypeEnum.Custom;
			billboard.Reflectivity = 0f;
			billboard.SoftParticleDistanceScale = 0f;
			billboard.DistanceSquared = (float)Vector3D.DistanceSquared(textpos, MyAPIGateway.Session.Camera.Position);
			billboard.Material = v1;
			billboard.Position0 = quad.Point0;
			billboard.Position1 = quad.Point1;
			billboard.Position2 = quad.Point2;
			billboard.Position3 = quad.Point3;
			billboard.ColorIntensity = 1f;
			billboard.Color = fontcolor;
			billboard.BlendType = blend;
			billboard.ParentID = uint.MaxValue;
			billboard.CustomViewProjection = -1;

			MyTransparentGeometry.AddBillboard(billboard, false);
		}

		internal static void AddBillboardOrientedTri(MyStringId v1, Vector4 fontcolor, Vector3D textpos, Vector2 p0, Vector2 p1, Vector2 p2, Vector3D up, Vector3D left, float width, float height, BlendTypeEnum blend = BlendTypeEnum.Standard)
		{
			MyTriangleD tri;
			Vector3 lv3, uv3;
			Vector3 normal = FontTexture.projectionNormal;
			lv3 = (Vector3)left;
			uv3 = (Vector3)up;

			GetBillboardTriOriented(out tri, ref textpos, p0, p1, p2, width, height, ref lv3, ref uv3);

			var billboard = GetOrAllocateTri();
			billboard.UV0 = p0;
			billboard.UV1 = p1;
			billboard.UV2 = p2;
			billboard.Normal0 = normal;
			billboard.LocalType = MyBillboard.LocalTypeEnum.Custom;
			billboard.Reflectivity = 0f;
			billboard.SoftParticleDistanceScale = 0f;
			billboard.DistanceSquared = (float)Vector3D.DistanceSquared(textpos, MyAPIGateway.Session.Camera.Position);
			billboard.Material = v1;
			billboard.Position0 = tri.Point0;
			billboard.Position1 = tri.Point1;
			billboard.Position2 = tri.Point2;
			//billboard.Position3 = quad.Point3;
			billboard.ColorIntensity = 1f;
			billboard.Color = fontcolor;
			billboard.BlendType = blend;
			billboard.ParentID = uint.MaxValue;
			billboard.CustomViewProjection = -1;

			MyTransparentGeometry.AddBillboard(billboard, false);
		}

		internal static void AddBillboardOriented(MyStringId v1, Vector4 fontcolor, Vector3D textpos, Vector3 up, Vector3 left, float width, float height, BlendTypeEnum blend = BlendTypeEnum.Standard)
		{
			MyQuadD quad;
			Vector3 lv3, uv3;

			lv3 = (Vector3)left;
			uv3 = (Vector3)up;

			MyUtils.GetBillboardQuadOriented(out quad, ref textpos, width / 2f, height / 2f, ref lv3, ref uv3);
			
			MyBillboard billboard = GetOrAllocate();

			billboard.UVOffset = Vector2.Zero;
			billboard.UVSize = Vector2.One;
			billboard.LocalType = MyBillboard.LocalTypeEnum.Custom;
			billboard.Reflectivity = 0f;
			billboard.SoftParticleDistanceScale = 0f;
			billboard.DistanceSquared = (float)Vector3D.DistanceSquared(textpos, MyAPIGateway.Session.Camera.Position);
			billboard.Material = v1;
			billboard.Position0 = quad.Point0;
			billboard.Position1 = quad.Point1;
			billboard.Position2 = quad.Point2;
			billboard.Position3 = quad.Point3;
			billboard.ColorIntensity = 1f;
			billboard.Color = fontcolor;
			billboard.BlendType = blend;
			billboard.ParentID = uint.MaxValue;
			billboard.CustomViewProjection = -1;

			MyTransparentGeometry.AddBillboard(billboard, false);
		}

		internal static void AddBillboardOriented(FontDefinition.FontCharacterDefinition FontData, Vector4 fontcolor, Vector3D textpos, Vector3D up, Vector3D left, float scale, BlendTypeEnum blend = BlendTypeEnum.Standard)
		{
			AddBillboardOriented(FontData, fontcolor, textpos, up, left, scale * ((float)FontData.sizex / (float)FontData.sizey), scale, blend);
        }

		internal static void AddBillboardOriented(FontDefinition.FontCharacterDefinition FontData, Vector4 fontcolor, Vector3D textpos, Vector3D up, Vector3D left, float width, float height, BlendTypeEnum blend = BlendTypeEnum.Standard)
		{
			MyQuadD quad;
			Vector3 lv3, uv3;

			lv3 = (Vector3)left;
			uv3 = (Vector3)up;

			MyUtils.GetBillboardQuadOriented(out quad, ref textpos, width /2f, height /2f, ref lv3, ref uv3);

			MyBillboard billboard = GetOrAllocate();
			billboard.UVOffset = FontData.v0;
			billboard.UVSize = FontData.v3 - FontData.v0;
			billboard.LocalType = MyBillboard.LocalTypeEnum.Custom;
			billboard.Reflectivity = 0f;
			billboard.SoftParticleDistanceScale = 0f;
			billboard.DistanceSquared = (float)Vector3D.DistanceSquared(textpos, MyAPIGateway.Session.Camera.Position);
			billboard.Material = FontData.MaterialId;
			billboard.Position0 = quad.Point0;
			billboard.Position1 = quad.Point1;
			billboard.Position2 = quad.Point2;
			billboard.Position3 = quad.Point3;
			billboard.ColorIntensity = 1f;
			billboard.Color = fontcolor;
			billboard.BlendType = blend;
			billboard.ParentID = uint.MaxValue;
			billboard.CustomViewProjection = -1;

			MyTransparentGeometry.AddBillboard(billboard, false);
		}

		internal static void AddBillboardOrientedSlant(FontDefinition.FontCharacterDefinition FontData, Vector4 fontcolor, Vector3D textpos, Vector3D up, Vector3D left, float width, float height, BlendTypeEnum blend = BlendTypeEnum.Standard)
		{
			MyQuadD quad;
			Vector3 lv3, uv3;
			Vector3 normal = FontTexture.projectionNormal;
			lv3 = (Vector3)left;
			uv3 = (Vector3)up;
			var slant = left * 0.15 * width;

			MyUtils.GetBillboardQuadOriented(out quad, ref textpos, width / 2f, height / 2f, ref lv3, ref uv3);
			quad.Point0 -= slant;
			quad.Point1 -= slant;

			MyBillboard billboard = GetOrAllocate();
			//MyBillboard billboard = new MyBillboard();
			billboard.UVOffset = FontData.v0;
			billboard.UVSize = FontData.v3 - FontData.v0;
			billboard.LocalType = MyBillboard.LocalTypeEnum.Custom;
			billboard.Reflectivity = 0f;
			billboard.SoftParticleDistanceScale = 0f;
			billboard.DistanceSquared = (float)Vector3D.DistanceSquared(textpos, MyAPIGateway.Session.Camera.Position);
			billboard.Material = FontData.MaterialId;
			billboard.Position0 = quad.Point0;
			billboard.Position1 = quad.Point1;
			billboard.Position2 = quad.Point2;
			billboard.Position3 = quad.Point3;
			billboard.ColorIntensity = 1f;
			billboard.Color = fontcolor;
			billboard.BlendType = blend;
			billboard.ParentID = uint.MaxValue;
			billboard.CustomViewProjection = -1;


			MyTransparentGeometry.AddBillboard(billboard, false);

		}

		public static void GetBillboardTriOriented(out MyTriangleD tri, ref Vector3D position, Vector2 uvP0, Vector2 uvP1, Vector2 uvP2, float width, float height, ref Vector3 leftVector, ref Vector3 upVector)
		{
			Vector3D billboardAxisX = leftVector * width;
			Vector3D billboardAxisY = upVector * height;

			//	Coordinates of four points of a billboard's quad
			tri.Point0 = position - uvP0.X * billboardAxisX - uvP0.Y * billboardAxisY;
			tri.Point1 = position - uvP1.X * billboardAxisX - uvP1.Y * billboardAxisY;
			tri.Point2 = position - uvP2.X * billboardAxisX - uvP2.Y * billboardAxisY;
			//quad.Point3 = position - billboardAxisY + billboardAxisX;
		}

		public struct MyTriangleD
		{
			public Vector3D Point0, Point1, Point2;
		}
	}
}
