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

import java.util.Collection;
import java.util.function.Consumer;

import org.lwjgl.opengl.GL11;

import speiger.src.collections.ints.collections.IntCollection;
import speiger.src.coreengine.math.value.IValue;
import speiger.src.coreengine.math.value.LiniarValue;
import speiger.src.coreengine.rendering.guiOld.GuiComponent;
import speiger.src.coreengine.rendering.guiOld.base.IButtonComponent;
import speiger.src.coreengine.rendering.guiOld.components.list.SelectionEntry;
import speiger.src.coreengine.rendering.guiOld.helper.Align;
import speiger.src.coreengine.rendering.guiOld.helper.box.IGuiBox;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrain.Target;
import speiger.src.coreengine.rendering.guiOld.helper.constrains.Constrains;
import speiger.src.coreengine.rendering.guiOld.renderer.UIRenderer;
import speiger.src.coreengine.rendering.guiOld.renderer.buffer.RenderBuffer;
import speiger.src.coreengine.rendering.tesselationOld.Tesselator;
import speiger.src.coreengine.rendering.tesselationOld.VertexType;

public class SelectionComponent extends GuiComponent implements IButtonComponent, Consumer<GuiComponent>
{
	public static final int FLAG_ANIMATE = 1 << 20;
	ListComponent<SelectionEntry> list = new ListComponent<SelectionEntry>().bounds(0F, 120F).setManualRenderer(true).setIgnoreBounds(true).cast();
	TextComponent text = new TextComponent().align(Align.LEFT_TOP, Align.CENTER).setTextScale(0.85F).setManualRenderer(true).cast();
	RenderBuffer buffer;
	int color;
	boolean isOpen = false;
	int selectedIndex = -1;
	int defaultIndex = -1;
	IValue animation = null;
	
	public SelectionComponent(int color)
	{
		super(0F, 0F, 0F, 0F);
		this.color = color;
		text.setText("Select Index");
		list.setColor(color);
	}
	
	public SelectionComponent(int color, Collection<String> collection)
	{
		super(0F, 0F, 0F, 0F);
		this.color = color;
		text.setText("Select Index");
		list.setColor(color);
		addEntries(collection);
	}
	
	public SelectionComponent(float x, float y, float width, float height, int color)
	{
		super(x, y, width, height);
		this.color = color;
		text.setText("Select Index");
		list.setColor(color);
	}
	
	public SelectionComponent(float x, float y, float width, float height, int color, Collection<String> collection)
	{
		super(x, y, width, height);
		this.color = color;
		text.setText("Select Index");
		list.setColor(color);
		addEntries(collection);
	}
	
	@Override
	public void init()
	{
		list.setEntryHeight(getGui().getFont().height()).onAction(this);
		addChild(text, Constrains.parent(21F, 0F, 10.5F, 0F));
		addChild(list, Constrains.parent(Target.X).invParent(Target.Y).parent(Target.WIDTH).build());
		onClose(buffer = getRenderer().createBuffer());
		createArrow();
	}
	
	public final SelectionComponent setAnimating(boolean value)
	{
		setFlag(FLAG_ANIMATE, value);
		return this;
	}
	
	public final boolean isAnimating()
	{
		return isFlagSet(FLAG_ANIMATE);
	}
	
	@Override
	protected void updateState()
	{
		list.setVisible(isOpen);
	}
	
	public TextComponent getText()
	{
		return text;
	}
	
	public ListComponent<SelectionEntry> getList()
	{
		return list;
	}
	
	public SelectionComponent addEntry(String s)
	{
		list.add(new SelectionEntry(s));
		return this;
	}
	
	public SelectionComponent addEntries(Collection<String> collection)
	{
		for(String s : collection)
		{
			list.add(new SelectionEntry(s));
		}
		return this;
	}
	
	public SelectionComponent updateEntry(int index, String newName)
	{
		list.get(index).setText(newName);
		if(index == selectedIndex)
		{
			updateSelection();
		}
		return this;
	}
	
	public SelectionComponent removeEntry(String s)
	{
		for(int i = 0,m=list.size();i<m;i++)
		{
			if(list.get(i).getText().equals(s))
			{
				list.remove(i);
				if(selectedIndex == i)
				{
					updateSelection();
				}
				return this;
			}
		}
		return this;
	}
	
	public SelectionComponent removeIndex(int index)
	{
		if(list.remove(index) != null && selectedIndex == index)
		{
			updateSelection();
		}
		return this;
	}
	
	public SelectionComponent removeIndexes(IntCollection values)
	{
		if(list.removeAll(values) && values.contains(selectedIndex))
		{
			updateSelection();
		}
		return this;
	}
	
	public SelectionComponent setDefaultIndex(int index)
	{
		defaultIndex = index;
		if(index != -1 && selectedIndex == -1)
		{
			list.setSelectedIndex(index);
			updateSelection();
		}
		return this;
	}
	
	public SelectionComponent setSelectedIndex(int index)
	{
		list.setSelectedIndex(index);
		updateSelection();
		return this;
	}
	
	public int getSelectedIndex()
	{
		return selectedIndex;
	}
	
	public String getSelectedValue()
	{
		return list.get(selectedIndex).getText();
	}
	
	protected void createArrow()
	{
		if(buffer == null)
		{
			return;
		}
		buffer.clear();
		Tesselator tes = buffer.start(GL11.GL_TRIANGLES, VertexType.UI).setOffset(-6F, -6F, 0F);
		tes.pos(0F, 0F, 0F).tex(0F, 0F).color4f(color).endVertex();
		tes.pos(6F, 0F, 0F).tex(0F, 0F).color4f(color).endVertex();
		tes.pos(0F, 12F, 0F).tex(0F, 0F).color4f(color).endVertex();
		tes.pos(0F, 12F, 0F).tex(0F, 0F).color4f(color).endVertex();
		tes.pos(6F, 0F, 0F).tex(0F, 0F).color4f(color).endVertex();
	    tes.pos(6F, 12F, 0F).tex(0F, 0F).color4f(color).endVertex();
	    tes.pos(6F, 0F, 0F).tex(0F, 0F).color4f(color).endVertex();
	    tes.pos(6F, 12F, 0F).tex(0F, 0F).color4f(color).endVertex();
	    tes.pos(12F, 6F, 0F).tex(0F, 0F).color4f(color).endVertex();
		tes.setOffset(0F, 0F, 0F);
		buffer.finishShape(0);
	}
	
	@Override
	protected boolean updateSelf(int mouseX, int mouseY, float particalTicks)
	{
		if(animation != null)
		{
			animation.update(particalTicks);
			if(animation.isDone())
			{
				if(animation.get() < 1F)
				{
					isOpen = false;
					list.setVisible(false);
				}
				animation = null;
			}
		}
		return true;
	}
	
	@Override
	protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
	{
		float brightness = getActiveBrightness();
		IGuiBox box = getBox();
		float minX = box.getMinX(10F);
		float minY = box.getMinY(10F);
		float currentZ = getRenderer().getCurrentZ();
		float rotation = animation != null ? animation.get() : (isOpen ? 90 : 0);
		UIRenderer render = getRenderer();
		render.setBrightness(brightness).drawQuad(box, color);
		render.setBrightness(brightness * 0.7F).drawQuad(box.getMinX(), box.getMinY(), box.getMinX(20F), box.getMaxY(), 0.001F, color);
		render.setFastTransform(false).setBrightness(brightness).translate(minX, minY, 0.02F + currentZ);
		render.scale(box.getScale()).rotateZ(rotation).drawBuffers(buffer, 0, 0).resetTransform().setFastTransform(true).translate(0F, 0F, 0.01F).setBrightness(1F);
		text.render(mouseX, mouseY, particalTicks);
		if(animation != null)
		{
			float progress = animation.get() / 90F;
			box = list.getBox();
			enableScissors(box.getMinX(), box.getMinY(), box.getWidth(), box.getHeight() * progress);
			list.render(mouseX, mouseY, particalTicks);
			disableScissors();
		}
		else if(isOpen)
		{
			list.render(mouseX, mouseY, particalTicks);
		}
		return true;
	}

	@Override
	public boolean isComponentColliding(int mouseX, int mouseY)
	{
		return isMouseOver(mouseX, mouseY) || (isOpen && list.isComponentColliding(mouseX, mouseY));
	}
	
	@Override
	public boolean isValidButton(int button)
	{
		return button == 0 || button == 2;
	}
	
	@Override
	public boolean onClick(int button, int mouseX, int mouseY)
	{
		//TODO look how to move into OnRelease
		if(isOpen && button == 0)
		{
			if(isMouseOver(mouseX, mouseY) && animation == null)
			{
				close();
			}
			return animation == null && list.onClick(button, mouseX, mouseY);
		}
		if(button == 2)
		{
			list.setSelectedIndex(-1);
			updateSelection();
			return true;
		}
		isOpen = true;
		list.setVisible(true);
		if(isAnimating())
		{
			animation = new LiniarValue(2F, 0F, 90F).setSmooth();
		}
		return true;
	}

	@Override
	public boolean onDrag(int mouseX, int mouseY)
	{
		return isOpen && animation == null && list.onDrag(mouseX, mouseY);
	}

	@Override
	public void onRelease(int button, int mouseX, int mouseY)
	{
		if(isOpen && animation == null)
		{
			list.onRelease(button, mouseX, mouseY);
		}
	}

	@Override
	public boolean onScroll(int scroll, int mouseX, int mouseY)
	{
		return isOpen && animation == null && list.onScroll(scroll, mouseX, mouseY);
	}
	
	protected void close()
	{
		if(isAnimating())
		{
			animation = new LiniarValue(2F, 90F, 0F).setSmooth();			
		}
		else
		{
			isOpen = false;
			list.setVisible(false);
		}
	}
	
	@Override
	public void accept(GuiComponent t)
	{
		updateSelection();
		close();
	}
	
	protected void updateSelection()
	{
		if(list.hasSelected())
		{
			selectedIndex = list.getSelectedIndex();
			text.setText(list.get(selectedIndex).getText());
		}
		else if(defaultIndex != -1)
		{
			list.setSelectedIndex(defaultIndex);
			selectedIndex = list.getSelectedIndex();
			text.setText(list.get(selectedIndex).getText());
		}
		else
		{
			selectedIndex = -1;
			text.setText("Select Index");
		}
	}
}
