package client.gui;

import java.awt.image.BufferedImage;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.lwjgl.opengl.GL11;

import client.renderer.GlState;
import client.renderer.texture.TextureUtil;
import client.util.FileUtils;
import common.log.Log;
import common.util.Displayable;
import common.util.Identifyable;

public enum Font implements Identifyable, Displayable {
	TINY("tiny", "Winzig", 6, 7),
	SMALL("small", "Klein", 8, 10),
	MEDIUM("medium", "Mittel", 10, 12),
	LARGE("large", "Groß", 12, 14);
	
	public static FontChar[] SIZES;
	public static int WIDTH;
	public static int HEIGHT;
	private static int TEXTURE;
	private static Font SELECTED;

	private final FontChar[] sizes = new FontChar[256];
	private final String name;
	private final String display;
	private final int width;
	private final int height;
	
	private int texture;
	
	public static void bindTexture() {
		GlState.bindTexture(TEXTURE);
	}

	private static int stride(int width, int height, int x, int y, int c) {
		return ((c & 15) * width + x) + (((c >> 4) & 15) * height + y) * (width << 4); // << 2;
	}
	
	private static byte specialChar(int width, int ch) {
		return (byte)((ch == Log.CHR_UNK) ? width : ((ch == Log.CHR_SPC) ? (width / 6) : 127));
	}
	
	private static void calculate(int[] data, FontChar[] glyphs, int width, int height, int page) {
		int off;
		for(int z = 0; z < 256; z++) {
			byte s, t, u, v;
			if((u = specialChar(width, (page << 8) + z)) != 127) {
				s = t = 0;
				v = (byte)(((int)u) * height / width);
				if(((page << 8) + z) != Log.CHR_UNK) {
					for(int x = 0; x < width; x++) {
						for(int y = 0; y < height; y++) {
							off = stride(width, height, x, y, z);
							data[off/*+3*/] = 0;
						}
					}
				}
				glyphs[z] = new FontChar(s, t, u, v);
				continue;
			}
			s = t = 127;
			u = v = 0;
			for(int x = 0; x < width; x++) {
				for(int y = 0; y < height; y++) {
					off = stride(width, height, x, y, z);
					if((data[off/*+3*/] & 0xff000000) != 0) {
						s = x < s ? (byte)x : s;
						t = y < t ? (byte)y : t;
						u = x > u ? (byte)x : u;
						v = y > v ? (byte)y : v;
					}
				}
			}
			if(s == 127 && t == 127 && u == 0 && v == 0) {
				s = t = 0;
			}
			else {
				u += 1;
				v += 1;
			}
			glyphs[z] = new FontChar(s, t, u, v);
		}
	}

	public static void loadFonts() {
		for(Font font : values()) {
			int width = font.width;
			int height = font.height;
	        BufferedImage img = null;
			try {
				img = TextureUtil.readImage(FileUtils.getResource("textures/font_" + font.name + ".png"));
			}
			catch(FileNotFoundException e) {
				Log.IO.error("Konnte Font-Textur nicht laden: Datei nicht vorhanden");
			}
			catch(IOException e) {
				Log.IO.error(e, "Konnte Font-Textur nicht laden");
			}
			if(img != null && (img.getWidth() != width * 16 || img.getHeight() != height * 16)) {
	    		Log.IO.error("Konnte Font-Textur nicht laden: Größe ist nicht %dx%d", width * 16, height * 16);
				img = null;
			}
			if(img == null)
				img = new BufferedImage(width * 16, height * 16, BufferedImage.TYPE_INT_ARGB);
	        int[] data = new int[width * 16 * height * 16];
	        img.getRGB(0, 0, width * 16, height * 16, data, 0, width * 16);
			calculate(data, font.sizes, width, height, 0);
			font.texture = GL11.glGenTextures();
			TextureUtil.uploadImage(font.texture, img);
			Log.RENDER.debug("Font-Textur wurde mit ID #%d geladen", font.texture);
		}
	}
	
	public static void select(Font font) {
		WIDTH = font.width;
		HEIGHT = font.height;
		TEXTURE = font.texture;
		SIZES = font.sizes;
		SELECTED = font;
	}
	
	public static void set(Font font) {
		WIDTH = font.width;
		HEIGHT = font.height;
		TEXTURE = font.texture;
		SIZES = font.sizes;
	}
	
	public static void unset() {
		WIDTH = SELECTED.width;
		HEIGHT = SELECTED.height;
		TEXTURE = SELECTED.texture;
		SIZES = SELECTED.sizes;
	}
	
	public static void unloadFonts() {
		for(Font font : values()) {
			if(font.texture != 0) {
				GL11.glDeleteTextures(font.texture);
				Log.RENDER.debug("Font-Textur mit ID #%d wurde gelöscht", font.texture);
				font.texture = 0;
			}
		}
	}
	
	private Font(String name, String display, int width, int height) {
		this.name = name;
		this.display = display;
		this.width = width;
		this.height = height;
	}

	public String getName() {
		return this.name;
	}

	public String getDisplay() {
		return this.display;
	}

	public int getWidth() {
		return this.width;
	}

	public int getHeight() {
		return this.height;
	}
}
