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

import speiger.src.collections.objects.functions.consumer.ObjectFloatConsumer;
import speiger.src.collections.objects.functions.function.ToFloatFunction;
import speiger.src.coreengine.ui.gui.animation.GuiAnimation.Target;

public interface IAction {
	public float duration();
	public void apply(Target target, ToFloatFunction<Target> getter, ObjectFloatConsumer<Target> setter, float progress);
	public default IAction withPreDelay(float delay) { return this instanceof PreDelayedAction delayed ? new PreDelayedAction(delayed.action(), delay + delayed.delay()) : new PreDelayedAction(this, delay); }
	public default IAction withPostDelay(float delay) { return this instanceof PostDelayedAction delayed ? new PostDelayedAction(delayed.action(), delay + delayed.delay()) : new PostDelayedAction(this, delay); }
	public default IAction reverse() { return this instanceof ReversedAction reversed ? reversed.action() : new ReversedAction(this); }
	public default IAction asLoop() { return this instanceof LoopingAction loop ? loop : new LoopingAction(this); }
	
	public record PreDelayedAction(IAction action, float delay) implements IAction {
		@Override
		public float duration() { return delay + action.duration(); }
		@Override
		public void apply(Target target, ToFloatFunction<Target> getter, ObjectFloatConsumer<Target> setter, float progress) {
			action.apply(target, getter, setter, Math.max(progress - delay, 0F));
		}
	}
	
	public record PostDelayedAction(IAction action, float delay) implements IAction {
		@Override
		public float duration() { return action.duration() + delay; }
		@Override
		public void apply(Target target, ToFloatFunction<Target> getter, ObjectFloatConsumer<Target> setter, float progress) {
			action.apply(target, getter, setter, Math.min(progress, action.duration()));
		}
	}
	
	public record ReversedAction(IAction action) implements IAction {
		@Override
		public float duration() { return action.duration(); }
		@Override
		public void apply(Target target, ToFloatFunction<Target> getter, ObjectFloatConsumer<Target> setter, float progress) {
			action.apply(target, getter, setter, action.duration() - progress);
		}
	}
	
	public record LoopingAction(IAction action) implements IAction {
		@Override
		public float duration() { return action.duration() * 2F; }
		@Override
		public void apply(Target target, ToFloatFunction<Target> getter, ObjectFloatConsumer<Target> setter, float progress) {
			float duration = action.duration();
			action.apply(target, getter, setter, progress >= duration ? duration - (progress - duration) : progress);
		}
	}
}