package speiger.src.coreengine.rendering.inputOld.window;

import java.util.List;
import java.util.Objects;

import org.lwjgl.glfw.GLFW;
import org.lwjgl.system.Callback;

import speiger.src.collections.longs.maps.interfaces.Long2ObjectMap;
import speiger.src.collections.objects.lists.ObjectArrayList;

public class WindowProvider
{
	Long2ObjectMap<Monitor> monitors;
	List<Callback> callbacks = new ObjectArrayList<>();
	List<Window> activeWindows = new ObjectArrayList<>();
	
	public void init() {
		monitors = Monitor.createMonitors();
		callbacks.add(GLFW.glfwSetMonitorCallback(this::onMonitorChange));
	}
	
	protected void onMonitorChange(long id, int state) {
		switch(state) {
			case GLFW.GLFW_CONNECTED:
				monitors.put(id, new Monitor(id));
				break;
			case GLFW.GLFW_DISCONNECTED:
				monitors.remove(state);
				break;
		}
	}
	
	public WindowStats createBuilder() {
		return new WindowStats(this);
	}
	
	public Monitor getMonitors(long id) {
		return monitors.get(id);
	}
	
	public Window getWindowFromId(long id) {
		for(Window window : activeWindows) {
			if(window.getId() == id) return window;
		}
		return null;
	}
	
	public List<Window> getActiveWindows() {
		return activeWindows;
	}
	
	public Monitor getMonitorFromWindow(Window window) {
		Monitor monitor = null;
		long overlap = Long.MIN_VALUE;
		for(Monitor entry : monitors.values()) {
			long thisOverlap = entry.getInBounds(window);
			if(thisOverlap > overlap) {
				monitor = entry;
				overlap = thisOverlap;
			}
		}
		return monitor == null ? monitors.get(GLFW.glfwGetPrimaryMonitor()) : monitor;
	}
	
	public List<Monitor> getMonitors() {
		return new ObjectArrayList<>(monitors.values());
	}
	
	public void destroy() {
		callbacks.forEach(Callback::free);
		callbacks.clear();
		GLFW.glfwTerminate();
		GLFW.glfwSetErrorCallback(null).free();
	}
	
	public void updateWindows() {
		activeWindows.forEach(Window::update);
	}
	
	public void finishFrame() {
		activeWindows.forEach(Window::finishFrame);
	}
	
	public static class WindowStats {
		WindowProvider provider;
		String name = "";
		int width;
		int height;
		int antiAlis;
		boolean vsync;
		boolean fpsCap;
		boolean fullScreen;
		boolean floating;
		boolean borderless;
		boolean center = true;
		Window parent;
		VideoMode videoMode;
		
		WindowStats(WindowProvider provider) {
			this.provider = provider;
			videoMode = provider.monitors.get(GLFW.glfwGetPrimaryMonitor()).getDefaultMode();
		}
		
		public WindowStats setName(String name) {
			this.name = Objects.requireNonNull(name);
			return this;
		}
		
		public WindowStats setWidth(int width) {
			this.width = Math.max(1, width);
			return this;
		}
		
		public WindowStats setHeight(int height) {
			this.height = Math.max(1, height);
			return this;
		}
		
		public WindowStats setAntiAlis(int antiAlis) {
			this.antiAlis = Math.max(1, antiAlis);
			return this;
		}
		
		public WindowStats setSubWindow(Window parent) {
			this.parent = parent;
			return this;
		}
		
		public WindowStats setFullScreen(boolean fullScreen) {
			this.fullScreen = fullScreen;
			borderless &= !fullScreen;
			floating &= !fullScreen;
			return this;
		}
		
		public WindowStats setBorderless(boolean borderless) {
			this.borderless = borderless;
			fullScreen &= !borderless;
			return this;
		}
		
		public WindowStats setFloating(boolean floating) {
			this.floating = floating;
			fullScreen &= !floating;
			return this;
		}
		
		public WindowStats setCentered(boolean center) {
			this.center = center;
			return this;
		}
		
		public WindowStats setMonitor(VideoMode videoMode) {
			if(videoMode != null && videoMode.monitor() != null) {
				this.videoMode = videoMode;
			}
			return this;
		}
		
		public WindowStats setVsync(boolean value) {
			vsync = value;
			return this;
		}
		
		public WindowStats setFPSCap(boolean cap) {
			fpsCap = cap;
			return this;
		}
		
		public Window build() {
			Window window = new Window().createWindow(this);
			provider.activeWindows.add(window);
			return window;
		}
	}
}
