package speiger.src.coreengine.rendering.models.buffers;

import java.nio.ByteBuffer;
import java.util.Iterator;
import java.util.List;

import org.lwjgl.system.MemoryStack;
import org.lwjgl.system.MemoryUtil;

import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.rendering.tesselation.commands.DrawArraysIndirectCommand;
import speiger.src.coreengine.rendering.utils.values.GLBuffer;

public class IndirectArrayBuffer extends VertexBuffer implements Iterable<DrawArraysIndirectCommand> {
	List<DrawArraysIndirectCommand> commands = new ObjectArrayList<>();
	boolean managed = false;
	
	public IndirectArrayBuffer() {
		super(GLBuffer.DRAW_INDIRECT_BUFFER);
	}
	
	public IndirectArrayBuffer(int size) {
		super(GLBuffer.DRAW_INDIRECT_BUFFER);
		for(int i = 0;i<size;i++) {
			commands.add(new DrawArraysIndirectCommand());
		}
		allocate(size * 16);
	}
	
	public int commands() {
		return commands.size();
	}
	
	public IndirectArrayBuffer setManaged(boolean value) {
		managed = value;
		return this;
	}
	
	public IndirectArrayBuffer add(DrawArraysIndirectCommand command) {
		commands.add(command);
		upload(command, commands.size()-1);
		return this;
	}
	
	public IndirectArrayBuffer set(int index, DrawArraysIndirectCommand command) {
		commands.set(index, command);
		upload(command, index);
		return this;
	}
	
	public DrawArraysIndirectCommand get(int index) {
		return commands.get(index);
	}
	
	public IndirectArrayBuffer update(int index) {
		upload(commands.get(index), index);
		return this;
	}
	
	public IndirectArrayBuffer remove(int index) {
		commands.remove(index);
		if(index != commands.size()) shift((index + 1) * 16, index*16, (commands.size()-index) * 16);
		return this;
	}
	
	public IndirectArrayBuffer uploadAll() {
		ByteBuffer buffer = MemoryUtil.memAlloc(commands.size() * 16);
		for(int i = 0,m=commands.size();i<m;i++) {
			commands.get(i).write(buffer);
		}
		buffer.flip();
		if(size < commands.size() * 16) set(buffer);
		else fill(0, buffer);
		return this;
	}
	
	private void upload(DrawArraysIndirectCommand command, int index) {
		if(managed) return;
		if(size <= index * 16) grow(size * 2);
		try(MemoryStack stack = MemoryStack.stackPush()) {
			ByteBuffer buf = stack.malloc(16);
			command.write(buf);
			fill(index*16, buf.flip());
		}
	}
	
	@Override
	public Iterator<DrawArraysIndirectCommand> iterator() {
		return commands.iterator();
	}
}