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

import java.util.List;
import java.util.function.Consumer;
import java.util.function.ObjIntConsumer;

import speiger.src.collections.ints.queues.IntArrayFIFOQueue;
import speiger.src.collections.ints.queues.IntPriorityQueue;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.math.color.ColorUtils;
import speiger.src.coreengine.math.misc.Facing;
import speiger.src.coreengine.math.vector.floats.Vec2f;
import speiger.src.coreengine.rendering.guiOld.components.SingleTabPanelComponent;
import speiger.src.coreengine.rendering.guiOld.components.TreeComponent;
import speiger.src.coreengine.rendering.guiOld.components.WindowComponent;
import speiger.src.coreengine.rendering.guiOld.components.tree.ProfilerTreeEntry;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
import speiger.src.coreengine.utils.profiler.IProfiler;
import speiger.src.coreengine.utils.profiler.IProfiler.IProfilerEntry;

public class TreeProfilerWindow extends WindowComponent
{
	IntPriorityQueue todoList = new IntArrayFIFOQueue().synchronizeQueue();
	ObjIntConsumer<IProfiler> listener = (_, V) -> todoList.enqueue(V);
	SingleTabPanelComponent panel = new SingleTabPanelComponent(Facing.SOUTH).onAction(this::onProfilerChanged).cast();
	TreeComponent<ProfilerTreeEntry> tree = panel.addChild(new TreeComponent<>(ColorUtils.GRAY, 9F).disableBackground(true).setSelectionMode(TreeComponent.SELECTION_MODE_INTERACT).cast(), Constrains.parent(Target.WIDTH).parent(4, Target.HEIGHT).build());
	List<ProfilerTab> tabs = new ObjectArrayList<>();
	int previouseTab = -1;
	
	
	public TreeProfilerWindow(float x, float y, float width, float height, String name)
	{
		super(x, y, width, height, DEFAULT_FLAGS, name);
	}
	
	public TreeProfilerWindow addProfiler(IProfiler profiler, String root)
	{
		panel.addTab(profiler.getName());
		tabs.add(new ProfilerTab(profiler, root));
		if(tabs.size() == 1)
		{
			onProfilerChanged();
		}
		return this;
	}
	
	@Override
	public boolean canMoveIntoForground()
	{
		return true;
	}
	
	@Override
	public Vec2f getMinimumBounds()
	{
		return Vec2f.of(100F, 50F);
	}
	
	@Override
	public void init()
	{
		super.init();
		addChild(panel.set(0F, 7.5F).onChange(minimizedListener), Constrains.parent(0.25F, Target.WIDTH).parent(4F, Target.HEIGHT).build());
	}
	
	@Override
	public void onClosed()
	{
		super.onClosed();
		applyProfiler(false, this::disable);
	}
	
	@Override
	protected boolean fixedUpdateSelf()
	{
		ProfilerTab entry = getActiveTab();
		if(entry == null)
		{
			todoList.clear();
			return true;
		}
		while(!todoList.isEmpty())
		{
			int index = todoList.dequeue();
			switch(index)
			{
				case 0:
					addEntries(entry.getRootEntry());
					break;
				case 1:
					tree.setTree(null);
					break;
				case 2:
					if(tree.getTree() == null)
					{
						addEntries(entry.getRootEntry());
						break;
					}
					updateChildren(entry.getRootEntry(), tree.getTree());
					tree.onTreeChanged();
					break;
			}
		}
		return true;
	}
	
	protected void onProfilerChanged()
	{
		if(previouseTab == panel.getActiveIndex()) return;
		applyProfiler(true, this::disable);
		applyProfiler(false, this::enable);
		previouseTab = panel.getActiveIndex();
		ProfilerTab tab = tabs.get(previouseTab);
		setCurrentEntry(tab.getRoot());
	}
	
	protected void enable(IProfiler profiler)
	{
		profiler.enable();
		profiler.addListener(listener);
	}
	
	protected void disable(IProfiler profiler)
	{
		profiler.removeListener(listener);
		profiler.disable();
	}
	
	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();
	}
	
	public TreeProfilerWindow setCurrentEntry(String name)
	{
		addEntries(getActive().getEntry(name));
		return this;
	}
	
	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);
		}
	}
	
	protected IProfiler getActive()
	{
		return tabs.get(panel.getActiveIndex()).getProfiler();
	}
	
	protected ProfilerTab getActiveTab() 
	{
		int index = panel.getActiveIndex();
		return index < 0 || index >= tabs.size() ? null : tabs.get(index);
	}
	
	protected void applyProfiler(boolean prev, Consumer<IProfiler> action)
	{
		int index = prev ? previouseTab : panel.getActiveIndex();
		if(index >= 0) action.accept(tabs.get(index).getProfiler());
	}
	
	private static class ProfilerTab
	{
		IProfiler profiler;
		String root;
		
		public ProfilerTab(IProfiler profiler, String root)
		{
			this.profiler = profiler;
			this.root = root;
		}
		
		public IProfiler getProfiler()
		{
			return profiler;
		}
		
		public String getRoot()
		{
			return root;
		}
		
		public IProfilerEntry getRootEntry()
		{
			return profiler.getEntry(root);
		}
		
	}
}
