package speiger.src.coreengine.platform.graphics.opengl.utils;

import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL13;
import org.lwjgl.opengl.GL14;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL21;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GL31;
import org.lwjgl.opengl.GL32;
import org.lwjgl.opengl.GL40;
import org.lwjgl.opengl.GL42;
import org.lwjgl.opengl.GL43;
import org.lwjgl.opengl.GL44;

import speiger.src.coreengine.platform.graphics.api.buffer.states.BufferState;
import speiger.src.coreengine.platform.graphics.api.buffer.states.BufferType;
import speiger.src.coreengine.platform.graphics.api.buffer.states.IndeciesType;
import speiger.src.coreengine.platform.graphics.api.compute.BarrierType;
import speiger.src.coreengine.platform.graphics.api.sampler.states.BorderMode;
import speiger.src.coreengine.platform.graphics.api.sampler.states.SampleMode;
import speiger.src.coreengine.platform.graphics.api.shader.states.BlendFactor;
import speiger.src.coreengine.platform.graphics.api.shader.states.DrawMode;
import speiger.src.coreengine.platform.graphics.api.shader.states.GraphicsDataType;
import speiger.src.coreengine.platform.graphics.api.shader.states.PolygonMode;
import speiger.src.coreengine.platform.graphics.api.shader.states.ShaderType;
import speiger.src.coreengine.platform.graphics.api.texture.states.StencilType;
import speiger.src.coreengine.platform.graphics.api.texture.states.SwizzleMask;
import speiger.src.coreengine.platform.graphics.api.texture.states.TextureFormat;
import speiger.src.coreengine.platform.graphics.api.texture.states.TextureType;
import speiger.src.coreengine.platform.graphics.api.utils.AccessType;
import speiger.src.coreengine.platform.graphics.api.utils.AlphaFunction;

public class GLUtils {	
	public static int toGL(BufferType type) {
		return switch(type) {
			case ARRAY_BUFFER -> GL15.GL_ARRAY_BUFFER;
			case ELEMENT_BUFFER -> GL15.GL_ELEMENT_ARRAY_BUFFER;
			case UNIFORM_BUFFER -> GL31.GL_UNIFORM_BUFFER;
			case DRAW_INDIRECT_BUFFER -> GL40.GL_DRAW_INDIRECT_BUFFER;
			case TEXTURE_BUFFER -> GL31.GL_TEXTURE_BUFFER;
			case PIXEL_PACK_BUFFER -> GL21.GL_PIXEL_PACK_BUFFER;
			case PIXEL_UNPACK_BUFFER -> GL21.GL_PIXEL_UNPACK_BUFFER;
			case TRANSFORM_FEEDBACK_BUFFER -> GL30.GL_TRANSFORM_FEEDBACK_BUFFER;
			case COPY_READ_BUFFER -> GL31.GL_COPY_READ_BUFFER;
			case COPY_WRITE_BUFFER -> GL31.GL_COPY_WRITE_BUFFER;
			case ATOMIC_COUNTER_BUFFER -> GL42.GL_ATOMIC_COUNTER_BUFFER;
			case DISPATCH_INDIRECT_BUFFER -> GL43.GL_DISPATCH_INDIRECT_BUFFER; 
			case SHADER_STORAGE_BUFFER -> GL43.GL_SHADER_STORAGE_BUFFER;
		};
	}
	
	public static int toGL(BufferState state) {
		return switch(state) {
			case STATIC_DRAW -> GL15.GL_STATIC_DRAW;
			case STATIC_READ -> GL15.GL_STATIC_READ;
			case STATIC_COPY -> GL15.GL_STATIC_COPY;
			case STREAM_DRAW -> GL15.GL_STREAM_DRAW;
			case STREAM_READ -> GL15.GL_STREAM_READ;
			case STREAM_COPY -> GL15.GL_STREAM_COPY;
			case DYNAMIC_DRAW -> GL15.GL_DYNAMIC_DRAW;
			case DYNAMIC_READ -> GL15.GL_DYNAMIC_READ;
			case DYNAMIC_COPY -> GL15.GL_DYNAMIC_COPY;
		};
	}
		
	public static int toGL(TextureType type) {
		return switch(type) {
			case TEXTURE_1D -> GL11.GL_TEXTURE_1D;
			case TEXTURE_1D_ARRAY -> GL30.GL_TEXTURE_1D_ARRAY;
			case TEXTURE_2D -> GL11.GL_TEXTURE_2D;
			case TEXTURE_2D_ARRAY -> GL30.GL_TEXTURE_2D_ARRAY;
			case TEXTURE_2D_MULTISAMPLE -> GL32.GL_TEXTURE_2D_MULTISAMPLE;
			case TEXTURE_2D_MULTISAMPLE_ARRAY -> GL32.GL_TEXTURE_2D_MULTISAMPLE_ARRAY;
			case TEXTURE_3D -> GL12.GL_TEXTURE_3D;
			case TEXTURE_CUBE_MAP -> GL32.GL_TEXTURE_CUBE_MAP;
			case TEXTURE_CUBE_MAP_ARRAY -> GL40.GL_TEXTURE_CUBE_MAP_ARRAY;
			case TEXTURE_RECTANGLE -> GL31.GL_TEXTURE_RECTANGLE;
			case TEXTURE_BUFFER -> GL31.GL_TEXTURE_BUFFER;
		};
	}
	
	public static int toGLInternal(TextureFormat format) {
		return switch(format) {
			case R -> GL11.GL_RED;
			case RG -> GL30.GL_RG;
			case RGB -> GL11.GL_RGB;
			case RGBA -> GL11.GL_RGBA8;
			case DEPTH -> GL11.GL_DEPTH_COMPONENT;
			case DEPTH_STENCIL -> GL30.GL_DEPTH_STENCIL;
			case LUMINANCE -> GL30.GL_R8;
			case LUMINANCE_ALPHA -> GL11.GL_LUMINANCE8_ALPHA8;
		};
	}
	
	public static int toGLExternal(TextureFormat format) {
		return switch(format) {
			case R -> GL11.GL_RED;
			case RG -> GL30.GL_RG;
			case RGB -> GL11.GL_RGB;
			case RGBA -> GL11.GL_RGBA;
			case DEPTH -> GL11.GL_DEPTH_COMPONENT;
			case DEPTH_STENCIL -> GL30.GL_DEPTH_STENCIL;
			case LUMINANCE -> GL30.GL_R8;
			case LUMINANCE_ALPHA -> GL11.GL_LUMINANCE8_ALPHA8;
		};
	}
	
	public static int components(TextureFormat format) {
		return switch(format) {
			case R -> 1;
			case RG -> 2;
			case RGB -> 3;
			case RGBA -> 4;
			case DEPTH -> 1;
			case DEPTH_STENCIL -> 2;
			case LUMINANCE -> 1;
			case LUMINANCE_ALPHA -> 2;
		};
	}
	
	public static int toGL(AccessType type) {
		return switch(type) {
			case READ -> GL15.GL_READ_ONLY;
			case WRITE -> GL15.GL_WRITE_ONLY;
			case BOTH -> GL15.GL_READ_WRITE;
		};
	}
	
	public static int toGL(SwizzleMask mask) {
		return switch(mask) {
			case RED -> GL11.GL_RED;
			case GREEN -> GL11.GL_GREEN;
			case BLUE -> GL11.GL_BLUE;
			case ALPHA -> GL11.GL_ALPHA;
			case ZERO -> GL11.GL_ZERO;
			case ONE -> GL11.GL_ONE;
			
		};
	}
	
	public static int toGL(StencilType type) {
		return type == StencilType.GL_COMPARE_REF_TO_TEXTURE ? GL30.GL_COMPARE_REF_TO_TEXTURE : GL11.GL_NONE;
	}
	
	//Sampler begin
	public static int toGL(BorderMode mode) {
		return switch(mode) {
			case CLAMP_TO_BORDER -> GL13.GL_CLAMP_TO_BORDER;
			case CLAMP_TO_EDGE -> GL12.GL_CLAMP_TO_EDGE;
			case MIRRORED_REPEAT -> GL14.GL_MIRRORED_REPEAT;
			case MIRROR_CLAMP_TO_EDGE -> GL44.GL_MIRROR_CLAMP_TO_EDGE;
			case REPEAT -> GL11.GL_REPEAT;
		};
	}
	
	public static int toGL(SampleMode mode) {
		return switch(mode) {
			case LINEAR -> GL11.GL_LINEAR;
			case LINEAR_MIPMAP_LINEAR -> GL11.GL_LINEAR_MIPMAP_LINEAR;
			case LINEAR_MIPMAP_NEAREST -> GL11.GL_LINEAR_MIPMAP_NEAREST;
			case NEAREST -> GL11.GL_NEAREST;
			case NEAREST_MIPMAP_LINEAR -> GL11.GL_NEAREST_MIPMAP_LINEAR;
			case NEAREST_MIPMAP_NEAREST -> GL11.GL_NEAREST_MIPMAP_NEAREST;
		};
	}
	
	public static int toGL(AlphaFunction type) {
		return switch(type) {
			case ALWAYS -> GL11.GL_ALWAYS;
			case EQUAL -> GL11.GL_EQUAL;
			case GEQUAL -> GL11.GL_GEQUAL;
			case GREATER -> GL11.GL_GREATER;
			case LEQUAL -> GL11.GL_LEQUAL;
			case LESS -> GL11.GL_LESS;
			case NEVER -> GL11.GL_NEVER;
			case NOTEQUAL -> GL11.GL_NOTEQUAL;
		};
	}

	public static int toGL(GraphicsDataType type) {
		return switch(type) {
			case BYTE -> GL11.GL_BYTE;
			case UNSIGNED_BYTE -> GL11.GL_UNSIGNED_BYTE;
			case SHORT -> GL11.GL_SHORT;
			case UNSIGNED_SHORT -> GL11.GL_UNSIGNED_SHORT;
			case INT -> GL11.GL_INT;
			case UNSIGNED_INT -> GL11.GL_UNSIGNED_INT;
			case FLOAT -> GL11.GL_FLOAT;
			case DOUBLE -> GL11.GL_DOUBLE;
			case UNSIGNED_3_3_2 -> GL12.GL_UNSIGNED_BYTE_3_3_2;
			case UNSIGNED_2_3_3_REV -> GL12.GL_UNSIGNED_BYTE_2_3_3_REV;
			case UNSIGNED_5_6_5 -> GL12.GL_UNSIGNED_SHORT_5_6_5;
			case UNSIGNED_5_6_5_REV -> GL12.GL_UNSIGNED_SHORT_5_6_5_REV;
			case UNSIGNED_4_4_4_4 -> GL12.GL_UNSIGNED_SHORT_4_4_4_4;
			case UNSIGNED_4_4_4_4_REV -> GL12.GL_UNSIGNED_SHORT_4_4_4_4_REV;
			case UNSIGNED_5_5_5_1 -> GL12.GL_UNSIGNED_SHORT_5_5_5_1;
			case UNSIGNED_1_5_5_5_REV -> GL12.GL_UNSIGNED_SHORT_1_5_5_5_REV;
			case UNSIGNED_8_8_8_8 -> GL12.GL_UNSIGNED_INT_8_8_8_8;
			case UNSIGNED_8_8_8_8_REV -> GL12.GL_UNSIGNED_INT_8_8_8_8_REV;
			case UNSIGNED_10_10_10_2 -> GL12.GL_UNSIGNED_INT_10_10_10_2;
			case UNSIGNED_2_10_10_10_REV -> GL12.GL_UNSIGNED_INT_2_10_10_10_REV;
			case UNSIGNED_INT_10F_11F_11F_REV -> GL30.GL_UNSIGNED_INT_10F_11F_11F_REV;
			case UNSIGNED_INT_5_9_9_9_REV -> GL30.GL_UNSIGNED_INT_5_9_9_9_REV;
		};
	}

	public static int toGL(BlendFactor type) {
		return switch(type) {
			case ZERO -> GL11.GL_ZERO;
			case ONE -> GL11.GL_ONE;
			case CONSTANT_COLOR -> GL15.GL_CONSTANT_COLOR;
			case CONSTANT_ALPHA -> GL15.GL_CONSTANT_ALPHA;
			case SRC_COLOR -> GL11.GL_SRC_COLOR;
			case SRC_ALPHA -> GL11.GL_SRC_ALPHA;
			case DST_COLOR -> GL11.GL_DST_COLOR;
			case DST_ALPHA -> GL11.GL_DST_ALPHA;
			case ONE_MINUS_SRC_COLOR -> GL11.GL_ONE_MINUS_SRC_COLOR;
			case ONE_MINUS_SRC_ALPHA -> GL11.GL_ONE_MINUS_SRC_ALPHA;
			case ONE_MINUS_DST_COLOR -> GL11.GL_ONE_MINUS_DST_COLOR;
			case ONE_MINUS_DST_ALPHA -> GL11.GL_ONE_MINUS_DST_ALPHA;
			case ONE_MINUS_CONSTANT_COLOR -> GL15.GL_ONE_MINUS_CONSTANT_COLOR;
			case ONE_MINUS_CONSTANT_ALPHA -> GL15.GL_ONE_MINUS_CONSTANT_ALPHA;
			case SRC_ALPHA_SATURATE -> GL11.GL_SRC_ALPHA_SATURATE;
		};
	}

	public static int toGL(PolygonMode state) {
		return switch(state) {
			case FILL -> GL11.GL_FILL;
			case LINE -> GL11.GL_LINE;
			case POINT -> GL11.GL_POINT;			
		};
	}

	public static int toGL(ShaderType type) {
		return switch(type) {
			case VERTEX -> GL20.GL_VERTEX_SHADER;
			case FRAGMENT -> GL20.GL_FRAGMENT_SHADER;
			case GEOMETRY -> GL32.GL_GEOMETRY_SHADER;
			case TESSELATION_CONTROL -> GL40.GL_TESS_CONTROL_SHADER;
			case TESSELATION_EVALUATION -> GL40.GL_TESS_EVALUATION_SHADER;
			case COMPUTE -> GL43.GL_COMPUTE_SHADER;
		};
	}

	public static int toGL(DrawMode mode) {
		return switch(mode) {
			case POINT -> GL11.GL_POINT;
			case LINES -> GL11.GL_LINES;
			case LINE_LOOP -> GL11.GL_LINE_LOOP;
			case LINE_STRIP -> GL11.GL_LINE_STRIP;
			case TRIANGLES -> GL11.GL_TRIANGLES;
			case TRIANGLE_FAN -> GL11.GL_TRIANGLE_FAN;
			case TRIANGLE_STRIP -> GL11.GL_TRIANGLE_STRIP;			
			case QUADS -> GL11.GL_QUADS;
		};
	}

	public static int toGL(IndeciesType type) {
		return switch(type) {
			case BYTE -> GL11.GL_UNSIGNED_BYTE;
			case SHORT -> GL11.GL_UNSIGNED_SHORT;
			case INT -> GL11.GL_UNSIGNED_INT;
		};
	}

	public static int toGL(BarrierType type) {
		return switch(type) {
			case MESH_BUFFER -> GL42.GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT | GL42.GL_ELEMENT_ARRAY_BARRIER_BIT;
			case SHADER_TEXTURE -> GL42.GL_TEXTURE_FETCH_BARRIER_BIT;
			case SHADER_IMAGE -> GL42.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
			case SHADER_STORAGE -> GL43.GL_SHADER_STORAGE_BARRIER_BIT;
			case SHADER_UNIFORM -> GL42.GL_UNIFORM_BARRIER_BIT;
			case INDIRECT_COMMAND -> GL42.GL_COMMAND_BARRIER_BIT;
			case FRAMEBUFFER -> GL42.GL_FRAMEBUFFER_BARRIER_BIT;
			case CPU -> GL42.GL_BUFFER_UPDATE_BARRIER_BIT | GL44.GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT;
		};
	}
}
