package tim.prune.function.autoplay;

/**
 * Class to hold a list of points and hold a running position
 */
public class PointList
{
	/** Array of milliseconds for each point */
	private long[] _millis = null;
	/** Array of indexes of corresponding points */
	private int[]  _indexes = null;
	/** Max array index */
	private final int _maxItem;
	/** Array index of current position */
	private int _currentItem = 0;

	/**
	 * Constructor
	 * @param inNumPoints number of points
	 */
	public PointList(int inNumPoints)
	{
		_millis = new long[inNumPoints];
		_indexes = new int[inNumPoints];
		_currentItem = 0;
		_maxItem = inNumPoints - 1;
	}

	/**
	 * Add a point to the array
	 * @param inMillis milliseconds since start
	 * @param inIndex point index
	 */
	public void setPoint(long inMillis, int inIndex)
	{
		_millis[_currentItem] = inMillis;
		_indexes[_currentItem] = inIndex;
		_currentItem++;
	}

	/**
	 * Set the position using the current milliseconds
	 * @param inMillis milliseconds since start
	 */
	public void set(long inMillis)
	{
		if (isFinished() || inMillis < _millis[_currentItem])
		{
			// must be reset
			_currentItem = 0;
		}
		while (_currentItem < _maxItem && _millis[_currentItem + 1] < inMillis)
		{
			_currentItem++;
		}
	}

	/**
	 * Normalize the list to cover the requested number of seconds duration
	 * @param inSeconds length of autoplay sequence in seconds
	 */
	public void normalize(int inSeconds)
	{
		if (_maxItem <= 0)
		{
			return; // nothing to normalize
		}
		long currentDuration = _millis[_maxItem] - _millis[0];
		if (currentDuration > 0L)
		{
			double multFactor = inSeconds * 1000.0 / currentDuration;
			for (int i=0; i<=_maxItem; i++)
			{
				_millis[i] = (long) (_millis[i] * multFactor);
			}
		}
	}

	/** @return the milliseconds of the current point */
	public long getCurrentMilliseconds()
	{
		if (isAtStart() || isFinished()) {
			return 0L;
		}
		return _millis[_currentItem];
	}

	/** @return the index of the current point */
	public int getCurrentPointIndex()
	{
		return _indexes[_currentItem];
	}

	/** @return true if we're on the first point */
	public boolean isAtStart() {
		return _currentItem == 0;
	}

	/** @return true if we're on the last point */
	public boolean isFinished() {
		return _currentItem >= _maxItem;
	}

	/**
	 * @param inCurrentMillis current time in milliseconds since start
	 * @return number of milliseconds to wait until next point is due
	 */
	public long getMillisUntilNextPoint(long inCurrentMillis)
	{
		if (isFinished() || _millis[_currentItem+1] < _millis[_currentItem]) {
			return 0; // no next point
		}
		return _millis[_currentItem+1] - inCurrentMillis;
	}
}
