package speiger.src.coreengine.rendering.guiOld.helper.animations;

import java.util.Iterator;
import java.util.List;
import java.util.function.BiConsumer;

import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.maps.impl.hash.Object2ObjectLinkedOpenHashMap;
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
import speiger.src.coreengine.rendering.guiOld.GuiComponent;
import speiger.src.coreengine.rendering.guiOld.helper.animations.Animation.AnimationListener;

public class Animator
{
	GuiComponent owner;
	List<BiConsumer<GuiComponent, Animator>> listeners = new ObjectArrayList<BiConsumer<GuiComponent, Animator>>();
	float xMod = 0F;
	float yMod = 0F;
	float widthMod = 0F;
	float heightMod = 0F;
	float scaleMod = 1F;
	float visibilityMod = 1F;
	
	
	boolean changed = false;
	boolean redraw = false;
	
	Object2ObjectMap<Animation, AnimationInstance> animations = new Object2ObjectLinkedOpenHashMap<Animation, AnimationInstance>();
	
	public Animator(GuiComponent owner)
	{
		this.owner = owner;
	}
	
	public void addAnimation(Animation animation, boolean reverse, float delay)
	{
		AnimationInstance old = animations.remove(animation);
		animations.put(animation, animation.createInstance(owner, old, delay, reverse));
	}
	
	public boolean isPlayingAnimation(Animation animation)
	{
		return animations.containsKey(animation);
	}
	
	public void update(float particalTicks)
	{
		for(int i = 0,m=listeners.size();i<m;i++)
		{
			listeners.get(i).accept(owner, this);
		}
		if(animations.isEmpty() && !changed)
		{
			return;
		}
		owner.setMassChanging();
		resetValues();
		for(Iterator<Object2ObjectMap.Entry<Animation, AnimationInstance>> iter = Object2ObjectMaps.fastIterator(animations);iter.hasNext();)
		{
			Object2ObjectMap.Entry<Animation, AnimationInstance> animation = iter.next();
			AnimationInstance instance = animation.getValue();
			instance.update(this, particalTicks);
			if(instance.isDone())
			{
				AnimationListener listener = instance.getListener();
				if(listener != null)
				{
					listener.onAnimationFinished(animation.getKey(), owner, instance.isReverse());
				}
				iter.remove();
			}
		}
		applyValues(true);
		if(changed)
		{
			owner.onChanged(redraw);
		}
		owner.finishMassChanging();
	}
	
	private void resetValues()
	{
		if(!changed) return;
		if(!owner.hasConstraints()) owner.changeVisibility(1F / visibilityMod).getBox().move(-xMod, -yMod).resize(-widthMod, -heightMod).scale(1F / scaleMod);
		else owner.changeVisibility(1F / visibilityMod).getBox().scale(1F / scaleMod);
		xMod = 0F;
		yMod = 0F;
		widthMod = 0F;
		heightMod = 0F;
		scaleMod = 1F;
		visibilityMod = 1F;
		changed = false;
		redraw = false;
	}
	
	public void applyValues(boolean internal)
	{
		if(!changed || (internal && owner.hasConstraints()))
		{
			return;
		}
		owner.changeVisibility(visibilityMod).getBox().scale(scaleMod).move(xMod, yMod).resize(widthMod, heightMod);
	}
	
	
	public void modifyX(float value)
	{
		if(value == 0F)
		{
			return;
		}
		xMod += value;
		changed = true;
	}
	
	public void modifyY(float value)
	{
		if(value == 0F)
		{
			return;
		}
		yMod += value;
		changed = true;
	}
	
	public void modifyWidth(float value)
	{
		if(value == 0F)
		{
			return;
		}
		widthMod += value;
		changed = true;
		redraw = true;
	}
	
	public void modifyHeight(float value)
	{
		if(value == 0F)
		{
			return;
		}
		heightMod += value;
		changed = true;
		redraw = true;
	}
	
	public void modifyScale(float value)
	{
		if(value == 1F)
		{
			return;
		}
		scaleMod *= value;
		changed = true;
		redraw = true;
	}
	
	public void modifyVisibility(float value)
	{
		visibilityMod *= value;
		changed = true;
	}
	
}
