// 
// rline/rlpc.h 
// 
// Copyright (C) 1999-2013 Rockstar Games.  All Rights Reserved. 
// 

#ifndef RLINE_RLPC_H
#define RLINE_RLPC_H

#include "file/file_config.h"

#if RSG_PC

#include "system/new.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/rgsc_common.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/rgsc_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/achievements_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/players_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/presence_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/profiles_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/commerce_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/delegate_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/cloudsave_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/configuration_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/gamerpics_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/pad_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/titleid_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/file_system_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/tasks_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/rgsc_ui_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/activation_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/patching_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/telemetry_interface.h"
#include "../../../suite/src/rgsc/rgsc/rgsc/public_interface/network_interface.h"

#include "atl/delegate.h"
#include "data/autoid.h"
#include "input/pad.h"
#include "net/relay.h"
#include "data/certificateverify.h"

#include "rline/scpresence/rlscpresencemessage.h"
#include "rline/rlpcpipe.h"
//#include "system/epic.h"

#if !__RGSC_DLL
#include "input/virtualkeyboard.h"
#endif

namespace rage
{

bool RockstarCertificateVerification(CertificateDetails & detail);

class rlGamerHandle;
class rlScPresenceMessageSender;

enum ePcEventType
{   
	RLPC_EVENT_SIGN_IN_STATE_CHANGED,
	RLPC_EVENT_ROS_TICKET_CHANGED,
	RLPC_EVENT_FRIEND_STATUS_CHANGED,
	RLPC_EVENT_SOCIAL_CLUB_MESSAGE,
	RLPC_EVENT_GAME_INVITE_ACCEPTED,
	RLPC_EVENT_JOINED_VIA_PRESENCE,
	RLPC_EVENT_CLOUD_SAVES_ENABLED_UPDATED
};

#define RLPC_EVENT_COMMON_DECL( name )\
	static unsigned EVENT_ID() { return name::GetAutoId(); }\
	virtual unsigned GetId() const { return name::GetAutoId(); }

#define RLPC_EVENT_DECL( name, id )\
	AUTOID_DECL_ID( name, rage::rlPcEvent, id )\
	RLPC_EVENT_COMMON_DECL( name )

class rlPcEvent
{
public:
	AUTOID_DECL_ROOT(rlPcEvent);

	RLPC_EVENT_COMMON_DECL(rlPcEvent);

	rlPcEvent() {}
	virtual ~rlPcEvent() {}
};

class rlPcEventSignInStateChanged : public rlPcEvent
{
public:
	RLPC_EVENT_DECL(rlPcEventSignInStateChanged, RLPC_EVENT_SIGN_IN_STATE_CHANGED);

	explicit rlPcEventSignInStateChanged(const rgsc::SignInStateFlags state)
		: m_State(state)
	{
	}

	rgsc::SignInStateFlags m_State;
};

class rlPcEventRosTicketChanged : public rlPcEvent
{
public:
	RLPC_EVENT_DECL(rlPcEventRosTicketChanged, RLPC_EVENT_ROS_TICKET_CHANGED);

	explicit rlPcEventRosTicketChanged(const char* xml)
		: m_Xml(xml)
	{
	}

	const char* m_Xml;
};

class rlPcEventFriendStatusChanged : public rlPcEvent
{
public:
	RLPC_EVENT_DECL(rlPcEventFriendStatusChanged, RLPC_EVENT_FRIEND_STATUS_CHANGED);

	rlPcEventFriendStatusChanged()
	{
	}
};

class rlPcEventSocialClubMessage : public rlPcEvent
{
public:
	RLPC_EVENT_DECL(rlPcEventSocialClubMessage, RLPC_EVENT_SOCIAL_CLUB_MESSAGE);

	explicit rlPcEventSocialClubMessage(const rlScPresenceMessage* scMsg, const rlScPresenceMessageSender* sender)
		: m_ScMsg(scMsg)
		, m_Sender(sender)
	{
	}

	const rlScPresenceMessage* m_ScMsg;
	const rlScPresenceMessageSender* m_Sender;
};

class rlPcEventGameInviteAccepted : public rlPcEvent
{
public:
	RLPC_EVENT_DECL(rlPcEventGameInviteAccepted, RLPC_EVENT_GAME_INVITE_ACCEPTED);

	explicit rlPcEventGameInviteAccepted(const rlScPresenceMessage* scMsg, const rlScPresenceMessageSender* sender)
	{
        m_ScMsg = scMsg;
		m_Sender = sender;
	}

	const rlScPresenceMessage* m_ScMsg;
	const rlScPresenceMessageSender* m_Sender;
};

class rlPcEventJoinedViaPresence : public rlPcEvent
{
public:
	RLPC_EVENT_DECL(rlPcEventJoinedViaPresence, RLPC_EVENT_JOINED_VIA_PRESENCE);

	explicit rlPcEventJoinedViaPresence(const rlScPresenceMessage* scMsg, const rlScPresenceMessageSender* sender)
	{
        m_ScMsg = scMsg;
		m_Sender = sender;
	}

	const rlScPresenceMessage* m_ScMsg;
	const rlScPresenceMessageSender* m_Sender;
};

class rlPcEventCloudSavesEnabledUpdate : public rlPcEvent
{
public:
	RLPC_EVENT_DECL(rlPcEventCloudSavesEnabledUpdate, RLPC_EVENT_CLOUD_SAVES_ENABLED_UPDATED);

	explicit rlPcEventCloudSavesEnabledUpdate(const char* rosTitleName)
		: m_RosTitleName(rosTitleName)
	{
	}

	const char* m_RosTitleName;
};

typedef atDelegator<void (class rlPc*, const class rlPcEvent*)> rlPcEventDelegator;
typedef rlPcEventDelegator::Delegate rlPcEventDelegate;

/* This class presents the interface to the external PC Platform DLL.
   It acts as the glue that binds Rage to the DLL and vice versa.
*/
class rlPc
{
	friend class RgscDelegate;
public:

	enum InitErrorCodes
	{
		SC_INIT_ERR_NONE = 0,
		SC_INIT_ERR_NO_DLL = 1,
		SC_INIT_ERR_NO_SC_COMMAND_LINE = 2,
		SC_INIT_ERR_PROGRAM_FILES_NOT_FOUND = 3,
		SC_INIT_ERR_LOAD_LIBRARY_FAILED = 4,
		SC_INIT_ERR_GET_PROC_ADDRESS_FAILED = 5,
		SC_INIT_ERR_CALL_EXPORTED_FUNC_FAILED = 6,
		SC_INIT_ERR_QUERY_INTERFACE_FAILED = 7,
		SC_INIT_ERR_UNKNOWN_ENV = 8,
		SC_INIT_ERR_INIT_CALL_FAILED = 9,
		SC_INIT_ERR_GET_SUBSYSTEM_FAILED = 10,
		SC_INIT_ERR_RGSC_NULL_AFTER_LOAD = 11,
		SC_INIT_ERR_CREATE_DEVICE_DX11 = 12,
		SC_INIT_ERR_CREATE_DEVICE_DX9 = 13,
		SC_INIT_ERR_NULL_PIPE = 14,
		SC_INIT_ERR_PIPE_CONNECT_FAILED = 15,
		SC_INIT_ERR_SIGNATURE_VERIFICATION_FAILED = 16,
		SC_INIT_ERR_WEBSITE_FAILED_LOAD = 17,
	};

    rlPc();
    ~rlPc();

    bool Init();
    void Shutdown();
    void Update();

	//PURPOSE
	//  Add/remove a delegate that will be called with event notifications.
	void AddDelegate(rlPcEventDelegate* dlgt);
	void RemoveDelegate(rlPcEventDelegate* dlgt);
	void DispatchEvent(const rlPcEvent* e);

	bool IsInitialized();

	rgsc::IRgscV10* GetRgscInterface();
	rgsc::IAchievementManagerV3* GetAchievementManager();
	rgsc::IPlayerManagerV2* GetPlayerManager();
	rgsc::IPresenceManagerV4* GetPresenceManager();
	rgsc::ICommerceManagerV4* GetCommerceManager();
	rgsc::IProfileManagerV2* GetProfileManager();
	rgsc::IGamepadManagerV3* GetGamepadManager();
	rgsc::IFileSystemV3* GetFileSystem();
	rgsc::IRgscUiV7* GetUiInterface();
	rgsc::IActivationV2* GetActivationInterface();
	rgsc::IPatchingV1* GetPatchingInterface();
	rgsc::ITaskManagerV1* GetTaskManager();
	rgsc::ITelemetryV3* GetTelemetry();
	rgsc::INetworkV1* GetNetworkInterface();
	rgsc::ICloudSaveManagerV3* GetCloudSaveManager();
	rgsc::IGamerPicManagerV1* GetGamerPicManager();

	//PURPOSE
	//  Show the main UI / landing page.
	bool ShowUi();

	//PURPOSE
	//  Show the sign-in UI.
	bool ShowSigninUi();

	//PURPOSE
	//  Shows the gamer profile UI (gamer card).
	//PARAMS
	//  target - Gamer handle of gamer who's profile will be shown.
	bool ShowGamerProfileUi(const rlGamerHandle& target);

	//PURPOSE
	//  Shows the commerce UI.
	//PARAMS
	//  url - url to the store's page to navigate to
	bool ShowCommerceUi(const char* url);	

	//PURPOSE
	//  Returns true if a system UI is showing.
	bool IsUiShowing() const;

	//PURPOSE
	//  Returns true if the UI is loaded and ready to accept commands.
	bool IsUiAcceptingCommands();

	// PURPOSE
	//	Returns true if the SCUI quit game button has been pressed
	bool HasUserRequestedShutdownViaScui();
	void SetUserRequestedShutdownViaScui(bool bShutdownRequested);

	bool ConnectDownloaderPipe(const char * pipeName);
	rlPCPipe* GetDownloaderPipe() { return m_PCPipe; }

	//PURPOSE
	//  Error codes to help debug startup issues.
	void SetInitErrorCode(int errorCode);
	int GetInitErrorCode() {return m_InitializationErrorCode;}

	const char* GetSocialClubVersion();

	//PURPOSE
	// Retrieves the presence message sender information if available.
	void GetPresenceMessageSender(rgsc::IPresenceMessage* msg, rlScPresenceMessageSender* sender);

	// PURPOSE
	//	Returns TRUE if the specified revision is the Social Club version.
	bool IsSocialClubVersion(int major, int minor, int build, int revision);

	// PURPOSE
	//	Returns TRUE if the specified revision is at least the Social Club version.
	bool IsAtLeastSocialClubVersion(int major, int minor, int build, int revision);

	// PURPOSE
	//	Called when a SCUI text box gains focus
	void SetTextBoxHasFocus(const bool hasFocus, const char* prompt, const char* text, const bool isPassword, const unsigned int maxNumChars);

	// PURPOSE
	// Called when we need to refresh the Steam Auth Token
	void RefreshSteamAuthTicket(bool bNotifyRgsc);
	u32 GetSteamAuthTicketLength();
	const char* GetSteamAuthTicket();

	// PURPOSE
	// Returns the additional session info attribute in use by the title for secondary game sessions (i.e. trinfo in GTAV)
	// Takes in a char ptr so we can potentially expand to a delimited list in future titles that may use more than 2 sessions
	const char* GetAdditionalSessionAttr() { return m_AdditionalSessionAttr; }
	void SetAdditionalSessionAttr(const char* attr) { safecpy(m_AdditionalSessionAttr, attr); }

	// PURPOSE
	// Returns the additional session join attribute in use by the title for secondary game sessions (i.e. trjoin in GTAV)
	// Takes in a char ptr so we can potentially expand to a delimited list in future titles that may use more than 2 sessions
	const char* GetAdditionalJoinAttr() { return m_AdditionalJoinAttr; }
	void SetAdditionalJoinAttr(const char* attr) { safecpy(m_AdditionalJoinAttr, attr); }

	// PURPOSE
	// Get/Set the Metadata file path
	const char* GetMetaDataPath() { return m_MetaDataPath; }
	void SetMetaDataPath(const char* path) { safecpy(m_MetaDataPath, path); }

	// PURPOSE
	//	Handler for entitlement events
	void HandleEntitlementEvent(const char* json);

	// PURPOSE
	//	Returns the number of virtual SCUI gamepads.
	unsigned GetNumScuiPads() const;

	// PURPOSE
	//	Returns a pointer to a virtual SCUI gamepad at the requested index.
	//	Returns nullptr if invalid or out of range.
	rgsc::RgscGamepad* GetScuiPad(const unsigned index) const;

#if !__FINAL
	void SimluateDeviceLost();
	void SimluateDeviceReset();
#endif

private:
	rlPcEventDelegator m_Delegator;

	int m_SocialClubVersionNum[4];
	char m_SocialClubVersion[32];
	bool m_bHasScuiRequestedQuit;

	rgsc::IRgscV10* m_Rgsc;
	rgsc::IProfileManagerV2* m_ProfileManager;
	rgsc::IGamepadManagerV3* m_GamepadManager;
	rgsc::IAchievementManagerV3* m_AchievementManager;
	rgsc::IPlayerManagerV2* m_PlayerManager;
	rgsc::IPresenceManagerV4* m_PresenceManager;
	rgsc::ICommerceManagerV4* m_CommerceManager;
	rgsc::IActivationV2* m_ActivationSystem;
	rgsc::IPatchingV1* m_PatchingSystem;
	rgsc::IFileSystemV3* m_FileSystem;
	rgsc::IRgscUiV7* m_RgscUi;
	rgsc::ITaskManagerV1* m_TaskManager;
	rgsc::ITelemetryV3* m_Telemetry;
	rgsc::INetworkV1* m_NetworkInterface;
	rgsc::ICloudSaveManagerV3* m_CloudSaveManager;
	rgsc::IGamerPicManagerV1* m_GamerPicManager;

	HMODULE m_hRgscDll;

	// IPC communication with the game's launcher
	rlPCPipe* m_PCPipe;

	// Virtual Gamepads
	rgsc::RgscGamepad* m_ScuiPads[ioPad::MAX_PADS];
	unsigned m_NumScuiPads;

	// listens for events from the relay server
	void OnRelayEvent(const netRelayEvent& event);

	// registered with netRelay to listen for events.
	netRelay::Delegate m_RelayDelegate;

//#if EPIC_API_SUPPORTED
//	sysEpicEventDelegator::Delegate m_EpicDelegate;
//	void OnEpicEvent(sysEpic*, const sysEpicEvent*);
//#endif

	int m_InitializationErrorCode;
	bool m_WaitingForKeyboardResult;
	unsigned m_KeyboardCompleteTime;

#if !__RGSC_DLL
	ioVirtualKeyboard m_ScuiVirtualKeyboard;
#endif

#if __STEAM_BUILD
	static char sm_SteamAuthTicket[rgsc::RGSC_STEAM_TICKET_ENCODED_BUF_SIZE];
	static u32 sm_uSteamAuthTicketLen;
#endif

	char m_AdditionalSessionAttr[rgsc::RGSC_ADDITIONAL_SESSION_ATTR_BUF_SIZE];
	char m_AdditionalJoinAttr[rgsc::RGSC_ADDITIONAL_SESSION_ATTR_BUF_SIZE];
	char m_MetaDataPath[rgsc::RGSC_MAX_PATH];

#if !__FINAL && !__RGSC_DLL
	u32 GetDllVersion(const char* fileName);
	bool InstallDlls(char (&loadPath)[MAX_PATH]);
	u32 GetDllFileCount(const char* path);
#endif
	void SetSocialClubVersion(const wchar_t* fileName);
	bool LoadDll();
};

// global instance
extern rlPc g_rlPc;

} // namespace rage

#endif //RSG_PC

#endif // RLINE_RLPC_H
