#pragma once

#include "l4rio.h"
#include "l4padbindings.h"

//########################################################################
//############################### PadRIO #################################
//########################################################################
//
// A cockpit-less RIO: synthesizes the RIOBase control surface from an
// XInput controller and the PC keyboard. Selected with L4CONTROLS=PAD.
//
// Every input is REBINDABLE: bindings.txt beside the exe (vRIO's
// profile format, written with the full default layout on first run)
// maps keys and pad controls to RIO button addresses (0x00-0x47), the
// pilot/external keypads (0x50-0x6F, delivered as arcade KeyEvents;
// unbound by default - the game never reads them), and the five axes
// with deflect/rate semantics. Defaults: vRIO's complete board layout
// (number+letter rows = MFD banks, F-keys = secondary columns) with
// flight on the numpad - 8/2/4/6 stick, 7/9 pedals, 0 trigger - and
// the modifiers: Shift/Ctrl throttle up/down, Alt reverse thrust,
// Space trigger, arrows hat.
//
// Set L4PADFLIP to a string containing 'X' and/or 'Y' to invert the
// stick axes on top of whatever the profile produces.
//
class PadRIO :
	public RIOBase
{
public:
	PadRIO();
	~PadRIO();

	Logical
		TestInstance() const;

	Logical
		GetNextEvent(RIOEvent *destinationPointer);

	void
		RequestAnalogUpdate();

	void
		GeneralReset();
	void
		ResetThrottle();

	void
		SetLamp(int lampNumber, int state);

	// Lamp state the game has commanded, indexed by RIO lamp number.
	// The on-screen cockpit buttons read this to light themselves.
	enum { lampCount = 64 };
	unsigned char
		lampState[lampCount];

	//---------------------------------------------------------------
	// On-screen cockpit buttons (MFDSplitView strips) press RIO units
	// through these; they are no-ops when no PadRIO is active (e.g.
	// real serial hardware selected).
	//---------------------------------------------------------------
	static void
		SetScreenButton(int unit, Logical pressed);
	static int
		GetLampState(int unit);
	static Logical
		IsActive()
			{ return activeInstance != NULL; }

protected:
	void
		PollInputs();
	void
		QueueEvent(const RIOEvent &an_event);

	enum { queueSize = 64 };
	enum { buttonUnits = 0x48 };	// through LastMappableButton

	RIOEvent
		eventQueue[queueSize];
	int
		queueHead, queueTail;

	static PadRIO
		*activeInstance;

	// pressed state driven by the on-screen cockpit buttons
	unsigned char
		screenButton[0x48];

	unsigned long
		lastPollTick,
		lastPadCheckTick;
	int
		padIndex;			// connected XInput slot, -1 = none
	Logical
		padReported;		// one-time connect/disconnect log flags
	Logical
		analogRequested;

	unsigned char
		buttonDown[buttonUnits];

	// keypad pressed-state (0x50-0x6F), for KeyEvent edges
	enum { keypadUnits = 0x20 };
	unsigned char
		keypadDown[keypadUnits];

	PadBindingProfile
		profile;

	Scalar
		throttleAccum;
	Logical
		invertX, invertY;
	Logical
		keyLightActive;		// Dynamic Lighting keyboard mirror running

	Scalar
		sentThrottle, sentLeftPedal, sentRightPedal,
		sentJoystickX, sentJoystickY;
};
