#include <string.h>

#include "types.h"
#include "keyboard.h"
#include "d_event.h"
#include "d_gui.h"
#include "i_system.h"
#include "duke3d.h"

#define KEYBUFFER_SIZE	128

event_t events[MAXEVENTS];
int eventhead;
int eventtail;

responder_p Responders[MAX_RESPONDERS];
int ResponderPriorities[MAX_RESPONDERS];

//==========================================================================
//
// D_ProcessEvents
//
// Send all the events of the given timestamp down the responder chain.
// Events are asynchronous inputs generally generated by the game user.
// Events can be discarded if no responder claims them
//
//==========================================================================

void D_ProcessEvents (void)
{
	event_t *ev;
		
	// [RH] If testing mode, do not accept input until test is over
#if 0
	if (testingmode)
	{
		if (testingmode == 1)
		{
			M_SetDefaultMode ();
		}
		else if (testingmode <= I_GetTime())
		{
			M_RestoreMode ();
		}
		return;
	}
#endif

	for (; eventtail != eventhead ; eventtail = (++eventtail)&(MAXEVENTS-1))
	{
		ev = &events[eventtail];

		for (int i = 0; i < MAX_RESPONDERS; ++i)
		{
			if (Responders[i] == NULL || Responders[i](ev))
			{
				break;
			}
		}
	}
}

//==========================================================================
//
// D_PostEvent
//
// Called by the I/O functions when input is detected.
//
//==========================================================================

void D_PostEvent (const event_t *ev)
{
	events[eventhead] = *ev;
	eventhead = (++eventhead)&(MAXEVENTS-1);
}

// Lower priority responders get executed first
void D_AddResponder (responder_p responder, int priority)
{
	for (int i = 0; i < MAX_RESPONDERS; ++i)
	{
		if (Responders[i] == responder)
		{
			break;
		}
		else if (Responders[i] == NULL || ResponderPriorities[i] > priority)
		{
			if (Responders[i] != NULL && i < MAX_RESPONDERS-1)
			{
				memmove (&Responders[i+1], &Responders[i], sizeof(responder_p)*(MAX_RESPONDERS-i-1));
				memmove (&ResponderPriorities[i+1], &ResponderPriorities[i], sizeof(int)*(MAX_RESPONDERS-i-1));
			}
			Responders[i] = responder;
			ResponderPriorities[i] = priority;
			break;
		}
	}
}

void D_RemoveResponder (responder_p responder)
{
	for (int i = 0; i < MAX_RESPONDERS; ++i)
	{
		if (Responders[i] == responder)
		{
			if (i < MAX_RESPONDERS-1)
			{
				memmove (&Responders[i], &Responders[i+1], sizeof(responder_p)*(MAX_RESPONDERS-i-1));
				memmove (&ResponderPriorities[i], &ResponderPriorities[i+1], sizeof(int)*(MAX_RESPONDERS-i-1));
			}
			Responders[MAX_RESPONDERS-1] = NULL;
			ResponderPriorities[MAX_RESPONDERS-1] = 0;
			break;
		}
	}
}
