package speiger.src.coreengine.platform.graphics.api.texture;

import java.util.Objects;
import java.util.Optional;
import java.util.OptionalInt;

import speiger.src.collections.objects.lists.ImmutableObjectList;
import speiger.src.coreengine.platform.graphics.api.texture.states.StencilType;
import speiger.src.coreengine.platform.graphics.api.texture.states.SwizzleMask;
import speiger.src.coreengine.platform.graphics.api.texture.states.TextureFormat;
import speiger.src.coreengine.platform.graphics.api.texture.states.TextureType;

public record TextureSettings(TextureType type, TextureFormat internal, boolean generateMipmapping, OptionalInt baseLevel, OptionalInt maxLevel, ImmutableObjectList<Optional<SwizzleMask>> swizzle, Optional<StencilType> stencilType) {
	
	public TextureSettings {
		Objects.requireNonNull(type, "Texture Type shouldn't be null"); 
		Objects.requireNonNull(internal, "Internal Format shouldn't be null"); 
		Objects.requireNonNull(baseLevel);
		Objects.requireNonNull(maxLevel);
		Objects.requireNonNull(swizzle);
		Objects.requireNonNull(stencilType);
	}
	
	public Builder copy() { return new Builder(this); }
	public static Builder builder() { return new Builder(); }
	
	public boolean hasSwizzle() {
		for(int i = 0;i<4;i++) {
			if(swizzle().get(i).isPresent()) return true;
		}
		return false;
	}
	
	public static class Builder {
		TextureFormat internalFormat = TextureFormat.RGBA;
		TextureType type = TextureType.TEXTURE_2D;
		boolean generateMipmapping = false;
		OptionalInt baseLevel = OptionalInt.empty();
		OptionalInt maxLevel = OptionalInt.empty();
		@SuppressWarnings("unchecked")
		Optional<SwizzleMask>[] swizzle = new Optional[] {Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()};
		Optional<StencilType> stencilType = Optional.empty();
		
		private Builder() {}
		private Builder(TextureSettings settings) {
			type = settings.type;
			internalFormat = settings.internal;
			generateMipmapping = settings.generateMipmapping;
			baseLevel = settings.baseLevel;
			maxLevel = settings.maxLevel;
			settings.swizzle.toArray(swizzle);
			stencilType = settings.stencilType;
		}
		
		public TextureSettings build() {
			return new TextureSettings(
					Objects.requireNonNull(type, "Texture Type shouldn't be null"), 
					Objects.requireNonNull(internalFormat, "Internal Format shouldn't be null"),  
					generateMipmapping, baseLevel, maxLevel, new ImmutableObjectList<>(swizzle), stencilType);
		}
		
		public Builder type(TextureType type) {
			this.type = type;
			return this;
		}
		
		public Builder format(TextureFormat format) {
			this.internalFormat = format;
			return this;
		}
		
		public Builder internal(TextureFormat format) {
			this.internalFormat = format;
			return this;
		}
		
		public Builder swizzle(SwizzleMask red, SwizzleMask green, SwizzleMask blue, SwizzleMask alpha) {
			swizzle[0] = Optional.ofNullable(red);
			swizzle[1] = Optional.ofNullable(green);
			swizzle[2] = Optional.ofNullable(blue);
			swizzle[3] = Optional.ofNullable(alpha);
			return this;
		}
		
		public Builder swizzleRed(SwizzleMask mask) {
			swizzle[0] = Optional.ofNullable(mask);
			return this;
		}
		
		public Builder swizzleGreen(SwizzleMask mask) {
			swizzle[1] = Optional.ofNullable(mask);
			return this;
		}
		
		public Builder swizzleBlue(SwizzleMask mask) {
			swizzle[2] = Optional.ofNullable(mask);
			return this;
		}
		
		public Builder swizzleAlpha(SwizzleMask mask) {
			swizzle[3] = Optional.ofNullable(mask);
			return this;
		}
		
		public Builder stencil(StencilType type) {
			stencilType = Optional.ofNullable(type);
			return this;
		}
		
		public Builder generateMipmapping(boolean value) {
			this.generateMipmapping = value;
			return this;
		}
		
		public Builder mipMapping(int base, int max) {
			this.baseLevel = OptionalInt.of(base);
			this.maxLevel = OptionalInt.of(max);
			return this;
		}
		
		public Builder clearmMipMapping() {
			this.baseLevel = OptionalInt.empty();
			this.maxLevel = OptionalInt.empty();
			return this;
		}
	}
}
