package speiger.src.coreengine.rendering.textures.base;

import org.lwjgl.opengl.GL45;

import speiger.src.collections.longs.lists.LongArrayList;
import speiger.src.collections.longs.lists.LongList;
import speiger.src.coreengine.math.BitUtil;
import speiger.src.coreengine.rendering.utils.values.IGLValue;
import speiger.src.coreengine.rendering.utils.values.IGLValue.IGLDataType;
import speiger.src.coreengine.rendering.utils.values.IGLValue.ITextureFormatType;
import speiger.src.coreengine.rendering.utils.values.IGLValue.ITextureParameter;

public class TextureMetadata {
	int internalFormat;
	int externalFormat;
	int dataFormat;
	LongList arguments = new LongArrayList();
	
	private TextureMetadata() {}
	
	public void applyArguments(int texture) {
		for(int i = 0,m=arguments.size();i<m;i++) {
			long value = arguments.getLong(i);
			GL45.glTextureParameteri(texture, BitUtil.toFirstInt(value), BitUtil.toSecondInt(value));
		}
	}
	
	public LongList getArguments() {
		return arguments.unmodifiable();
	}
	
	public int getInternalFormat() { return internalFormat; }
	public int getExternalFormat() { return externalFormat; }
	public int getDataFormat() { return dataFormat; }
	public Builder copy() { return new Builder(this); }
	public static Builder builder() { return new Builder(); }
	
	public static class Builder {
		TextureMetadata metadata = new TextureMetadata();
		
		private Builder() {}
		
		private Builder(TextureMetadata data) {
			metadata.internalFormat = data.internalFormat;
			metadata.externalFormat = data.externalFormat;
			metadata.dataFormat = data.dataFormat;
			metadata.arguments.addAll(data.arguments);
		}
		
		public Builder internalFormat(ITextureFormatType type) {
			if(!type.internal()) throw new IllegalArgumentException("The GL_Type ["+type.glMode()+"] isn't supported in the internal format");
			return internalFormat(type.glMode());
		}
		
		public Builder internalFormat(int glValue) {
			metadata.internalFormat = glValue;
			return this;
		}
		
		public Builder externalFormat(ITextureFormatType type) {
			return externalFormat(type.glMode());
		}
		
		public Builder externalFormat(int glValue) {
			metadata.externalFormat = glValue;
			return this;
		}
		
		public Builder dataFormat(IGLDataType type) {
			return dataFormat(type.glMode());
		}
		
		public Builder dataFormat(int glValue) {
			metadata.dataFormat = glValue;
			return this;
		}
		
		public Builder removeArgument(ITextureParameter id) {
			return removeArgument(id.glMode());
		}
		
		public Builder removeArgument(int id) {
			LongList list = metadata.arguments;
			for(int i = 0,m=list.size();i<m;i++) {
				if(BitUtil.toFirstInt(list.getLong(i)) == id) {
					list.removeLong(i--);
				}
			}
			return this;
		}
		
		public Builder arguement(ITextureParameter parameter, IGLValue value) {
			return argument(parameter, value.glMode());
		}
		
		public Builder argument(ITextureParameter parameter, int value) {
			if(!parameter.isValid(value)) throw new IllegalArgumentException("Value ["+value+"] isn't supported for GL Function ["+parameter.glMode()+"], only int functions are supported with this");
			return argument(parameter.glMode(), value);
		}
		
		public Builder argument(int id, int value) {
			metadata.arguments.add(BitUtil.toLong(id, value));
			return this;
		}
		
		public TextureMetadata build() {
			TextureMetadata meta = metadata;
			metadata = null;
			return meta;
		}
	}
}
