package projectzombie.display;

import java.text.DecimalFormat;

import org.lwjgl.opengl.GL33;

import gl_engine.MathHelpers;
import gl_engine.matrix.Matrix4;
import gl_engine.vec.Vec2d;
import gl_engine.vec.Vec3d;
import projectzombie.Main;
import projectzombie.init.Models;
import projectzombie.inventory.Inventory;
import projectzombie.model.Model;
import projectzombie.model.ModelGui;
import projectzombie.text.Text;
import projectzombie.util.ItemStack;
import projectzombie.util.gl.GlHelpers;
import projectzombie.world.chunk.ChunkEventHandler;
import projectzombie.world.layer.Layer;

public class DisplayRenderUI
{
	public static boolean showFPS = false;
	public static boolean debug = false;
	public static int guiScale = 2;
	
	public static Matrix4 camera, projection;
	
	private static float calculateGreen(double a) {
		return (float)(-2 * a * (a - 1) + 0.25 * a * a);
	}
	
	public static void renderGameGui()
	{
		{
			Matrix4 matrix = Matrix4.translate(-Models.UI_ITEM_SLOTS.getWidth() / 2, -9.5, 0);
			Inventory inventory = Main.player.getInventory();
			
			int slot = Main.player.inventory_hand;
			double offset = Models.UI_ITEM_SLOTS.getWidth() / 10;
			Matrix4 matrix_slot = Matrix4.multiply(matrix, Matrix4.translate(offset * slot, 0, 0));
			
			Models.UI_ITEM_SLOTS.setModel(matrix);
			Models.UI_ITEM_SLOTS.render();
			
			Models.UI_ACTIVE_SLOT.setModel(matrix_slot);
			Models.UI_ACTIVE_SLOT.render();
			
			for(int i = 0; i < 10; i++)
			{
				ItemStack stack = inventory.getItem(i);
				
				if(stack.isEmpty()) {
					continue;
				}
				
				Model model_item = stack.item.getModel(stack).getGuiModel();
				double item_offset = (Models.UI_ACTIVE_SLOT.getHeight() - model_item.getHeight()) / 2;
				
				Matrix4 matrix_item = Matrix4.multiply(matrix, Matrix4.translate(i * offset + item_offset, item_offset, 0));
				
				model_item.setModel(matrix_item);
				model_item.render();
				
				double damage = stack.item.getDamage(stack);
				
				if(damage > 0)
				{
					Matrix4 matrix_damage = Matrix4.multiply(matrix_item, Matrix4.translate(0, -0.85 / 16, 0));
					matrix_damage = Matrix4.multiply(Matrix4.scale(new Vec3d(damage * 0.85, 0.85 / 16, 0)), matrix_damage);
					
					GL33.glUniform4f(Main.window.glsl_color,
							1 - (float)MathHelpers.squared(1 - damage),
							1 - (float)MathHelpers.squared(damage), 0, 1);
					
					Models.UI_PIXEL_WHITE.setModel(matrix_damage);
					Models.UI_PIXEL_WHITE.render();
					
					GL33.glUniform4f(Main.window.glsl_color, 1, 1, 1, 1);
				}
				
				if(stack.count > 1)
				{
					Matrix4 matrix_text = Matrix4.multiply(matrix, Matrix4.translate(i * offset + 0.25, 0.28125, 0));
					matrix_text = Matrix4.multiply(Matrix4.scale(new Vec3d(0.4, 0.4, 0.4)), matrix_text);
					
					Text.render("" + stack.count, matrix_text);
				}
			}
		}
		
		{
			ModelGui model_health_f = Models.UI_HEALTH_FG;
			ModelGui model_health_b = Models.UI_HEALTH_BG;
			ModelGui model_temperature = Models.UI_TEMPERATURE;
			ModelGui model_water = Models.UI_WATER;
			Matrix4 matrix;
			
			{
				double offset = -(79 * 15.0) / 160;
				matrix = Matrix4.translate(offset, -9.5 + (1.5 * 17) / 16, 0);
				
				model_health_b.setModel(matrix);
				model_health_b.render();
				
				GL33.glUniform1i(Main.window.glsl_do_discard_coords, 1);
				GL33.glUniform4f(Main.window.glsl_discard_coords, -10, -10, (float)MathHelpers.map(
						Main.player.getHealth(),
						0, Main.player.maxHealth(),
						offset, offset + model_health_f.getWidth()), 10);
				
				model_health_f.setModel(matrix);
				model_health_f.render();
			}
			
			double temperature = MathHelpers.smoothStep(Main.player.getTemperature());
			double hydration = MathHelpers.smoothStep(1 - Main.player.getHydration());
			
			{
				Vec2d offset = new Vec2d((1 * 0.75) / 8, -9.5 + (1.5 * 17) / 16);
				
				matrix = Matrix4.translate(offset.x, offset.y, 0);
				
				GL33.glUniform1i(Main.window.glsl_do_discard_coords, 0);
				GL33.glUniform4f(Main.window.glsl_color, 0.65f, 0.65f, 0.65f, 1);
				
				model_water.setModel(matrix);
				model_water.render();
				
				GL33.glUniform1i(Main.window.glsl_do_discard_coords, 1);
				
				GL33.glUniform4f(Main.window.glsl_discard_coords,
						(float)offset.x, (float)offset.y,
						(float)(offset.x + model_water.getWidth()),
						(float)(offset.y + model_water.getHeight() * Main.player.getHydration()));
				
				GL33.glUniform4f(Main.window.glsl_color,
						(float)hydration * 0.75f, calculateGreen(hydration), 1 - (float)hydration, 1);
				
				model_water.render();
				
				GL33.glUniform1i(Main.window.glsl_do_discard_coords, 0);
			}
			
			{
				GL33.glUniform4f(Main.window.glsl_color,
						(float)temperature, calculateGreen(temperature), 1 - (float)temperature, 1);
				
				matrix = Matrix4.translate(-(9 * 0.75) / 8, -9.5 + (1.5 * 17) / 16, 0);
				
				model_temperature.setModel(matrix);
				model_temperature.render();
			}
			
			GL33.glUniform4f(Main.window.glsl_color, 1, 1, 1, 1);
		}
	}
	
	public static void render()
	{
		DecimalFormat dec = new DecimalFormat("0.####");
		
		camera = Matrix4.identity();
		projection = Matrix4.scale(new Vec3d(0.1/GlHelpers.getAspectRatio(), 0.1, 1));
		
		GL33.glUniform3f(Main.window.glsl_day_low, 1, 1, 1);
		GL33.glUniform3f(Main.window.glsl_day_high, 1, 1, 1);
		
		GL33.glUniformMatrix4fv(Main.window.glsl_projection, true, projection.getArray());
		
		GL33.glDisable(GL33.GL_DEPTH_TEST);
		
		if(Main.menu.doGameRender && Main.menu.showIngameGUI && ChunkEventHandler.loaded) {
			renderGameGui();
		}
		
		double aspect = (double)Main.window.getWidth() / (double)Main.window.getHeight();
		Matrix4 matrix = Matrix4.scale(new Vec3d(0.35, 0.35, 0.35));
		matrix = Matrix4.multiply(matrix, Matrix4.translate(-10 * aspect, 9.5, 0));
		
		if(showFPS) {
			
			float fps = DisplayStatsEventHandler.fps;
			
			if(fps >= 120) {
				GL33.glUniform4f(Main.window.glsl_color, 0, 1, 0, 1);
			} else if(fps >= 60) {
				GL33.glUniform4f(Main.window.glsl_color, 1, 1, 0, 1);
			} else {
				GL33.glUniform4f(Main.window.glsl_color, 1, 0, 0, 1);
			}
			
			Text.render("Fps: " + DisplayStatsEventHandler.fps, matrix);
			matrix = Matrix4.multiply(matrix, Matrix4.translate(0, -0.7, 0));
		}
		
		if(debug) {
			Layer layer = Main.world.getLayer();
			Vec3d pos = Main.player.getPos();
			
			GL33.glUniform4f(Main.window.glsl_color, 1, 1, 0, 1);
			
			if(ChunkEventHandler.loaded)
			{
				Text.render("temperature: " + dec.format(
						layer.getTemperature(Main.player.getPos().xz().toInt())), matrix);
				matrix = Matrix4.multiply(matrix, Matrix4.translate(0, -0.35, 0));
				Text.render("humidity: " + dec.format(
						layer.getHumidity(Main.player.getPos().xz().toInt())), matrix);
				matrix = Matrix4.multiply(matrix, Matrix4.translate(0, -0.7, 0));
				
				Text.render("x: "+dec.format(pos.x), matrix);
				matrix = Matrix4.multiply(matrix, Matrix4.translate(0, -0.35, 0));
				Text.render("y: "+dec.format(pos.y), matrix);
				matrix = Matrix4.multiply(matrix, Matrix4.translate(0, -0.35, 0));
				Text.render("z: "+dec.format(pos.z), matrix);
				matrix = Matrix4.multiply(matrix, Matrix4.translate(0, -0.7, 0));
			}
		}
		
		GL33.glUniform4f(Main.window.glsl_color, 1, 1, 1, 1);
		
		// Render the loaded menu
		Main.menu.render();
	}
}
