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

import java.awt.Color;
import java.util.function.Consumer;

import speiger.src.coreengine.math.MathUtils;
import speiger.src.coreengine.math.misc.ColorObject;
import speiger.src.coreengine.math.misc.Facing;
import speiger.src.coreengine.math.vector.floats.Vec2f;
import speiger.src.coreengine.rendering.gui.UITextures;
import speiger.src.coreengine.rendering.gui.components.ButtonComponent;
import speiger.src.coreengine.rendering.gui.components.GradientSliderComponent;
import speiger.src.coreengine.rendering.gui.components.SliderComponent;
import speiger.src.coreengine.rendering.gui.components.TextFieldComponent;
import speiger.src.coreengine.rendering.gui.components.WindowComponent;
import speiger.src.coreengine.rendering.gui.components.icon.IIcon;
import speiger.src.coreengine.rendering.gui.components.icon.TexturedIcon;
import speiger.src.coreengine.rendering.gui.helper.box.GuiBox;
import speiger.src.coreengine.rendering.gui.helper.box.IGuiBox;
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.RelativeConstrain;
import speiger.src.coreengine.utils.functions.Functions;
import speiger.src.coreengine.utils.helpers.InternalThreadPools;

public class ColorPickerWindowComponent extends WindowComponent
{
	Consumer<ColorObject> listener;
	IIcon wheelIcon = new TexturedIcon(UITextures.COLOR_WHEEL);
	IGuiBox wheelBox = new GuiBox(15, 10, 70, 70);
	IGuiBox selectedBox = new GuiBox(5F, 94F, 50F, 10F);
	ColorObject[] colors = new ColorObject[]{ColorObject.rgb(0), ColorObject.rgb(0), ColorObject.rgb(0), ColorObject.rgb(0), ColorObject.rgb(0)};
	SliderComponent brightness = new GradientSliderComponent(95, 13, 17, 76, 0, 100, 0, ColorObject.GRAY, colors[2], colors[3], Facing.NORTH, null).setScrollEffect(-1).setVertical(true);
	SliderComponent saturation = new GradientSliderComponent(110, 13, 17, 76, 0, 100, 0, ColorObject.GRAY, colors[0], colors[1], Facing.NORTH, null).setScrollEffect(-1).setVertical(true);
	TextFieldComponent code = new TextFieldComponent(60, 94, 104, 20, ColorObject.DARK_GRAY).setValidator(Functions.NUMBERS_ONLY).setMaxTextLength(8);
	float[] hsv = new float[3];
	IGuiBox[] colorBoxes;
	ColorPool pool;

	public ColorPickerWindowComponent(float x, float y, ColorPool pool, ColorObject defaultColor, Consumer<ColorObject> listener, String name)
	{
		super(x, y, 125, 140, FIXED_SIZE_POPUP, name);
		this.pool = pool;
		this.listener = listener;
		hsv = defaultColor.toHue();
		colorBoxes = new IGuiBox[Math.min(18, pool.size())];
		for(int i = 0,m=colorBoxes.length;i<m;i++)
		{
			addBox(colorBoxes[i] = new GuiBox(5 + ((i % 9) * 12), 108 + (i >= 9 ? 12 : 0), 10, 10));
		}
	}
	
	@Override
	public void init()
	{
		super.init();
		addBox(wheelBox);
		addBox(selectedBox);
		addChild(brightness.addChangeListener(minimizedListener).addUserActionListener(T -> setColor(hsv[0], hsv[1], T.cast(SliderComponent.class).getValue() * 0.01F)));
		addChild(saturation.addChangeListener(minimizedListener).addUserActionListener(T -> setColor(hsv[0], T.cast(SliderComponent.class).getValue() * 0.01F, hsv[2])));
		addChild(code.setScale(0.5F).addChangeListener(minimizedListener).addUserActionListener(T -> onTyped()));
		addChild(new ButtonComponent(0F, 0F, 0F, 20F, "Select", ColorObject.GREEN).setScale(0.4F).addUserActionListener(T -> apply()), new ComponentConstrains(null, new ParentConstrain(8F).invert(), new RelativeConstrain(0.5F / 0.4F), null));
		addChild(new ButtonComponent(0F, 0F, 0F, 20F, "Cancel", ColorObject.RED).setScale(0.4F).addUserActionListener(T -> T.getGui().removeComponent(this)), new ComponentConstrains(new RelativeConstrain(0.5F), new ParentConstrain(8F).invert(), new RelativeConstrain(0.5F / 0.4F), null));
		setColor(hsv[0], hsv[1], hsv[2]);
	}
	
	@Override
	public boolean isPopup()
	{
		return true;
	}
	
	@Override
	protected boolean renderSelf(int mouseX, int mouseY, float particalTicks)
	{
		super.renderSelf(mouseX, mouseY, particalTicks);
		wheelIcon.render(getRenderer().translate(0F, 0F, 0.01F).setBrightness(hsv[1]), wheelBox);
		getRenderer().setBrightness(1F);
		ColorObject color = new ColorObject(0);
		for(int i = 0,m=colorBoxes.length;i<m;i++)
		{
			IGuiBox box = colorBoxes[i];
			getRenderer().drawQuad(box, color.setRGB(pool.getColor(i))).drawFrame(box, ColorObject.DARK_GRAY);
		}
		getRenderer().drawQuad(selectedBox, colors[4]).drawFrame(selectedBox, ColorObject.DARK_GRAY);
		float centerX = wheelBox.getCenterX();
		float centerY = wheelBox.getCenterY();
		Vec2f pos = InternalThreadPools.VEC2F.get().set(centerX, centerY).add(0F, -(hsv[2] * 33F)).rotate((float)Math.toRadians(-hsv[0] * 360F), centerX, centerY);
		getRenderer().drawQuad(pos.getX() - 1F, pos.getY() - 1F, pos.getX() + 1F, pos.getY() + 1, 0.1F, ColorObject.BLACK);
		InternalThreadPools.VEC2F.accept(pos);
		getRenderer().translate(0F, 0F, -0.01F);
		return true;
	}
	
	private void onTyped()
	{
		try
		{
			int color = Integer.decode(code.getText());
			float[] hsv = Color.RGBtoHSB((color >> 16) & 0xFF, (color >> 8) & 0xFF, color & 0xFF, new float[3]);
			setColor(hsv[0], hsv[1], hsv[2]);
		}
		catch(Exception e){}
	}
	
	public void apply()
	{
		pool.addColor(colors[4].getRGB());
		listener.accept(colors[4]);
		getGui().removeComponent(this);
	}
	
	@Override
	public boolean onClick(int button, int mouseX, int mouseY)
	{
		return wheelBox.isColiding(mouseX, mouseY) ? onChanged(mouseX, mouseY) : super.onClick(button, mouseX, mouseY);
	}
	
	@Override
	public boolean onDrag(int mouseX, int mouseY)
	{
		return super.onDrag(mouseX, mouseY) || (wheelBox.isColiding(mouseX, mouseY) ? onChanged(mouseX, mouseY) : false);
	}
	
	private boolean onChanged(int mouseX, int mouseY)
	{
		Vec2f pos = InternalThreadPools.VEC2F.get().set(mouseX, mouseY);
		float radius = (float)pos.distanceTo(wheelBox.getCenterX(), wheelBox.getCenterY());
		if(radius > 38)
		{
			InternalThreadPools.VEC2F.accept(pos);
			return false;
		}
		float hue = (pos.directionAngle(wheelBox.getCenterX(), wheelBox.getCenterY()) + 180F) % 360F;
		setColor(hue / 360F, hsv[1], radius / 33F);
		InternalThreadPools.VEC2F.accept(pos);
		return true;
	}
	
	protected void setColor(float hue, float saturation, float brightness)
	{
		hsv[0] = MathUtils.clamp(0F, 1F, hue);
		hsv[1] = MathUtils.clamp(0F, 1F, saturation);
		hsv[2] = MathUtils.clamp(0F, 1F, brightness);
		colors[0].setRGB(hsv[0], 0F, 1F, 255);
		colors[1].setRGB(hsv[0], 1F, 1F, 255);
		colors[2].setRGB(hsv[0], 1F, 0F, 255);
		colors[3].setRGB(hsv[0], 1F, 1F, 255);
		colors[4].setRGB(hsv[0], hsv[1], hsv[2], 255);
		code.setText(colors[4].getHTMLCode(false));
		this.brightness.setValue((int)(hsv[2] * 100F));
		this.saturation.setValue((int)(hsv[1] * 100F));
	}
}
