#include "RenderCadenceClock.h"

#include <algorithm>

RenderCadenceClock::RenderCadenceClock(double frameDurationMilliseconds)
{
	mFrameDuration = std::chrono::duration_cast<Duration>(std::chrono::duration<double, std::milli>(frameDurationMilliseconds));
	if (mFrameDuration <= Duration::zero())
		mFrameDuration = std::chrono::milliseconds(16);
	Reset();
}

void RenderCadenceClock::Reset(TimePoint now)
{
	mNextRenderTime = now;
	mPendingFrameAdvance = 1;
	mOverrunCount = 0;
	mSkippedFrameCount = 0;
}

RenderCadenceClock::Tick RenderCadenceClock::Poll(TimePoint now)
{
	Tick tick;
	if (now < mNextRenderTime)
	{
		tick.sleepFor = std::min(Duration(std::chrono::milliseconds(1)), mNextRenderTime - now);
		return tick;
	}

	tick.due = true;
	mPendingFrameAdvance = 1;
	const Duration lateBy = now - mNextRenderTime;
	if (lateBy > mFrameDuration)
	{
		tick.skippedFrames = static_cast<uint64_t>(lateBy / mFrameDuration);
		mPendingFrameAdvance += tick.skippedFrames;
		++mOverrunCount;
		mSkippedFrameCount += tick.skippedFrames;
	}
	return tick;
}

void RenderCadenceClock::MarkRendered(TimePoint now)
{
	mNextRenderTime += mFrameDuration * mPendingFrameAdvance;
	mPendingFrameAdvance = 1;
	if (now - mNextRenderTime > mFrameDuration * 4)
		mNextRenderTime = now + mFrameDuration;
}
