package speiger.src.coreengine.rendering.shaderOld;

import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.lwjgl.opengl.GL20;

import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.assets.AssetManager;
import speiger.src.coreengine.assets.reloader.IReloadableResource;

public class ShaderTracker implements IReloadableResource
{
	public static final ShaderTracker INSTANCE = new ShaderTracker();
	List<ReloadReference<?>> programs = new ObjectArrayList<>();
	int activeShader = 0;
	boolean reloading = false;
	AssetManager assets;
	
	public void init(AssetManager assets) {
		this.assets = assets;
	}
	
	public <T extends ShaderProgram> T register(Supplier<T> creator, Consumer<T> reloader) {
		T result = creator.get();
		result.init();
		programs.add(new ReloadReference<>(result, creator, reloader));
		return result;
	}
	
	protected AssetManager getAssets() {
		return assets;
	}
	
	void startNextShader(ShaderProgram shader) {
		if(shader.getShaderID() == activeShader) return;
		activeShader = shader.getShaderID();
		GL20.glUseProgram(activeShader);
	}
	
	void stopShader(ShaderProgram shader) {
		if(activeShader == 0) return;
		activeShader = 0;
		GL20.glUseProgram(activeShader);
	}
	
	public void stopShader() {
		if(activeShader == 0) return;
		activeShader = 0;
		GL20.glUseProgram(activeShader);
	}
	
	public boolean isShaderActive() {
		return activeShader > 0;
	}
	
	@Override
	public void reload() {
		programs.forEach(ReloadReference::reload);
	}
	
	@Override
	public void destroy() {
		reloading = true;
		programs.forEach(ReloadReference::destroy);
		programs.clear();
		reloading = false;
	}
		
	class ReloadReference<T extends ShaderProgram> {
		T program;
		Supplier<T> creator;
		Consumer<T> listener;
		
		public ReloadReference(T value, Supplier<T> creator, Consumer<T> listener) {
			this.program = value;
			this.creator = creator;
			this.listener = listener;
			program.setReference(this);
		}
		
		private void destroy() {
			if(program == null || reloading) return;
			program.removeShader();
			program = null;
			listener.accept(null);
		}
		
		public void removeReference() {
			destroy();
			if(reloading) return;
			programs.remove(this);
		}
		
		public void reload() {
			reloading = true;
			program.removeShader();
			program = creator.get();
			program.init();
			program.setReference(this);
			listener.accept(program);
			reloading = false;
		}
	}
}
