// [meta] an auxilliary function to the main update loop:

static void	DoUpdates(const UpdateState& u)
// Runs the update functions using the given update state.
{
	// Run UI update.
	UI::Update(u);
	
	// Run object updates (physics & behavior).
	Model::Update(u);
	
	// Run game logic (course timers, etc.)
	Game::Update(u);

	// Deal with network?
}


// [meta] From the main update loop:

	// Update the game logic & physics.
	int	UpdateCount = 20;	// For protection against update functions taking longer than the sampling period.
	UpdateState	u;
	while (UpdatesPending() && UpdateCount-- > 0) {
		GetNextUpdateState(&u);
		DoUpdates(u);
	}
	GetNextUpdateState(&u);
	DoUpdates(u);
	
	// [meta] then does rendering...


// [meta] Here's the code for the input polling thread:


#include <windows.h>	// For input thread stuff.
#include <winbase.h>
#include <process.h>


bool	StopInputsThread = false;
unsigned long	ServiceInputsThread = -1;
void _cdecl	ServiceInputsThreadFunction(void*);


// [meta] during initialization:

		// Start input thread.
		StopInputsThread = false;
		ServiceInputsThread = _beginthread(ServiceInputsThreadFunction, 0, 0);
		if (ServiceInputsThread == -1) {
			Error e; e << "Can't create thread to poll input.";
			throw e;
		}
		
//
// Input polling thread.
//


const int	MIN_SAMPLE_PERIOD = 33;	// ~33 Hz.  Sample at least this often (in ms).


HANDLE	PauseInputThread = NULL;


HANDLE	BufferMutex = NULL;
int	NextSampleTime = 0;
int	LastSampleTime = 0;

const int	SAMPLE_BUFFER_BITS = 4;	// 16-sample buffer.
const int	MAX_SAMPLES = 1 << SAMPLE_BUFFER_BITS;
const int	BUFFER_MASK = MAX_SAMPLES - 1;
UpdateState	Buffer[MAX_SAMPLES];
int	Front = 0;
int	Rear = 0;
int	BufferCount() { return (Front - Rear) & BUFFER_MASK; }


bool	SampleInputsAndAddToBuffer()
// Locks the input buffer, samples the control inputs, and inserts a new UpdateState
// into the buffer.
// Returns false if the buffer is full or it can't acquire a lock on the input buffer.
{
	if (BufferCount() >= 15 || WaitForSingleObject(BufferMutex, 0) == WAIT_FAILED) {
		return false;
	}

	UpdateState*	u = &Buffer[Front];

	// Fill timer values.
	u->Ticks = Timer::GetTicks();
	u->DeltaTicks = u->Ticks - LastSampleTime;
	if (u->DeltaTicks <= 0) u->DeltaTicks = 1;	// Don't allow a 0 time delta.
	if (u->DeltaTicks > 100) u->DeltaTicks = 100;	// Limit max time delta.
	u->DeltaT = u->DeltaTicks / 1000.0;

	// Poll user input.
	Input::GetInputState(&u->Inputs);

	// Remember when we sampled.
	LastSampleTime = u->Ticks;

	// Schedule next sample.
	NextSampleTime = u->Ticks + MIN_SAMPLE_PERIOD;

	// Commit the sample.
	Front = (Front + 1) & BUFFER_MASK;
	
	// Unlock the buffer.
	ReleaseMutex(BufferMutex);

	return true;
}


bool	UpdatesPending()
// Returns true if there are update samples in the queue waiting to be processed.
{
	// Check buffer.
	return BufferCount() > 0;
}


void	GetNextUpdateState(UpdateState* u)
// Returns the next update to be processed.  If the update buffer is empty, then
// polls the control inputs and returns their current values.
{
	// Timeout on this, to be safe?
	while (BufferCount() == 0) {
		SampleInputsAndAddToBuffer();
	}

	*u = Buffer[Rear];	// Copy sampled data.

	Rear = (Rear + 1) & BUFFER_MASK;
}


void _cdecl	ServiceInputsThreadFunction(void* dummy)
// Thread procedure which periodically polls the inputs and the time and puts
// the results in a buffer for retrieval by the main game loop.
{
	BufferMutex = CreateMutex(NULL, FALSE, "input-buffer-mutex");

	while (!StopInputsThread) {
//		wait for PauseInputThread;

		// Sleep while waiting until it's time to collect input.
		int	Ticks = Timer::GetTicks();
		int	SleepTime = NextSampleTime - Ticks;
		if (SleepTime > 0) {
			Sleep(SleepTime);
		}

		// If it's time to collect input, then go for it.
		Ticks = Timer::GetTicks();
		if (Ticks >= NextSampleTime) {
			SampleInputsAndAddToBuffer();	// get inputs, & timestamp, & add to buffer;
		}
	}
}


