SbTween/Core/TweenSequence.cs
using Sandbox;
using System;
using System.Collections.Generic;

namespace SbTween;

public class TweenSequence
{
	private List<BaseTween> _queue = new();
	private List<TweenSnapshot> _snapshots = new();
	private bool _hasCaptured = false;
	private int _currentIndex = 0;

	public float Delay { get; private set; } = 0;
	private float _delayElapsed = 0;

	public int Loops { get; private set; } = 0;
	private int _loopsDone = 0;

	public bool IsFinished { get; private set; }
	public bool IsPaused { get; private set; } = true;

	public TweenSequence Append( BaseTween tween )
	{
		tween.Pause();
		_queue.Add( tween );
		return this;
	}

	public TweenSequence SetDelay( float seconds ) { Delay = seconds; return this; }
	public TweenSequence SetLoops( int loops ) { Loops = loops; return this; }

	public void Play()
	{
		if ( !_hasCaptured )
		{
			foreach ( var t in _queue )
			{
				if ( t.Target.IsValid() )
				{
					var snp = new TweenSnapshot();
					snp.Capture( t.Target );
					_snapshots.Add( snp );
				}
			}
			_hasCaptured = true;
		}

		IsPaused = false;
		IsFinished = false;
		_currentIndex = 0;
		_loopsDone = 0;
		_delayElapsed = 0;

		TweenManager.Instance.AddSequence( this );
	}

	public void Update()
	{
		if ( IsFinished || IsPaused || _queue.Count == 0 ) return;

		if ( _delayElapsed < Delay )
		{
			_delayElapsed += RealTime.Delta;
			return;
		}

		float dt = RealTime.Delta;

		while ( dt > 0 && _currentIndex < _queue.Count )
		{
			var current = _queue[_currentIndex];
			if ( current.IsPaused ) current.Play();

			float timeNeeded = current.Duration - current.Elapsed;
			float timeToApply = Math.Min( dt, timeNeeded );

			current.Update( timeToApply );
			dt -= timeToApply;

			if ( current.IsFinished )
			{
				_currentIndex++;

				if ( _currentIndex >= _queue.Count )
				{
					if ( Loops == -1 || _loopsDone < Loops )
					{
						_loopsDone++;
						ResetSequence();
						break;
					}
					else
					{
						IsFinished = true;
						break;
					}
				}
			}
		}
	}

	private void ResetSequence()
	{
		_currentIndex = 0;
		_delayElapsed = 0;

		foreach ( var snp in _snapshots )
		{
			snp.Restore();
		}

		foreach ( var t in _queue )
		{
			t.Reset();
		}
	}
}