package speiger.src.coreengine.rendering.gui.components.window.debug;

import java.util.function.ObjIntConsumer;

import speiger.src.collections.ints.queues.IntArrayFIFOQueue;
import speiger.src.collections.ints.queues.IntPriorityQueue;
import speiger.src.collections.ints.utils.IntPriorityQueues;
import speiger.src.coreengine.math.misc.ColorObject;
import speiger.src.coreengine.math.vector.floats.Vec2f;
import speiger.src.coreengine.rendering.gui.GuiManager;
import speiger.src.coreengine.rendering.gui.components.ButtonComponent;
import speiger.src.coreengine.rendering.gui.components.TreeComponent;
import speiger.src.coreengine.rendering.gui.components.WindowComponent;
import speiger.src.coreengine.rendering.gui.components.tree.ProfilerTreeEntry;
import speiger.src.coreengine.rendering.gui.helper.constrains.ComponentConstrains;
import speiger.src.coreengine.rendering.gui.helper.constrains.ParentConstrain;
import speiger.src.coreengine.rendering.gui.helper.constrains.PixelConstrain;
import speiger.src.coreengine.rendering.gui.helper.constrains.RelativeConstrain;
import speiger.src.coreengine.utils.profiler.IProfiler;
import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry;

public class TreeProfilerWindowComponent extends WindowComponent
{
	IntPriorityQueue todoList = IntPriorityQueues.synchronize(new IntArrayFIFOQueue());
	TreeComponent<ProfilerTreeEntry> tree = new TreeComponent<ProfilerTreeEntry>(ColorObject.GRAY, 9F).disableBackground(true).setSelectionMode(TreeComponent.SELECTION_MODE_INTERACT);
	ButtonComponent[] buttons = new ButtonComponent[3];
	ObjIntConsumer<IProfiler> listener = (T, V) -> todoList.enqueue(V);
	IProfiler profiler;
	String root;
	
	public TreeProfilerWindowComponent(float x, float y, float width, float height, String name)
	{
		super(x, y, width, height, DEFAULT_FLAGS, name);
	}
	
	@Override
	public boolean canMoveIntoForground()
	{
		return true;
	}
	
	@Override
	public void init()
	{
		super.init();
		addChild(tree.addChangeListener(minimizedListener), new ComponentConstrains(new PixelConstrain(2F), new PixelConstrain(getMinimizedY()), new ParentConstrain(1.5F), new PixelConstrain(getMinimizedY() + 8.5F).setInverted()));
		buttons[0] = createButton(0, "Client");
		buttons[1] = createButton(1, "GPU");
		buttons[2] = createButton(2, "Server");
	}
	
	@Override
	protected boolean fixedUpdateSelf()
	{
		while(!todoList.isEmpty())
		{
			int index = todoList.dequeue();
			switch(index)
			{
				case 0:
					addEntries(profiler.getEntry(root));
					break;
				case 1:
					tree.setTree(null);
					break;
				case 2:
					if(tree.getTree() == null)
					{
						addEntries(profiler.getEntry(root));
						break;
					}
					updateChildren(profiler.getEntry(root), tree.getTree());
					tree.onTreeChanged();
					break;
			}
		}
		return true;
	}
	
	public TreeProfilerWindowComponent setProfiler(IProfiler profiler, String root)
	{
		if(this.profiler != null)
		{
			buttons[getProfilerIndex(this.profiler)].setEnabled(true);
			this.profiler.removeListener(listener);
			this.profiler.disable();
			tree.setTree(null);
		}
		this.profiler = profiler;
		this.root = root;
		if(this.profiler != null)
		{
			buttons[getProfilerIndex(this.profiler)].setEnabled(false);
			this.profiler.enable();
			this.profiler.addListener(listener);
			addEntries(this.profiler.getEntry(this.root));
		}
		return this;
	}
	
	protected void addEntries(IProfilerEntry entry)
	{
		if(entry == null)
		{
			return;
		}
		ProfilerTreeEntry child = new ProfilerTreeEntry(entry);
		for(int i = 0,m=entry.getChildCount();i<m;i++)
		{
			addChildren(entry.getChild(i), child);
		}
		tree.setTree(child);
		tree.openAll();
	}
	
	protected void updateChildren(IProfilerEntry entry, ProfilerTreeEntry tree)
	{
		if(entry == null || tree == null)
		{
			return;
		}
		for(int i = 0,m=entry.getChildCount();i<m;i++)
		{
			addChildren(entry.getChild(i), tree);
		}
	}
	
	protected void addChildren(IProfilerEntry entry, ProfilerTreeEntry tree)
	{
		if(entry == null || tree == null)
		{
			return;
		}
		ProfilerTreeEntry child = new ProfilerTreeEntry(entry);
		int index = tree.indexOf(child);
		if(index != -1)
		{
			child = (ProfilerTreeEntry)tree.getChild(index);
		}
		else
		{
			tree.addChild(child);
		}
		for(int i = 0,m=entry.getChildCount();i<m;i++)
		{
			addChildren(entry.getChild(i), child);
		}
	}
	
	public IProfiler getProfiler(int index)
	{
		GuiManager manager = getGui().getUIManager();
		switch(index)
		{
			case 1:
				return manager.getGPUProfiler();
			case 2:
				return manager.getServerProfiler();
			default:
				return manager.getCPUProfiler();
		}
	}
	
	public int getProfilerIndex(IProfiler prof)
	{
		GuiManager manager = getGui().getUIManager();
		return manager.getGPUProfiler() == prof ? 1 : manager.getServerProfiler() == prof ? 2 : 0;
	}
	
	protected ButtonComponent createButton(int index, String name)
	{
		ButtonComponent button = new ButtonComponent(name, ColorObject.GRAY);
		button.getText().setTextScale(0.3F);
		button.addChangeListener(minimizedListener).addUserActionListener(T -> setProfiler(getProfiler(index), PieProfilerWindowComponent.getRoot(index)));
		addChild(button, new ComponentConstrains(new RelativeConstrain(index * 0.3333F), new PixelConstrain(8F).setInverted(), new RelativeConstrain(0.3333F), new PixelConstrain(7F)));
		return button;
	}
	
	@Override
	public Vec2f getMinimumBounds()
	{
		return Vec2f.newVec(100F, 50F);
	}
}
