package speiger.src.coreengine.rendering.utils.values;

import java.util.Map;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL30;

import speiger.src.collections.ints.maps.impl.hash.Int2ObjectOpenHashMap;
import speiger.src.collections.ints.maps.interfaces.Int2ObjectMap;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectOpenHashMap;
import speiger.src.coreengine.rendering.utils.values.IGLValue.IGLDataType;

public record GLDataType(String name, int glValue, int byteSize, GLDataType.DataType type, boolean supportsIBO, boolean isCompound) implements IGLDataType {
	static final Int2ObjectMap<GLDataType> ID_TO_TYPE = new Int2ObjectOpenHashMap<>();
	static final Map<String, GLDataType> NAME_TO_TYPE = new Object2ObjectOpenHashMap<>();
	
	//Basic Types
	public static final GLDataType BYTE = new GLDataType("byte", GL11.GL_BYTE, 1, DataType.BYTE);
	public static final GLDataType UNSIGNED_BYTE = new GLDataType("u_byte", GL11.GL_UNSIGNED_BYTE, 1, DataType.BYTE, true, false);
	public static final GLDataType SHORT = new GLDataType("short", GL11.GL_SHORT, 2, DataType.SHORT);
	public static final GLDataType UNSIGNED_SHORT = new GLDataType("u_short", GL11.GL_UNSIGNED_SHORT, 2, DataType.SHORT, true, false);
	public static final GLDataType INT = new GLDataType("int", GL11.GL_INT, 4, DataType.INT);
	public static final GLDataType UNSIGNED_INT = new GLDataType("u_int", GL11.GL_UNSIGNED_INT, 4, DataType.INT, true, false);
	public static final GLDataType FLOAT = new GLDataType("float", GL11.GL_FLOAT, 4, DataType.FLOAT);
	public static final GLDataType DOUBLE = new GLDataType("double", GL11.GL_DOUBLE, 8, DataType.DOUBLE);
	
	//CompressedTypes
	public static final GLDataType UNSIGNED_3_3_2 = new GLDataType("u_byte_3_3_2", GL12.GL_UNSIGNED_BYTE_3_3_2, 1, DataType.BYTE);
	public static final GLDataType UNSIGNED_2_3_3_REV = new GLDataType("u_byte_2_3_3_rev", GL12.GL_UNSIGNED_BYTE_2_3_3_REV, 1, DataType.BYTE);
	public static final GLDataType UNSIGNED_5_6_5 = new GLDataType("u_short_5_6_5", GL12.GL_UNSIGNED_SHORT_5_6_5, 2, DataType.SHORT);
	public static final GLDataType UNSIGNED_5_6_5_REV = new GLDataType("u_short_5_6_5_rev", GL12.GL_UNSIGNED_SHORT_5_6_5_REV, 2, DataType.SHORT);
	public static final GLDataType UNSIGNED_4_4_4_4 = new GLDataType("u_short_4_4_4_4", GL12.GL_UNSIGNED_SHORT_4_4_4_4, 2, DataType.SHORT);
	public static final GLDataType UNSIGNED_4_4_4_4_REV = new GLDataType("u_short_4_4_4_4_rev", GL12.GL_UNSIGNED_SHORT_4_4_4_4_REV, 2, DataType.SHORT);
	public static final GLDataType UNSIGNED_5_5_5_1 = new GLDataType("u_short_5_5_5_1", GL12.GL_UNSIGNED_SHORT_5_5_5_1, 2, DataType.SHORT);
	public static final GLDataType UNSIGNED_1_5_5_5_REV = new GLDataType("u_short_1_5_5_5_rev", GL12.GL_UNSIGNED_SHORT_1_5_5_5_REV, 2, DataType.SHORT);
	public static final GLDataType UNSIGNED_8_8_8_8 = new GLDataType("u_int_8_8_8_8", GL12.GL_UNSIGNED_INT_8_8_8_8, 4, DataType.INT);
	public static final GLDataType UNSIGNED_8_8_8_8_REV = new GLDataType("u_int_8_8_8_8_rev", GL12.GL_UNSIGNED_INT_8_8_8_8_REV, 4, DataType.INT);
	public static final GLDataType UNSIGNED_10_10_10_2 = new GLDataType("u_int_10_10_10_2", GL12.GL_UNSIGNED_INT_10_10_10_2, 4, DataType.INT);
	public static final GLDataType UNSIGNED_2_10_10_10_REV = new GLDataType("u_int_2_10_10_10_rev", GL12.GL_UNSIGNED_INT_2_10_10_10_REV, 4, DataType.INT);
	
	public static final GLDataType UNSIGNED_INT_10F_11F_11F_REV = new GLDataType("u_int_10_11_11_rev", GL30.GL_UNSIGNED_INT_10F_11F_11F_REV, 4, DataType.INT);
	public static final GLDataType UNSIGNED_INT_5_9_9_9_REV = new GLDataType("u_int_5_9_9_9_rev", GL30.GL_UNSIGNED_INT_5_9_9_9_REV, 4, DataType.INT);
	
	public GLDataType(String name, int glValue, int byteSize, DataType type, boolean isCompound) {
		this(name, glValue, byteSize, type, false, isCompound);
	}
	
	public GLDataType(String name, int glValue, int byteSize, DataType type) {
		this(name, glValue, byteSize, type, false, false);
	}
	
	public GLDataType {
		ID_TO_TYPE.put(glValue, this);
		NAME_TO_TYPE.put(name, this);
	}
	
	public int size(int attributes) { return isCompound ? byteSize : attributes * byteSize; }
	
	public static GLDataType byName(String name) { return NAME_TO_TYPE.get(name); }
	public static GLDataType byId(int id) { return ID_TO_TYPE.get(id); }
	
	public static enum DataType {
		BYTE,
		SHORT,
		INT,
		LONG,
		FLOAT,
		DOUBLE;
	}
}
