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

import java.util.Objects;

import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.utils.Stack;
import speiger.src.coreengine.math.vector.ints.Vec4i;

public class ScissorsManager {
	IScissorsHandler handler;
	Stack<Vec4i> stack = new ObjectArrayList<>();
	boolean withRoot = false;
	int limit;
	
	public ScissorsManager(int limit, IScissorsHandler handler) {
		if(limit <= 0) throw new IllegalStateException("Limit is negative");
		this.limit = limit;
		this.handler = Objects.requireNonNull(handler, "Handler is required");
	}
	
	public void setRoot(int x, int y, int width, int height) {
		if(stack.size() > 0) throw new IllegalStateException("A Root can't be set if the Stack is already in use or the root is already set");
		withRoot = true;
		stack.push(Vec4i.of(x, y, x + width, y + height));
		handler.enable();
		handler.apply(x, y, width, height);
	}
	
	public void push(int x, int y, int width, int height) {
		if(stack.size() >= limit) {
			//TODO implement logging
			return;
		}
		if(stack.isEmpty()) {
			stack.push(Vec4i.of(x, y, x + width, y + height));
			handler.enable();
			handler.apply(x, y, width, height);
			return;
		}
		Vec4i top = stack.top();
		Vec4i result = Vec4i.of(Math.max(x, top.x()), Math.max(y, top.y()), Math.min(x + width, top.z()), Math.min(y + height, top.w()));
		stack.push(result);
		handler.apply(result.x(), result.y(), result.z() - result.x(), result.w() - result.y());
	}
	
	public Vec4i top() { 
		return stack.isEmpty() ? Vec4i.MINUS_ONE : stack.top();
	}
	
	public boolean contains(int x, int y, int width, int height) {
		return stack.isEmpty() || contains(stack.top(), x, y, width, height);
	}
	
	protected boolean contains(Vec4i top, int x, int y, int width, int height) {
		return x >= top.x() && y >= top.y() && x + width < top.z() && y + height < top.w();
	}
	
	public void pop() {
		if(stack.size() <= (withRoot ? 1 : 0)) {
			//TODO implement logging
			return;
		}
		stack.pop();
		if(stack.isEmpty()) {
			handler.disable();
			return;
		}
		Vec4i result = stack.top();
		handler.apply(result.x(), result.y(), result.z() - result.x(), result.w() - result.y());
	}
	
	public void clear() {
		stack.clear();
		withRoot = false;
		handler.disable();
	}
	
	public static interface IScissorsHandler {
		public void enable();
		public void disable();
		public void apply(int x, int y, int width, int height);
	}
	
	public static class NoOp implements IScissorsHandler {
		public static final IScissorsHandler INSTANCE = new NoOp();
		@Override
		public void enable() {}
		@Override
		public void disable() {}
		@Override
		public void apply(int x, int y, int width, int height) {}
		
	}
}
