/*
**	Command & Conquer Generals(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

////////////////////////////////////////////////////////////////////////////////
//																																						//
//  (c) 2001-2003 Electronic Arts Inc.																				//
//																																						//
////////////////////////////////////////////////////////////////////////////////

// FILE: MetaEvent.h ///////////////////////////////////////////////////////////
// Author: Steven Johnson, Dec 2001

#pragma once

#ifndef _H_MetaEvent
#define _H_MetaEvent

#include "Common/SubsystemInterface.h"
#include "GameClient/InGameUI.h"


enum MappableKeyCategories
{
	CATEGORY_CONTROL = 0,
	CATEGORY_INFORMATION,
	CATEGORY_INTERFACE,
	CATEGORY_SELECTION,
	CATEGORY_TAUNT,
	CATEGORY_TEAM,
	CATEGORY_MISC,
	CATEGORY_DEBUG,
	CATEGORY_NUM_CATEGORIES // keep this last
};

static const LookupListRec CategoryListName[] = 
{
	{"CONTROL",						CATEGORY_CONTROL},
	{"INFORMATION",				CATEGORY_INFORMATION},
	{"INTERFACE",					CATEGORY_INTERFACE},
	{"SELECTION",					CATEGORY_SELECTION},
	{"TAUNT",							CATEGORY_TAUNT},
	{"TEAM",							CATEGORY_TEAM},
	{"MISC",							CATEGORY_MISC},
	{"DEBUG",							CATEGORY_DEBUG},
	{NULL, 0}// keep this last
};


// -------------------------------------------------------------------------------
// the keys we allow to be mapped to Meta-events.
// note that this is a subset of all the keys available;
// in particular, "modifier" keys and keypad keys aren't
// available. Note that MappableKeyType is a SUBSET of
// KeyDefType; this is extremely important to maintain!
enum MappableKeyType
{
	MK_ESC					= KEY_ESC,
	MK_BACKSPACE		= KEY_BACKSPACE,
	MK_ENTER				= KEY_ENTER,
	MK_SPACE				= KEY_SPACE,
	MK_TAB					= KEY_TAB,
	MK_F1						= KEY_F1,
	MK_F2						= KEY_F2,
	MK_F3						= KEY_F3,
	MK_F4						= KEY_F4,
	MK_F5						= KEY_F5,
	MK_F6						= KEY_F6,
	MK_F7						= KEY_F7,
	MK_F8						= KEY_F8,
	MK_F9						= KEY_F9,
	MK_F10					= KEY_F10,
	MK_F11					= KEY_F11,
	MK_F12					= KEY_F12,
	MK_A						= KEY_A,
	MK_B						= KEY_B,
	MK_C						= KEY_C,
	MK_D						= KEY_D,
	MK_E						= KEY_E,
	MK_F						= KEY_F,
	MK_G						= KEY_G,
	MK_H						= KEY_H,
	MK_I						= KEY_I,
	MK_J						= KEY_J,
	MK_K						= KEY_K,
	MK_L						= KEY_L,
	MK_M						= KEY_M,
	MK_N						= KEY_N,
	MK_O						= KEY_O,
	MK_P						= KEY_P,
	MK_Q						= KEY_Q,
	MK_R						= KEY_R,
	MK_S						= KEY_S,
	MK_T						= KEY_T,
	MK_U						= KEY_U,
	MK_V						= KEY_V,
	MK_W						= KEY_W,
	MK_X						= KEY_X,
	MK_Y						= KEY_Y,
	MK_Z						= KEY_Z,
	MK_1						= KEY_1,
	MK_2						= KEY_2,
	MK_3						= KEY_3,
	MK_4						= KEY_4,
	MK_5						= KEY_5,
	MK_6						= KEY_6,
	MK_7						= KEY_7,
	MK_8						= KEY_8,
	MK_9						= KEY_9,
	MK_0						= KEY_0,
	MK_KP1					= KEY_KP1,
	MK_KP2					= KEY_KP2,
	MK_KP3					= KEY_KP3,
	MK_KP4					= KEY_KP4,
	MK_KP5					= KEY_KP5,
	MK_KP6					= KEY_KP6,
	MK_KP7					= KEY_KP7,
	MK_KP8					= KEY_KP8,
	MK_KP9					= KEY_KP9,
	MK_KP0					= KEY_KP0,
	MK_MINUS				= KEY_MINUS,
	MK_EQUAL				= KEY_EQUAL,
	MK_LBRACKET			= KEY_LBRACKET,
	MK_RBRACKET			= KEY_RBRACKET,
	MK_SEMICOLON		= KEY_SEMICOLON,
	MK_APOSTROPHE		= KEY_APOSTROPHE,
	MK_TICK					= KEY_TICK,
	MK_BACKSLASH		= KEY_BACKSLASH,
	MK_COMMA				= KEY_COMMA,
	MK_PERIOD				= KEY_PERIOD,
	MK_SLASH				= KEY_SLASH,
	MK_UP						= KEY_UP,
	MK_DOWN					= KEY_DOWN,
	MK_LEFT					= KEY_LEFT,
	MK_RIGHT				= KEY_RIGHT,
	MK_HOME					= KEY_HOME,
	MK_END					= KEY_END,
	MK_PGUP					= KEY_PGUP,
	MK_PGDN					= KEY_PGDN,
	MK_INS					= KEY_INS,
	MK_DEL					= KEY_DEL,
	MK_KPSLASH			= KEY_KPSLASH,
	MK_NONE					= KEY_NONE

};	

static const LookupListRec KeyNames[] = 
{
	{ "KEY_ESC", MK_ESC },
	{ "KEY_BACKSPACE", MK_BACKSPACE },
	{ "KEY_ENTER", MK_ENTER },
	{ "KEY_SPACE", MK_SPACE },
	{ "KEY_TAB", MK_TAB },
	{ "KEY_F1", MK_F1 },
	{ "KEY_F2", MK_F2 },
	{ "KEY_F3", MK_F3 },
	{ "KEY_F4", MK_F4 },
	{ "KEY_F5", MK_F5 },
	{ "KEY_F6", MK_F6 },
	{ "KEY_F7", MK_F7 },
	{ "KEY_F8", MK_F8 },
	{ "KEY_F9", MK_F9 },
	{ "KEY_F10", MK_F10 },
	{ "KEY_F11", MK_F11 },
	{ "KEY_F12", MK_F12 },
	{ "KEY_A", MK_A },
	{ "KEY_B", MK_B },
	{ "KEY_C", MK_C },
	{ "KEY_D", MK_D },
	{ "KEY_E", MK_E },
	{ "KEY_F", MK_F },
	{ "KEY_G", MK_G },
	{ "KEY_H", MK_H },
	{ "KEY_I", MK_I },
	{ "KEY_J", MK_J },
	{ "KEY_K", MK_K },
	{ "KEY_L", MK_L },
	{ "KEY_M", MK_M },
	{ "KEY_N", MK_N },
	{ "KEY_O", MK_O },
	{ "KEY_P", MK_P },
	{ "KEY_Q", MK_Q },
	{ "KEY_R", MK_R },
	{ "KEY_S", MK_S },
	{ "KEY_T", MK_T },
	{ "KEY_U", MK_U },
	{ "KEY_V", MK_V },
	{ "KEY_W", MK_W },
	{ "KEY_X", MK_X },
	{ "KEY_Y", MK_Y },
	{ "KEY_Z", MK_Z },
	{ "KEY_1", MK_1 },
	{ "KEY_2", MK_2 },
	{ "KEY_3", MK_3 },
	{ "KEY_4", MK_4 },
	{ "KEY_5", MK_5 },
	{ "KEY_6", MK_6 },
	{ "KEY_7", MK_7 },
	{ "KEY_8", MK_8 },
	{ "KEY_9", MK_9 },
	{ "KEY_0", MK_0 },
	{ "KEY_KP1", MK_KP1 },
	{ "KEY_KP2", MK_KP2 },
	{ "KEY_KP3", MK_KP3 },
	{ "KEY_KP4", MK_KP4 },
	{ "KEY_KP5", MK_KP5 },
	{ "KEY_KP6", MK_KP6 },
	{ "KEY_KP7", MK_KP7 },
	{ "KEY_KP8", MK_KP8 },
	{ "KEY_KP9", MK_KP9 },
	{ "KEY_KP0", MK_KP0 },
	{ "KEY_MINUS", MK_MINUS },
	{ "KEY_EQUAL", MK_EQUAL },
	{ "KEY_LBRACKET", MK_LBRACKET },
	{ "KEY_RBRACKET", MK_RBRACKET },
	{ "KEY_SEMICOLON", MK_SEMICOLON },
	{ "KEY_APOSTROPHE", MK_APOSTROPHE },
	{ "KEY_TICK", MK_TICK },
	{ "KEY_BACKSLASH", MK_BACKSLASH },
	{ "KEY_COMMA", MK_COMMA },
	{ "KEY_PERIOD", MK_PERIOD },
	{ "KEY_SLASH", MK_SLASH },
	{ "KEY_UP", MK_UP },
	{ "KEY_DOWN", MK_DOWN },
	{ "KEY_LEFT", MK_LEFT },
	{ "KEY_RIGHT", MK_RIGHT },
	{ "KEY_HOME", MK_HOME },
	{ "KEY_END", MK_END },
	{ "KEY_PGUP", MK_PGUP },
	{ "KEY_PGDN", MK_PGDN },
	{ "KEY_INS", MK_INS },
	{ "KEY_DEL", MK_DEL },
	{ "KEY_KPSLASH", MK_KPSLASH },
	{ "KEY_NONE", MK_NONE },
	{ NULL, 0	} // keep this last!
};

// -------------------------------------------------------------------------------
enum MappableKeyTransition
{
	DOWN,
	UP,
	DOUBLEDOWN	// if a key transition is repeated immediately, we generate this.
};

static const LookupListRec TransitionNames[] = 
{
	{ "DOWN",				DOWN },
	{ "UP",					UP },
	{ "DOUBLEDOWN",	DOUBLEDOWN },
	{ NULL, 0	}// keep this last!
};

// -------------------------------------------------------------------------------
// an easier-to-type subset of the KEY_STATE stuff.
enum MappableKeyModState
{
	NONE							= 0,
	CTRL							= KEY_STATE_LCONTROL,
	ALT								= KEY_STATE_LALT,
	SHIFT							= KEY_STATE_LSHIFT,
	CTRL_ALT					= CTRL|ALT,
	SHIFT_CTRL				= SHIFT|CTRL,
	SHIFT_ALT					= SHIFT|ALT,
	SHIFT_ALT_CTRL		= SHIFT|ALT|CTRL
};

static const LookupListRec ModifierNames[] = 
{
	{ "NONE",							NONE },
	{ "CTRL",							CTRL },
	{ "ALT",							ALT },
	{ "SHIFT",						SHIFT },
	{ "CTRL_ALT",					CTRL_ALT },
	{ "SHIFT_CTRL",				SHIFT_CTRL },
	{ "SHIFT_ALT",				SHIFT_ALT },
	{ "SHIFT_ALT_CTRL" ,	SHIFT_ALT_CTRL },
	{ NULL, 0	}// keep this last!
};



// -------------------------------------------------------------------------------
// CommandUsableInType sets in what state the commands are allowed.
enum CommandUsableInType
{
	COMMANDUSABLE_NONE				= 0,

	COMMANDUSABLE_SHELL				= (1 << 0),
	COMMANDUSABLE_GAME				= (1 << 1)
};

static const char* TheCommandUsableInNames[] =
{
	"SHELL",
	"GAME",

	NULL
};

// -------------------------------------------------------------------------------
class MetaMapRec : public MemoryPoolObject
{
	MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(MetaMapRec, "MetaMapRec")		
public:
	MetaMapRec*							m_next;
	GameMessage::Type				m_meta;						///< the meta-event to emit
	MappableKeyType					m_key;						///< the key we want
	MappableKeyTransition		m_transition;			///< the state of the key
	MappableKeyModState			m_modState;				///< the required state of the ctrl-alt-shift keys
	CommandUsableInType			m_usableIn;				///< the allowed place the command can be used in
	// Next fields are added for Key mapping Dialog
	MappableKeyCategories		m_category;				///< This is the catagory the key falls under
	UnicodeString						m_description;		///< The description string for the keys
	UnicodeString						m_displayName;		///< The display name of our command
};
EMPTY_DTOR(MetaMapRec)


//-----------------------------------------------------------------------------
class MetaEventTranslator : public GameMessageTranslator                          
{
private:

	Int						m_lastKeyDown;	// really a MappableKeyType
	Int						m_lastModState;	// really a MappableKeyModState

	enum { NUM_MOUSE_BUTTONS = 3 };
	ICoord2D m_mouseDownPosition[NUM_MOUSE_BUTTONS];
	Bool	m_nextUpShouldCreateDoubleClick[NUM_MOUSE_BUTTONS];

public:
	MetaEventTranslator();
	~MetaEventTranslator();
	virtual GameMessageDisposition translateGameMessage(const GameMessage *msg);
};	

//-----------------------------------------------------------------------------
class MetaMap : public SubsystemInterface
{
	friend class MetaEventTranslator;

private:
	MetaMapRec *m_metaMaps;

protected:
	GameMessage::Type findGameMessageMetaType(const char* name);
	MetaMapRec *getMetaMapRec(GameMessage::Type t);

public:
	
	MetaMap();
	~MetaMap();

	void init() { }
	void reset() { }
	void update() { }

	static void parseMetaMap(INI* ini);
	const MetaMapRec *getFirstMetaMapRec() const { return m_metaMaps; }
};

extern MetaMap *TheMetaMap;

#endif