package speiger.src.coreengine.rendering.shader.uniform;

import org.lwjgl.opengl.GL20;

import speiger.src.collections.ints.maps.impl.hash.Int2IntOpenHashMap;
import speiger.src.collections.ints.maps.interfaces.Int2IntMap;
import speiger.src.coreengine.rendering.shader.ShaderProgram;
import speiger.src.coreengine.rendering.utils.GLStateTracker;
import speiger.src.coreengine.utils.io.GameLog;

public abstract class Uniform implements IUniform {
	protected final String name;
	protected final Int2IntMap positions = new Int2IntOpenHashMap();
	
	public Uniform(String name) {
		this.name = name;
		positions.setDefaultReturnValue(-1);
	}
	
	public String name() {
		return name;
	}
	
	protected boolean contains(int shaderId) {
		return positions.containsKey(shaderId);
	}
	
	protected int getPosition(ShaderProgram program) {
		return positions.get(program.id());
	}
	
	public void registerShader(ShaderProgram program) {
		int position = getUniformLocation(program.id(), name);
		if(position == -1) {
			GameLog.error("Couldn't find Shader Uniform: "+name+", Shader: "+"("+program.getClass().getSimpleName()+".java:0) ("+program.id()+")");
			return;
		}
		positions.put(program.id(), position);
		processChanges(position, position);
	}
	
	public void removeShader(ShaderProgram program) {
		positions.remove(program.id());
	}
	
	protected int getUniformLocation(int id, String name) {
		return GL20.glGetUniformLocation(id, name);
	}
	
	protected void update() {
		positions.forEach(this::processChanges);
		if(this instanceof IAutoUniform auto) {
			int id = GLStateTracker.instance().shaders.getActiveShader();
			if(contains(id)) auto.bind(id);
		}
	}
	
	protected void processChanges(int programId, int location) {
		
	}
}
