package speiger.src.coreengine.rendering.guiOld.components.menu;

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

import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.coreengine.rendering.guiOld.GuiComponent;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.DynamicConstrain;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.MenuConstrain;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.PixelConstrain;

public class MenuComponent extends MenuItemComponent implements Consumer<GuiComponent>
{
	static final int FLAG_OPEN = 1 << 21;
	static final int FLAG_SUB_MENU = 1 << 22;
	List<MenuItemComponent> components = new ObjectArrayList<>();
	float defaultScale = 1F;
	float width = 0F;
	float entryHeight = 10F;
	float textScale = 1F;
	long timeNotHovered = -1;
	MenuComponent ownerMenu;
	
	public MenuComponent(String name)
	{
		super(name);
		clearFlag(FLAG_SUPPORT_BINDING);
	}
	
	public MenuComponent(float x, float y, float width, float height, String name)
	{
		super(x, y, width, height, name);
		clearFlag(FLAG_SUPPORT_BINDING);
	}
	
	@Override
	public boolean canMoveIntoForground()
	{
		return true;
	}
	
	public MenuComponent setHeight(float height)
	{
		entryHeight = height;
		return this;
	}
	
	protected MenuComponent setParent(MenuComponent owner)
	{
		ownerMenu = owner;
		return this;
	}
	
	@Override
	protected void setMenuColor(int color)
	{
		super.setMenuColor(color);
		for(int i = 0,m=components.size();i<m;i++)
		{
			components.get(i).setMenuColor(color);
		}
	}
	
	public MenuComponent setDefaultScale(float scale)
	{
		defaultScale = scale;
		return this;
	}
	
	@Override
	protected void setTextScale(float scale)
	{
		super.setTextScale(scale);
		if(textScale != scale)
		{
			textScale = scale;
			for(int i = 0,m=components.size();i<m;i++)
			{
				components.get(i).setTextScale(textScale);
			}
		}
	}
	
	@Override
	protected void setBoxWidth(float value)
	{
		boolean changed = boxWidth != value;
		super.setBoxWidth(value);
		if(changed)
		{
			for(int i = 0,m=components.size();i<m;i++)
			{
				components.get(i).onChanged(false);
			}
		}
	}
	
	public MenuComponent addSubMenu(String name)
	{
		return addMenuItem(new MenuComponent(name+" >").setIsSubMenu(true).setParent(this)).cast();
	}
	
	public MenuItemComponent addText(String name)
	{
		return addMenuItem(new MenuTextComponent(name)).cast();
	}
	
	public MenuItemComponent addMenuItem(String name)
	{
		return addMenuItem(new MenuItemComponent(name));
	}
	
	public MenuCheckBoxComponent addCheckBox(String name)
	{
		return addMenuItem(new MenuCheckBoxComponent(name)).cast();
	}
	
	public MenuCheckBoxComponent addCheckBox(String name, boolean value)
	{
		return addMenuItem(new MenuCheckBoxComponent(name, value)).cast();
	}
	
	public MenuItemComponent addMenuItem(MenuItemComponent comp)
	{
		components.add(comp);
		comp.setScale(defaultScale);
		comp.setMenuColor(color);
		addChild(comp.setIgnoreBounds(true).onAction(this), createConstrains(comp)).onChanged(false);
		comp.setVisible(isFlagSet(FLAG_OPEN));
		comp.setTextScale(textScale);
		return comp;
	}
	
	protected Constrains createConstrains(MenuItemComponent comp)
	{
		Constrain constraint = isFlagSet(FLAG_SUB_MENU) ? new DynamicConstrain(() -> Math.max(getBox().getBaseWidth(), boxWidth / getBox().getScale())) : new PixelConstrain();
		return new Constrains(constraint, new MenuConstrain<MenuItemComponent>(components, isFlagSet(FLAG_SUB_MENU) ? MenuConstrain.DEFAULT : () -> getBox().getBaseHeight() + 0.1F).setPadding(0.01F), comp.createWidthConstriain(), new PixelConstrain(entryHeight));
	}
	
	@Override
	public GuiComponent removeChild(GuiComponent comp)
	{
		super.removeChild(comp);
		if(components.remove(comp))
		{
			onChanged(false);
		}
		return this;
	}
	
	@Override
	public GuiComponent removeChildren()
	{
		components.clear();
		return super.removeChildren();
	}
	
	public void removeElements()
	{
		for(MenuItemComponent comp : components)
		{
			super.removeChild(comp);
		}
		components.clear();
	}
	
	@Override
	protected boolean updateSelf(int mouseX, int mouseY, float particalTicks)
	{
		if(isSubMenu() && isVisible())
		{
			if(isFlagSet(FLAG_OPEN))
			{
				if(isMouseOver(mouseX, mouseY) || isOverChild(mouseX, mouseY))
				{
					timeNotHovered = -1;
					return true;
				}
				if(timeNotHovered == -1)
				{
					timeNotHovered = getGlobalClock();
				}
				if(getGlobalClock() - timeNotHovered > 10)
				{
					setOpen(false);
				}
				return true;
			}
			timeNotHovered = -1;		
			if(isMouseOver(mouseX, mouseY) && !ownerMenu.hasOtherMenuOpen(this))
			{
				setOpen(true);
			}
		}
		return true;
	}
	
	@Override
	protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
	{
		float brigthness = isFlagSet(FLAG_OPEN) ? 0.7F : getBrightness(mouseX, mouseY);
		float minX = getBox().getMinX(0.2F);
		float minY = getBox().getMinY(0.2F);
		float maxX = Math.max(getBox().getMaxX(), minX + boxWidth);
		float maxY = getBox().getMaxY(-0.2F);
		getRenderer().setBrightness(brigthness).drawQuad(minX, minY, maxX, maxY, color).setBrightness(brigthness * 0.5F).drawFrame(minX, minY, maxX, maxY, color);
		text.setBrightness(brigthness);
		return true;
	}
	
	@Override
	public boolean onClick(int button, int mouseX, int mouseY)
	{
		if(!isSubMenu())
		{
			setOpen(!isFlagSet(FLAG_OPEN)).notifyListeners(LISTENER_USER_ACTION);
		}
		return true;
	}
	
	protected MenuComponent setIsSubMenu(boolean value)
	{
		if(setFlag(FLAG_SUB_MENU, value))
		{
			setFlag(FLAG_KEEP_MENU_OPEN, value);
			for(int i = 0,m=components.size();i<m;i++)
			{
				MenuItemComponent comp = components.get(i);
				addConstrains(comp, createConstrains(comp));
			}
		}
		return this;
	}
	
	public boolean isSubMenu()
	{
		return isFlagSet(FLAG_SUB_MENU);
	}
	
	public MenuComponent setOpen(boolean open)
	{
		if(setFlag(FLAG_OPEN, open))
		{
			width = 0F;
			for(int i = 0,m=components.size();i<m;i++)
			{
				GuiComponent comp = components.get(i);
				comp.setVisible(open);
				width = Math.max(width, comp.getBox().getBaseWidth());
			}
			width *= getBox().getScale();
			width += 1F;
			for(int i = 0,m=components.size();i<m;i++)
			{
				components.get(i).setBoxWidth(width);
			}
			onChanged(false);
		}
		return this;
	}
	
	protected boolean hasOtherMenuOpen(MenuComponent other)
	{
		for(int i = 0,m=components.size();i<m;i++)
		{
			MenuItemComponent comp = components.get(i);
			if(comp != other && comp instanceof MenuComponent && comp.isFlagSet(FLAG_OPEN))
			{
				return true;
			}
		}
		return false;
	}
	
	@Override
	protected void updateState()
	{
		if(isFlagSet(FLAG_OPEN) != isVisible())
		{
			boolean isOpen = isFlagSet(FLAG_OPEN);
			for(int i = 0,m=components.size();i<m;i++)
			{
				components.get(i).setVisible(isOpen);
			}
		}
	}
	
	@Override
	public void onFocusLost()
	{
		if(!isChildFocused())
		{
			setOpen(false);
		}
	}
	
	@Override
	public void accept(GuiComponent t)
	{
		if(t.cast(MenuItemComponent.class).isNotClosingMenu())
		{
			return;
		}
		setOpen(false);
		if(ownerMenu != null)
		{
			ownerMenu.accept(t);
		}
	}

	@Override
	public String toString()
	{
		return "Menu: "+getText().getText();
	}
}
