package speiger.src.coreengine.ui.gui.animation;

import java.util.List;
import java.util.Map.Entry;

import speiger.src.collections.objects.functions.consumer.ObjectFloatConsumer;
import speiger.src.collections.objects.lists.ObjectArrayList;
import speiger.src.collections.objects.maps.interfaces.Object2ObjectMap;
import speiger.src.collections.objects.utils.maps.Object2ObjectMaps;
import speiger.src.coreengine.ui.gui.animation.GuiAnimation.Target;
import speiger.src.coreengine.ui.gui.component.base.GuiComponent;

public class GuiAnimator implements ObjectFloatConsumer<Target> {	
	protected GuiComponent owner;
	float xDiff = 0F;
	float yDiff = 0F;
	float widthDiff = 0F;
	float heightDiff = 0F;
	float scaleDiff = 1F;
	int changeState = 0;
	Object2ObjectMap<GuiAnimation, GuiAnimationSnapshot> activeAnimations = Object2ObjectMap.builder().linkedMap(); 
	List<GuiAnimation> toDelete = new ObjectArrayList<>();
	
	public GuiAnimator(GuiComponent owner) {
		this.owner = owner;
	}
	
	public void addAnimation(GuiAnimation animation, boolean looping) {
		activeAnimations.put(animation, new GuiAnimationSnapshot(this, owner.getBox(), looping));
	}
	
	public boolean isAnimationPlaying(GuiAnimation animation) {
		return activeAnimations.containsKey(animation);
	}
	
	public int getLoopAmount(GuiAnimation animation) {
		GuiAnimationSnapshot snapshot = activeAnimations.get(animation);
		return snapshot == null ? -1 : snapshot.loops();
	}
	
	public void removeAnimation(GuiAnimation animation) {
		activeAnimations.remove(animation);
	}
	
	private void reset() {
		if(changeState == 0) return;
		owner.getBox().move(-xDiff, -yDiff).resize(-widthDiff, -heightDiff).scale(1F / scaleDiff);
		xDiff = 0F;
		yDiff = 0F;
		widthDiff = 0F;
		heightDiff = 0F;
		scaleDiff = 1F;
		changeState = 0;
	}
	
	public void apply() {
		if(changeState == 0) return;
		owner.getBox().move(xDiff, yDiff).resize(widthDiff, heightDiff).scale(scaleDiff);
	}
	
	public boolean update(float partialTime) {
		reset();
		for(Entry<GuiAnimation, GuiAnimationSnapshot> entry : Object2ObjectMaps.fastIterable(activeAnimations)) {
			GuiAnimation animation = entry.getKey();
			if(entry.getValue().applyDifference(owner).update(animation, partialTime)) {
				toDelete.add(animation);
			}
		}
		if(changeState > 0) {
			owner.onChanged(changeState > 1);
		}
		for(int i = 0,m=toDelete.size();i<m;i++) {
			GuiAnimation animation = toDelete.get(i);
			activeAnimations.remove(animation);
			if(animation.listener() != null) {
				animation.listener().accept(animation, owner);
			}
		}
		return activeAnimations.size() > 0;
	}
	
	@Override
	public void accept(Target k, float v) {
		switch(k) {
			case X -> xDiff += v;
			case Y -> yDiff += v;
			case WIDTH -> widthDiff += v;
			case HEIGHT -> heightDiff += v;
			case SCALE -> scaleDiff *= v;
		}
		changeState |= k.changeState();
	}
}
