// Copyright (c) 2022- PPSSPP Project.

// 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, version 2.0 or later versions.

// 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 2.0 for more details.

// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/

// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.

#pragma once


#pragma pack(push,1)

// Based on https://gist.githubusercontent.com/raw/4140449/PS%20Vita (Might be slightly different with PSP?)
#define SCE_NP_MATCHING2_ERROR_OUT_OF_MEMORY					0x80550c01
#define SCE_NP_MATCHING2_ERROR_ALREADY_INITIALIZED				0x80550c02
#define SCE_NP_MATCHING2_ERROR_NOT_INITIALIZED					0x80550c03
#define SCE_NP_MATCHING2_ERROR_CONTEXT_MAX						0x80550c04 // might be "Invalid Argument" on PSP?
#define SCE_NP_MATCHING2_ERROR_CONTEXT_ALREADY_EXISTS			0x80550c05 // might be "Context Max/Context Id higher than 7" on PSP?
#define SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_FOUND				0x80550c06
#define SCE_NP_MATCHING2_ERROR_CONTEXT_ALREADY_STARTED			0x80550c07
#define SCE_NP_MATCHING2_ERROR_CONTEXT_NOT_STARTED				0x80550c08
#define SCE_NP_MATCHING2_ERROR_SERVER_NOT_FOUND					0x80550c09
#define SCE_NP_MATCHING2_ERROR_INVALID_ARGUMENT					0x80550c0a
#define SCE_NP_MATCHING2_ERROR_INVALID_CONTEXT_ID				0x80550c0b
#define SCE_NP_MATCHING2_ERROR_INVALID_SERVER_ID				0x80550c0c
#define SCE_NP_MATCHING2_ERROR_INVALID_LOBBY_ID					0x80550c0e
#define SCE_NP_MATCHING2_ERROR_INVALID_ROOM_ID					0x80550c0f
#define SCE_NP_MATCHING2_ERROR_INVALID_MEMBER_ID				0x80550c10
#define SCE_NP_MATCHING2_ERROR_INVALID_ATTRIBUTE_ID				0x80550c11
#define SCE_NP_MATCHING2_ERROR_INVALID_CASTTYPE					0x80550c12
#define SCE_NP_MATCHING2_ERROR_INVALID_SORT_METHOD				0x80550c13
#define SCE_NP_MATCHING2_ERROR_INVALID_MAX_SLOT					0x80550c14
#define SCE_NP_MATCHING2_ERROR_INVALID_OPT_SIZE					0x80550c15
#define SCE_NP_MATCHING2_ERROR_INVALID_MATCHING_SPACE			0x80550c16
#define SCE_NP_MATCHING2_ERROR_INVALID_BLOCK_KICK_FLAG			0x80550c18
#define SCE_NP_MATCHING2_ERROR_INVALID_MESSAGE_TARGET			0x80550c19
#define SCE_NP_MATCHING2_ERROR_RANGE_FILTER_MAX					0x80550c1a
#define SCE_NP_MATCHING2_ERROR_INVALID_ALIGNMENT				0x80550c1e
#define SCE_NP_MATCHING2_ERROR_CONNECTION_CLOSED_BY_SERVER		0x80550c22
#define SCE_NP_MATCHING2_ERROR_SSL_VERIFY_FAILED				0x80550c23
#define SCE_NP_MATCHING2_ERROR_SSL_HANDSHAKE					0x80550c24
#define SCE_NP_MATCHING2_ERROR_SSL_SEND							0x80550c25
#define SCE_NP_MATCHING2_ERROR_SSL_RECV							0x80550c26
#define SCE_NP_MATCHING2_ERROR_JOINED_SESSION_MAX				0x80550c27
#define SCE_NP_MATCHING2_ERROR_ALREADY_JOINED					0x80550c28
#define SCE_NP_MATCHING2_ERROR_INVALID_SESSION_TYPE				0x80550c29
#define SCE_NP_MATCHING2_ERROR_NP_SIGNED_OUT					0x80550c2b
#define SCE_NP_MATCHING2_ERROR_BUSY								0x80550c2c
#define SCE_NP_MATCHING2_ERROR_SERVER_NOT_AVAILABLE				0x80550c2d
#define SCE_NP_MATCHING2_ERROR_NOT_ALLOWED						0x80550c2e
#define SCE_NP_MATCHING2_ERROR_ABORTED							0x80550c2f
#define SCE_NP_MATCHING2_ERROR_REQUEST_NOT_FOUND				0x80550c30
#define SCE_NP_MATCHING2_ERROR_SESSION_DESTROYED				0x80550c31
#define SCE_NP_MATCHING2_ERROR_CONTEXT_STOPPED					0x80550c32
#define SCE_NP_MATCHING2_ERROR_INVALID_REQUEST_PARAMETER		0x80550c33
#define SCE_NP_MATCHING2_ERROR_NOT_NP_SIGN_IN					0x80550c34
#define SCE_NP_MATCHING2_ERROR_ROOM_NOT_FOUND					0x80550c35
#define SCE_NP_MATCHING2_ERROR_ROOM_MEMBER_NOT_FOUND			0x80550c36
#define SCE_NP_MATCHING2_ERROR_LOBBY_NOT_FOUND					0x80550c37
#define SCE_NP_MATCHING2_ERROR_LOBBY_MEMBER_NOT_FOUND			0x80550c38
#define SCE_NP_MATCHING2_ERROR_KEEPALIVE_TIMEOUT				0x80550c3a
#define SCE_NP_MATCHING2_ERROR_TIMEOUT_TOO_SHORT				0x80550c3b
#define SCE_NP_MATCHING2_ERROR_TIMEDOUT							0x80550c3c
#define SCE_NP_MATCHING2_ERROR_INVALID_SLOTGROUP				0x80550c3d
#define SCE_NP_MATCHING2_ERROR_INVALID_ATTRIBUTE_SIZE			0x80550c3e
#define SCE_NP_MATCHING2_ERROR_CANNOT_ABORT						0x80550c3f
#define SCE_NP_MATCHING2_ERROR_SESSION_NOT_FOUND				0x80550c40

#define SCE_NP_MATCHING2_SERVER_ERROR_BAD_REQUEST						0x80550d01
#define SCE_NP_MATCHING2_SERVER_ERROR_SERVICE_UNAVAILABLE				0x80550d02
#define SCE_NP_MATCHING2_SERVER_ERROR_BUSY								0x80550d03
#define SCE_NP_MATCHING2_SERVER_ERROR_END_OF_SERVICE					0x80550d04
#define SCE_NP_MATCHING2_SERVER_ERROR_INTERNAL_SERVER_ERROR				0x80550d05
#define SCE_NP_MATCHING2_SERVER_ERROR_PLAYER_BANNED						0x80550d06
#define SCE_NP_MATCHING2_SERVER_ERROR_FORBIDDEN							0x80550d07
#define SCE_NP_MATCHING2_SERVER_ERROR_BLOCKED							0x80550d08
#define SCE_NP_MATCHING2_SERVER_ERROR_UNSUPPORTED_NP_ENV				0x80550d09
#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_TICKET					0x80550d0a
#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_SIGNATURE					0x80550d0b
#define SCE_NP_MATCHING2_SERVER_ERROR_EXPIRED_TICKET					0x80550d0c
#define SCE_NP_MATCHING2_SERVER_ERROR_ENTITLEMENT_REQUIRED				0x80550d0d
#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_CONTEXT					0x80550d0e
#define SCE_NP_MATCHING2_SERVER_ERROR_CLOSED							0x80550d0f
#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_TITLE						0x80550d10
#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_WORLD						0x80550d11
#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_LOBBY						0x80550d12
#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM						0x80550d13
#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_LOBBY_INSTANCE			0x80550d14
#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_ROOM_INSTANCE				0x80550d15
#define SCE_NP_MATCHING2_SERVER_ERROR_PASSWORD_MISMATCH					0x80550d17
#define SCE_NP_MATCHING2_SERVER_ERROR_LOBBY_FULL						0x80550d18
#define SCE_NP_MATCHING2_SERVER_ERROR_ROOM_FULL							0x80550d19
#define SCE_NP_MATCHING2_SERVER_ERROR_GROUP_FULL						0x80550d1b
#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_USER						0x80550d1c
#define SCE_NP_MATCHING2_SERVER_ERROR_TITLE_PASSPHRASE_MISMATCH			0x80550d1e
#define SCE_NP_MATCHING2_SERVER_ERROR_CONSOLE_BANNED					0x80550d28
#define SCE_NP_MATCHING2_SERVER_ERROR_NO_ROOMGROUP						0x80550d29
#define SCE_NP_MATCHING2_SERVER_ERROR_NO_SUCH_GROUP						0x80550d2a
#define SCE_NP_MATCHING2_SERVER_ERROR_NO_PASSWORD						0x80550d2b
#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_GROUP_SLOT_NUM			0x80550d2c
#define SCE_NP_MATCHING2_SERVER_ERROR_INVALID_PASSWORD_SLOT_MASK		0x80550d2d
#define SCE_NP_MATCHING2_SERVER_ERROR_DUPLICATE_GROUP_LABEL				0x80550d2e
#define SCE_NP_MATCHING2_SERVER_ERROR_REQUEST_OVERFLOW					0x80550d2f
#define SCE_NP_MATCHING2_SERVER_ERROR_ALREADY_JOINED					0x80550d30
#define SCE_NP_MATCHING2_SERVER_ERROR_NAT_TYPE_MISMATCH					0x80550d31
#define SCE_NP_MATCHING2_SERVER_ERROR_ROOM_INCONSISTENCY				0x80550d32

#define SCE_NP_MATCHING2_SIGNALING_ERROR_NOT_INITIALIZED				0x80550e01
#define SCE_NP_MATCHING2_SIGNALING_ERROR_ALREADY_INITIALIZED			0x80550e02
#define SCE_NP_MATCHING2_SIGNALING_ERROR_OUT_OF_MEMORY					0x80550e03
#define SCE_NP_MATCHING2_SIGNALING_ERROR_CTXID_NOT_AVAILABLE			0x80550e04
#define SCE_NP_MATCHING2_SIGNALING_ERROR_CTX_NOT_FOUND					0x80550e05
#define SCE_NP_MATCHING2_SIGNALING_ERROR_REQID_NOT_AVAILABLE			0x80550e06
#define SCE_NP_MATCHING2_SIGNALING_ERROR_REQ_NOT_FOUND					0x80550e07
#define SCE_NP_MATCHING2_SIGNALING_ERROR_PARSER_CREATE_FAILED			0x80550e08
#define SCE_NP_MATCHING2_SIGNALING_ERROR_PARSER_FAILED					0x80550e09
#define SCE_NP_MATCHING2_SIGNALING_ERROR_INVALID_NAMESPACE				0x80550e0a
#define SCE_NP_MATCHING2_SIGNALING_ERROR_NETINFO_NOT_AVAILABLE			0x80550e0b
#define SCE_NP_MATCHING2_SIGNALING_ERROR_PEER_NOT_RESPONDING			0x80550e0c
#define SCE_NP_MATCHING2_SIGNALING_ERROR_CONNID_NOT_AVAILABLE			0x80550e0d
#define SCE_NP_MATCHING2_SIGNALING_ERROR_CONN_NOT_FOUND					0x80550e0e
#define SCE_NP_MATCHING2_SIGNALING_ERROR_PEER_UNREACHABLE				0x80550e0f
#define SCE_NP_MATCHING2_SIGNALING_ERROR_TERMINATED_BY_PEER				0x80550e10
#define SCE_NP_MATCHING2_SIGNALING_ERROR_TIMEOUT						0x80550e11
#define SCE_NP_MATCHING2_SIGNALING_ERROR_CTX_MAX						0x80550e12
#define SCE_NP_MATCHING2_SIGNALING_ERROR_RESULT_NOT_FOUND				0x80550e13
#define SCE_NP_MATCHING2_SIGNALING_ERROR_CONN_IN_PROGRESS				0x80550e14
#define SCE_NP_MATCHING2_SIGNALING_ERROR_INVALID_ARGUMENT				0x80550e15
#define SCE_NP_MATCHING2_SIGNALING_ERROR_OWN_NP_ID						0x80550e16
#define SCE_NP_MATCHING2_SIGNALING_ERROR_TOO_MANY_CONN					0x80550e17
#define SCE_NP_MATCHING2_SIGNALING_ERROR_TERMINATED_BY_MYSELF			0x80550e18
#define SCE_NP_MATCHING2_SIGNALING_ERROR_MATCHING2_PEER_NOT_FOUND		0x80550e19

// Based on https://github.com/RPCS3/rpcs3/blob/master/rpcs3/Emu/Cell/Modules/sceNp2.h (Just as reference, might be slightly different than PSP)
// Event of request functions
enum PS3Matching2RequestEvent
{
	SCE_NP_MATCHING2_REQUEST_EVENT_GetServerInfo					= 0x0001,
	SCE_NP_MATCHING2_REQUEST_EVENT_GetWorldInfoList					= 0x0002,
	SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomMemberDataExternalList	= 0x0003,
	SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataExternal				= 0x0004,
	SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataExternalList			= 0x0005,
	SCE_NP_MATCHING2_REQUEST_EVENT_GetLobbyInfoList					= 0x0006,
	SCE_NP_MATCHING2_REQUEST_EVENT_SetUserInfo						= 0x0007,
	SCE_NP_MATCHING2_REQUEST_EVENT_GetUserInfoList					= 0x0008,
	SCE_NP_MATCHING2_REQUEST_EVENT_CreateServerContext				= 0x0009,
	SCE_NP_MATCHING2_REQUEST_EVENT_DeleteServerContext				= 0x000a,
	SCE_NP_MATCHING2_REQUEST_EVENT_CreateJoinRoom					= 0x0101,
	SCE_NP_MATCHING2_REQUEST_EVENT_JoinRoom							= 0x0102,
	SCE_NP_MATCHING2_REQUEST_EVENT_LeaveRoom						= 0x0103,
	SCE_NP_MATCHING2_REQUEST_EVENT_GrantRoomOwner					= 0x0104,
	SCE_NP_MATCHING2_REQUEST_EVENT_KickoutRoomMember				= 0x0105,
	SCE_NP_MATCHING2_REQUEST_EVENT_SearchRoom						= 0x0106,
	SCE_NP_MATCHING2_REQUEST_EVENT_SendRoomChatMessage				= 0x0107,
	SCE_NP_MATCHING2_REQUEST_EVENT_SendRoomMessage					= 0x0108,
	SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomDataInternal				= 0x0109,
	SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomDataInternal				= 0x010a,
	SCE_NP_MATCHING2_REQUEST_EVENT_SetRoomMemberDataInternal		= 0x010b,
	SCE_NP_MATCHING2_REQUEST_EVENT_GetRoomMemberDataInternal		= 0x010c,
	SCE_NP_MATCHING2_REQUEST_EVENT_SetSignalingOptParam				= 0x010d,
	SCE_NP_MATCHING2_REQUEST_EVENT_JoinLobby						= 0x0201,
	SCE_NP_MATCHING2_REQUEST_EVENT_LeaveLobby						= 0x0202,
	SCE_NP_MATCHING2_REQUEST_EVENT_SendLobbyChatMessage				= 0x0203,
	SCE_NP_MATCHING2_REQUEST_EVENT_SendLobbyInvitation				= 0x0204,
	SCE_NP_MATCHING2_REQUEST_EVENT_SetLobbyMemberDataInternal		= 0x0205,
	SCE_NP_MATCHING2_REQUEST_EVENT_GetLobbyMemberDataInternal		= 0x0206,
	SCE_NP_MATCHING2_REQUEST_EVENT_GetLobbyMemberDataInternalList	= 0x0207,
	SCE_NP_MATCHING2_REQUEST_EVENT_SignalingGetPingInfo				= 0x0e01,
};

// Based on decompiled np_matching2.prx, commented with syscalls where the event id is being used
#define PSP_NP_MATCHING2_EVENT_0001	0x0001	// GetServerInfo
#define PSP_NP_MATCHING2_EVENT_0002	0x0002	// GetWorldInfoList
#define PSP_NP_MATCHING2_EVENT_0003	0x0003	// SetUserInfo
#define PSP_NP_MATCHING2_EVENT_0004	0x0004	// GetUserInfoList
#define PSP_NP_MATCHING2_EVENT_0005	0x0005	// GetRoomMemberDataExternalList
#define PSP_NP_MATCHING2_EVENT_0006	0x0006	// SetRoomDataExternal
#define PSP_NP_MATCHING2_EVENT_0007	0x0007	// GetRoomDataExternalList

#define PSP_NP_MATCHING2_EVENT_0101	0x0101	// CreateJoinRoom
#define PSP_NP_MATCHING2_EVENT_0102	0x0102	// JoinRoom
#define PSP_NP_MATCHING2_EVENT_0103	0x0103	// LeaveRoom
#define PSP_NP_MATCHING2_EVENT_0104	0x0104	// GrantRoomOwner
#define PSP_NP_MATCHING2_EVENT_0105	0x0105	// KickoutRoomMember
#define PSP_NP_MATCHING2_EVENT_0106	0x0106	// SearchRoom
#define PSP_NP_MATCHING2_EVENT_0107	0x0107	// SendRoomChatMessage
#define PSP_NP_MATCHING2_EVENT_0108	0x0108	// SendRoomMessage, also used on various places (internal function)
#define PSP_NP_MATCHING2_EVENT_0109	0x0109	// SetRoomDataInternal
#define PSP_NP_MATCHING2_EVENT_010A	0x010A	// GetRoomDataInternal
#define PSP_NP_MATCHING2_EVENT_010B	0x010B	// SetRoomMemberDataInternal
#define PSP_NP_MATCHING2_EVENT_010C	0x010C	// GetRoomMemberDataInternal
#define PSP_NP_MATCHING2_EVENT_010D	0x010D	// GetRoomMemberDataInternalList
#define PSP_NP_MATCHING2_EVENT_010E	0x010E	// SetSignalingOptParam

#define PSP_NP_MATCHING2_EVENT_A102	0xA102	// Used on various places (internal function)

// Either this is an ID, state/status, flags, or might be size of data?
#define PSP_NP_MATCHING2_STATE_1001	0x1001
#define PSP_NP_MATCHING2_STATE_1006	0x1006
#define PSP_NP_MATCHING2_STATE_1007	0x1007
#define PSP_NP_MATCHING2_STATE_1008	0x1008

#define PSP_NP_MATCHING2_STATE_1200	0x1200
#define PSP_NP_MATCHING2_STATE_1206	0x1206
#define PSP_NP_MATCHING2_STATE_1207	0x1207
#define PSP_NP_MATCHING2_STATE_1208	0x1208
#define PSP_NP_MATCHING2_STATE_1209	0x1209
#define PSP_NP_MATCHING2_STATE_120B	0x120B
#define PSP_NP_MATCHING2_STATE_120C	0x120C

#define PSP_NP_MATCHING2_STATE_3202	0x3202
#define PSP_NP_MATCHING2_STATE_3203	0x3203
#define PSP_NP_MATCHING2_STATE_3204	0x3204
#define PSP_NP_MATCHING2_STATE_3205	0x3205
#define PSP_NP_MATCHING2_STATE_3206	0x3206
#define PSP_NP_MATCHING2_STATE_3207	0x3207
#define PSP_NP_MATCHING2_STATE_3208	0x3208
#define PSP_NP_MATCHING2_STATE_320A	0x320A
#define PSP_NP_MATCHING2_STATE_3210	0x3210
#define PSP_NP_MATCHING2_STATE_3211	0x3211

#define PSP_NP_MATCHING2_MAX_CONTEXTID	7;

struct NpMatching2Handler {
	u32 entryPoint;
	u32 argument;
};

// Arg1 and Arg2 seems to be a pair and predefined: 0x0001 with 0x1001, 0x0002 with 0x1008, 0x0003 with 0x1006, 0x0004 with 0x1007, 
//		0x0005 with 0x1206, 0x0006 with 0x1207, 0x0007 with 0x1208, 0x0101 with 0x1209, 0x0102 with 0x1209, 0x0103 with 0x3202,
//		0x0104 with 0x3210, 0x0105 with 0x3211, 0x0106 with 2 possibilities (0x1200 and 0x120c), 0x0107 with 0x3208, 0x0108 with 0x320a,
//		0x0109 with 0x3204, 0x010a with 0x3205, 0x010b with 0x3206, 0x010c with 0x3207, 0x010d with 0x3203, 0x010e with 0x3204,
//		0xa102 with 0x120b.
// Arg5 seems to be boolean (0/1), mostly 0, conditional when Arg1=0x0001
// Arg7 seems to be integer/state? (0..2), mostly 0, conditional when Arg1=0x0108 (0 on SendRoomMessage, 2 on others), 1 when Arg1=0xa102
struct NpMatching2Args {
	u32_le data[11]; // 7 elements (excluding optional data)? or may be 11 elements (including optional data)?
	// May be followed by optional data? since these Args usually created on the stack
};

#pragma pack(pop)

extern std::recursive_mutex npMatching2EvtMtx;

bool NpMatching2ProcessEvents();

void Register_sceNpMatching2();
