// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System;
using ClassicalSharp.GraphicsAPI;
using OpenTK;

namespace ClassicalSharp.Renderers {
	
	public sealed class PickedPosRenderer : IGameComponent {
		Game game;
		int vb;
		
		void IGameComponent.Init(Game game) {
			this.game = game;
			col = new PackedCol(0, 0, 0, 102);
			
			ContextRecreated();
			game.Graphics.ContextLost += ContextLost;
			game.Graphics.ContextRecreated += ContextRecreated;
		}
		
		void IDisposable.Dispose() { 
			ContextLost();
			game.Graphics.ContextLost -= ContextLost;
			game.Graphics.ContextRecreated -= ContextRecreated;
		}

		void IGameComponent.Ready(Game game) { }
		void IGameComponent.Reset(Game game) { }
		void IGameComponent.OnNewMap(Game game) { }
		void IGameComponent.OnNewMapLoaded(Game game) { }		
		
		PackedCol col;
		int index;
		const int verticesCount = 16 * 6;
		VertexP3fC4b[] vertices = new VertexP3fC4b[verticesCount];
		
		public void Update(PickedPos selected) {
			index = 0;
			Vector3 camPos = game.CurrentCameraPos;
			float dist = (camPos - selected.Min).LengthSquared;

			float offset = 0.01f;
			if (dist < 4 * 4) offset = 0.00625f;
			if (dist < 2 * 2) offset = 0.00500f;
			
			Vector3 p1 = selected.Min - new Vector3(offset, offset, offset);
			Vector3 p2 = selected.Max + new Vector3(offset, offset, offset);
			
			float size = 1/16f;
			if (dist < 32 * 32) size = 1/32f;
			if (dist < 16 * 16) size = 1/64f;
			if (dist < 8 * 8) size = 1/96f;
			if (dist < 4 * 4) size = 1/128f;
			if (dist < 2 * 2) size = 1/192f;

			DrawLines(p1, p2, size);
		}
		
		public void Render(double delta) {
			if (game.Graphics.LostContext) return;
			IGraphicsApi gfx = game.Graphics;
			
			gfx.AlphaBlending = true;
			gfx.DepthWrite = false;
			gfx.SetBatchFormat(VertexFormat.P3fC4b);
			gfx.UpdateDynamicVb_IndexedTris(vb, vertices, index);
			gfx.DepthWrite = true;
			gfx.AlphaBlending = false;
		}
		
		void DrawLines(Vector3 p1, Vector3 p2, float size) {
			// bottom face
			YQuad(p1.Y, p1.X, p1.Z + size, p1.X + size, p2.Z - size);
			YQuad(p1.Y, p2.X, p1.Z + size, p2.X - size, p2.Z - size);
			YQuad(p1.Y, p1.X, p1.Z, p2.X, p1.Z + size);
			YQuad(p1.Y, p1.X, p2.Z, p2.X, p2.Z - size);
			// top face
			YQuad(p2.Y, p1.X, p1.Z + size, p1.X + size, p2.Z - size);
			YQuad(p2.Y, p2.X, p1.Z + size, p2.X - size, p2.Z - size);
			YQuad(p2.Y, p1.X, p1.Z, p2.X, p1.Z + size);
			YQuad(p2.Y, p1.X, p2.Z, p2.X, p2.Z - size);
			// left face
			XQuad(p1.X, p1.Z, p1.Y + size, p1.Z + size, p2.Y - size);
			XQuad(p1.X, p2.Z, p1.Y + size, p2.Z - size, p2.Y - size);
			XQuad(p1.X, p1.Z, p1.Y, p2.Z, p1.Y + size);
			XQuad(p1.X, p1.Z, p2.Y, p2.Z, p2.Y - size);
			// right face
			XQuad(p2.X, p1.Z, p1.Y + size, p1.Z + size, p2.Y - size);
			XQuad(p2.X, p2.Z, p1.Y + size, p2.Z - size, p2.Y - size);
			XQuad(p2.X, p1.Z, p1.Y, p2.Z, p1.Y + size);
			XQuad(p2.X, p1.Z, p2.Y, p2.Z, p2.Y - size);
			// front face
			ZQuad(p1.Z, p1.X, p1.Y + size, p1.X + size, p2.Y - size);
			ZQuad(p1.Z, p2.X, p1.Y + size, p2.X - size, p2.Y - size);
			ZQuad(p1.Z, p1.X, p1.Y, p2.X, p1.Y + size);
			ZQuad(p1.Z, p1.X, p2.Y, p2.X, p2.Y - size);
			// back face
			ZQuad(p2.Z, p1.X, p1.Y + size, p1.X + size, p2.Y - size);
			ZQuad(p2.Z, p2.X, p1.Y + size, p2.X - size, p2.Y - size);
			ZQuad(p2.Z, p1.X, p1.Y, p2.X, p1.Y + size);
			ZQuad(p2.Z, p1.X, p2.Y, p2.X, p2.Y - size);
		}
		
		void XQuad(float x, float z1, float y1, float z2, float y2) {
			vertices[index++] = new VertexP3fC4b(x, y1, z1, col);
			vertices[index++] = new VertexP3fC4b(x, y2, z1, col);
			vertices[index++] = new VertexP3fC4b(x, y2, z2, col);
			vertices[index++] = new VertexP3fC4b(x, y1, z2, col);
		}
		
		void ZQuad(float z, float x1, float y1, float x2, float y2) {
			vertices[index++] = new VertexP3fC4b(x1, y1, z, col);
			vertices[index++] = new VertexP3fC4b(x1, y2, z, col);
			vertices[index++] = new VertexP3fC4b(x2, y2, z, col);
			vertices[index++] = new VertexP3fC4b(x2, y1, z, col);
		}
		
		void YQuad(float y, float x1, float z1, float x2, float z2) {
			vertices[index++] = new VertexP3fC4b(x1, y, z1, col);
			vertices[index++] = new VertexP3fC4b(x1, y, z2, col);
			vertices[index++] = new VertexP3fC4b(x2, y, z2, col);
			vertices[index++] = new VertexP3fC4b(x2, y, z1, col);
		}
		
		void ContextLost() { game.Graphics.DeleteVb(ref vb); }
		
		void ContextRecreated() {
			vb = game.Graphics.CreateDynamicVb(VertexFormat.P3fC4b, verticesCount);
		}
	}
}
