package theGhastModding.midiPlayerGL.models;

import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;

public class Loader {
	
	private List<Integer> textures;
	
	public Loader() {
		textures = new ArrayList<Integer>();
	}
	
	public RawModel loadToVAO(float[] positions, int[] indices) {
    	int vaoID = createVAO();
    	int[] vboIDs = new int[2];
    	vboIDs[0] = bindIndicesBuffer(indices);
    	vboIDs[1] = storeDataInAttributeListFloat(0, 2, positions);
    	unbindVAO();
    	return new RawModel(vaoID, indices.length, vboIDs);
	}
	
	public int[] loadToVAO(float[] positions, float[] textureCoords) {
		int vaoID = createVAO();
		int[] toReturn = new int[3];
		toReturn[1] = storeDataInAttributeListFloat(0, 2, positions);
		toReturn[2] = storeDataInAttributeListFloat(1, 2, textureCoords);
		unbindVAO();
		toReturn[0] = vaoID;
		return toReturn;
	}
	
    private int storeDataInAttributeListFloat(int attributeNumber, int coordinateSize, float[] data){
    	int vboID = GL15.glGenBuffers();
    	GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, vboID);
    	FloatBuffer buffer = storeDataInFloatBuffer(data);
    	GL15.glBufferData(GL15.GL_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
    	GL20.glVertexAttribPointer(attributeNumber, coordinateSize, GL11.GL_FLOAT, false, 0, 0);
    	GL15.glBindBuffer(GL15.GL_ARRAY_BUFFER, 0);
    	return vboID;
    }
	
	private int createVAO() {
    	int vaoID = GL30.glGenVertexArrays();
    	GL30.glBindVertexArray(vaoID);
    	return vaoID;
	}
	
    private void unbindVAO(){
    	GL30.glBindVertexArray(0);
    }
	
    public int bindIndicesBuffer(int[] indices){
    	int vboID = GL15.glGenBuffers();
    	GL15.glBindBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER, vboID);
    	IntBuffer buffer = storeDataInIntBuffer(indices);
    	GL15.glBufferData(GL15.GL_ELEMENT_ARRAY_BUFFER, buffer, GL15.GL_STATIC_DRAW);
    	return vboID;
    }
    
	public int loadTextureFromFile(String fileName) throws Exception {
		int textureID;
		BufferedImage bi;
		bi = ImageIO.read(this.getClass().getResourceAsStream(fileName));
		int width = bi.getWidth();
		int height = bi.getHeight();
		
		int[] pixels_raw = new int[width * height * 4];
		pixels_raw = bi.getRGB(0, 0, width, height, null, 0, width);
		
		
		ByteBuffer pixels = BufferUtils.createByteBuffer(width * height * 4);
		
		for(int i = 0; i < height; i++){
			for(int j = 0; j < width; j++){
				int pixel = pixels_raw[i * width + j];
				pixels.put((byte)((pixel >> 16) & 0xFF)); //R
				pixels.put((byte)((pixel >> 8) & 0xFF)); //G
				pixels.put((byte)(pixel & 0xFF)); //B
				pixels.put((byte)((pixel >> 24) & 0xFF)); //A
			}
		}
		
		pixels.flip();
		
		textureID = GL11.glGenTextures();
		textures.add(textureID);
		
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
		
		GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
		GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
		//GL11.glTexParameterf(GL11.GL_TEXTURE_2D, GL14.GL_TEXTURE_LOD_BIAS, -1);
		
		GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA, width, height, GL11.GL_NONE, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, pixels);
		GL30.glGenerateMipmap(GL11.GL_TEXTURE_2D);
		GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
		return textureID;
	}
    
	public void cleanUp() {
		for(Integer i:textures){
			GL11.glDeleteTextures(i);
		}
	}
	
    public IntBuffer storeDataInIntBuffer(int[] data){
    	IntBuffer buffer = BufferUtils.createIntBuffer(data.length);
    	buffer.put(data);
    	buffer.flip();
    	return buffer;
    }
    
    public FloatBuffer storeDataInFloatBuffer(float[] data){
    	FloatBuffer buffer = BufferUtils.createFloatBuffer(data.length);
    	buffer.put(data);
    	buffer.flip();
    	return buffer;
    }
	
}