package speiger.src.coreengine.rendering.shader;

import org.lwjgl.opengl.GL20;

import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.lists.ObjectList;
import speiger.src.coreengine.assets.base.IAssetProvider;
import speiger.src.coreengine.assets.base.IManagedAsset;
import speiger.src.coreengine.assets.base.IReloadableAsset.ISimpleRealodableAsset;

public class ShaderTracker implements ISimpleRealodableAsset, IManagedAsset {
	ObjectList<Shader<?>> shaders = new ObjectArrayList<>();
	int activeShaderId;
	IAssetProvider provider;
		
	public void register(Shader<?> shader) {
		if(shaders.contains(shader)) throw new IllegalStateException("Shader is already registered!");
		shaders.add(shader);
		load(provider, shader);
	}
	
	public void remove(Shader<?> shader) {
		shaders.remove(shader);
	}
	
	public void bind(ShaderProgram program) {
		bind(shaderId(program));
	}
	
	public void bind(int shaderId) {
		if(activeShaderId == shaderId) return;
		activeShaderId = shaderId;
		GL20.glUseProgram(shaderId);
	}
	
	public void unbind() { bind(0); }
	
	public boolean isActive() { return activeShaderId != 0; }
	public boolean isShaderActive(ShaderProgram program) { return activeShaderId == shaderId(program); }
	public int getActiveShader() { return activeShaderId; }
	public ShaderProgram getActiveProgram() {
		if(isActive()) {
			for(int i = 0,m=shaders.size();i<m;i++) {
				ShaderProgram program = shaders.get(i).get();
				if(activeShaderId == shaderId(program)) {
					return program;
				}
			}
		}
		return null;
	}
	
	private int shaderId(ShaderProgram program) {
		return program == null ? 0 : program.id();
	}
	
	@Override
	public void destroy() {
		shaders.forEach(Shader::remove);
		shaders.clear();
		activeShaderId = 0;
	}

	@Override
	public String getName() { return "shader_tracker"; }
	@Override
	public void setProvider(IAssetProvider provider) { this.provider = provider; }
	@Override
	public void onAssetsReloaded(IAssetProvider provider) {
		ShaderProgram.IMPORTS.clear();
		shaders.forEach(provider, this::load);
		activeShaderId = 0;
	}
	
	private void load(IAssetProvider provider, Shader<?> shader) {
		if(provider == null) return;
		shader.load(provider);
		shader.validate();
	}
}
