package speiger.src.coreengine.rendering.models;

import speiger.src.coreengine.rendering.models.buffers.VertexBuffer;

public class MultiVertexBuffer {
	VertexBuffer buffer;
	final int bytesPerIndex;
	final int limit;
	final int startSize;
	final float growRate;
	final int padding;
	final int[][] offsets;
	int currentCapacity;
	
	public MultiVertexBuffer(VertexBuffer buffer, int bytesPerIndex, int limit, int startSize, int padding, float growRate, int[][] offsets) {
		super();
		this.buffer = buffer;
		this.bytesPerIndex = bytesPerIndex;
		this.limit = limit;
		this.startSize = startSize;
		this.padding = padding;
		this.growRate = growRate;
		this.offsets = offsets;
		currentCapacity = startSize;
		buffer.bind().allocate(startSize * bytesPerIndex).unbind();
	}
	
	public boolean ensureSize(int index, int capacity) {
		int[] offset = offsets[index];
		int room = offset[2] - offset[0];
		if(capacity >= room) {
			int newCap = Math.max((int)(room * growRate), capacity + 1);
			offset[2] = offset[0] + newCap;
			grow(index + 1, newCap - room);
			return true;
		}
		return false;
	}
	
	protected void grow(int index, int extra) {
		if(index == offsets.length) {
			int newCap = offsets[offsets.length - 1][2] + extra;
			if(newCap > currentCapacity) {
				if(currentCapacity == limit) { throw new RuntimeException("THIS SHOULD NEVER HAPPEN!: "+currentCapacity+":"+limit); }
				currentCapacity = Math.min(Math.max(currentCapacity + (currentCapacity / 2), newCap), limit);
				buffer.bind().grow(currentCapacity * bytesPerIndex).unbind();
			}
			return;
		}
		int startBytes = offsets[index][0] * bytesPerIndex;
		int endBytes = offsets[offsets.length - 1][2] * bytesPerIndex;
		for(int i = index;i < offsets.length;i++) {
			offsets[i][0] += extra;
			offsets[i][2] += extra;
		}
		grow(offsets.length, extra);
		buffer.bind().shift(startBytes, endBytes - startBytes, extra * bytesPerIndex).unbind();
	}
	
	protected void shrink(int index, int extra) {
		if(index == offsets.length) {
			int newCap = offsets[offsets.length - 1][2] - extra;
			if(newCap < currentCapacity / 2 && currentCapacity != 10) {
				currentCapacity = Math.max(10, newCap);
				buffer.bind().shrink(currentCapacity * bytesPerIndex).unbind();
			}
			return;
		}
		int startBytes = offsets[index][0] * bytesPerIndex;
		buffer.bind().shift(startBytes, (offsets[offsets.length - 1][2] * bytesPerIndex) - startBytes, -(extra * bytesPerIndex)).unbind();
		for(int i = index;i < offsets.length;i++) {
			offsets[i][0] -= extra;
			offsets[i][2] -= extra;
		}
		shrink(offsets.length, extra);
	}
}
