package speiger.src.coreengine.rendering.models;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.lwjgl.opengl.GL15;
import org.lwjgl.opengl.GL30;


public abstract class VertexArray
{
	int arrayID;
	List<BufferAttribute> attributes = new ArrayList<BufferAttribute>();
	VertexBuffer indeciesBuffer;
	List<VertexBuffer> buffers = new ArrayList<VertexBuffer>();
	
	public VertexArray()
	{
		arrayID = GL30.glGenVertexArrays();
	}
	
	public abstract int getVertexCount();
	
	protected void bind()
	{
		GL30.glBindVertexArray(arrayID);
	}
	
	public void bindArray()
	{
		bind();
		for(BufferAttribute attr : attributes)
		{
			attr.bind();
		}
	}
	
	protected BufferAttribute getAttribute(int index)
	{
		return attributes.get(index);
	}
	
	protected void unbind()
	{
		GL30.glBindVertexArray(0);
	}
		
	public void unbindArray()
	{
		for(BufferAttribute attr : attributes)
		{
			attr.unbind();
		}
		unbind();
	}
	
	public int getArrayID()
	{
		return arrayID;
	}
	
	public boolean isValid()
	{
		return arrayID != -1;
	}
	
	public boolean isInvalid()
	{
		return arrayID == -1;
	}
	
	public void remove()
	{
		if(arrayID == -1)
		{
			return;
		}
		GL30.glDeleteVertexArrays(arrayID);
		if(indeciesBuffer != null)
		{
			indeciesBuffer.delete();
		}
		for(VertexBuffer buffer : buffers)
		{
			buffer.delete();
		}
		arrayID = -1;
	}
	
	public VertexBuffer getIndeciesBuffer()
	{
		return indeciesBuffer;
	}
	
	public VertexBuffer getBuffer(int index)
	{
		return buffers.get(index);
	}
	
	public void createIndenciesBuffer(int[] indencies)
	{
		indeciesBuffer = new VertexBuffer(GL15.GL_ELEMENT_ARRAY_BUFFER);
		indeciesBuffer.bind();
		indeciesBuffer.setBufferData(indencies);
	}
	
	public void updateIndenciesBuffer(int[] indencies)
	{
		indeciesBuffer.bind();
		indeciesBuffer.setBufferData(indencies);
	}
	
	public VertexBuffer createSimpleBuffer(int index, int size, GLDataType type)
	{
		VertexBuffer buffer = new VertexBuffer(GL15.GL_ARRAY_BUFFER);
		buffers.add(buffer);
		buffer.bind();
		BufferAttribute attribute = new BufferAttribute(index, size, type);
		attributes.add(attribute);
		finishAttributes(attribute);
		return buffer;
	}
	
	public VertexBuffer createBuffer(BufferAttribute...array)
	{
		VertexBuffer buffer = new VertexBuffer(GL15.GL_ARRAY_BUFFER);
		buffers.add(buffer);
		attributes.addAll(Arrays.asList(array));
		buffer.bind();
		finishAttributes(array);
		return buffer;
	}
	
	public void removeBuffer(int attr)
	{
		for(int i = 0;i<attr;i++)
		{
			attributes.remove(attributes.size() - 1);
		}
		buffers.remove(buffers.size() - 1);
	}
	
	public static void finishAttributes(BufferAttribute...array)
	{
		finishAttributes(countBytes(array), array);
	}
	
	public static void finishAttributes(int totalBytes, BufferAttribute...array)
	{
		int offset = 0;
		for(BufferAttribute attr : array)
		{
			attr.bind();
			attr.applyAttribute(totalBytes, offset);
			offset += attr.type.calulateSize(attr.size);
		}
	}
	
	public static int countBytes(BufferAttribute...array)
	{
		int totalBytes = 0;
		for(BufferAttribute attr : array)
		{
			totalBytes += attr.type.calulateSize(attr.size);
		}
		return totalBytes;
	}
}
