/*==LICENSE==*

CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, 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/>.

Additional permissions under GNU GPL version 3 section 7

If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.

You can contact Cyan Worlds, Inc. by email legal@cyan.com
 or by snail mail at:
      Cyan Worlds, Inc.
      14617 N Newport Hwy
      Mead, WA   99021

*==LICENSE==*/
/*****************************************************************************
*
*   $/Plasma20/Sources/Plasma/NucleusLib/pnNetProtocol/Private/pnNpCommon.h
*   
***/

#ifdef PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNNETPROTOCOL_PRIVATE_PNNPCOMMON_H
#error "Header $/Plasma20/Sources/Plasma/NucleusLib/pnNetProtocol/Private/pnNpCommon.h included more than once"
#endif
#define PLASMA20_SOURCES_PLASMA_NUCLEUSLIB_PNNETPROTOCOL_PRIVATE_PNNPCOMMON_H


/*****************************************************************************
*
*   Client message field types
*
***/

#ifdef USES_NETCLI

const NetMsgField kNetMsgFieldAccountName   = NET_MSG_FIELD_STRING(kMaxAccountNameLength);
const NetMsgField kNetMsgFieldPlayerName    = NET_MSG_FIELD_STRING(kMaxPlayerNameLength);
const NetMsgField kNetMsgFieldShaDigest     = NET_MSG_FIELD_RAW_DATA(sizeof(ShaDigest));
const NetMsgField kNetMsgFieldUuid          = NET_MSG_FIELD_DATA(sizeof(Uuid));
const NetMsgField kNetMsgFieldTransId       = NET_MSG_FIELD_DWORD();
const NetMsgField kNetMsgFieldTimeMs        = NET_MSG_FIELD_DWORD();
const NetMsgField kNetMsgFieldENetError     = NET_MSG_FIELD_DWORD();
const NetMsgField kNetMsgFieldEAgeId        = NET_MSG_FIELD_DWORD();
const NetMsgField kNetMsgFieldNetNode       = NET_MSG_FIELD_DWORD();
const NetMsgField kNetMsgFieldBuildId       = NET_MSG_FIELD_DWORD();

#endif


/*****************************************************************************
*
*   Player information structures
*
***/

#include <PshPack1.h>
struct SrvPlayerInfo {
	unsigned	playerInt;
	wchar		playerName[kMaxPlayerNameLength];
	wchar		avatarShape[kMaxVaultNodeStringLength];
	unsigned	explorer;
};
#include <PopPack.h>


/*****************************************************************************
*
*   NetAgeInfo
*
***/

struct NetAgeInfo {
	Uuid		ageInstId;
	wchar		ageFilename[kMaxAgeNameLength];
	wchar		ageInstName[kMaxAgeNameLength];
	wchar		ageUserName[kMaxAgeNameLength];
	wchar		ageDesc[1024];
	dword		ageSequenceNumber;
	dword		ageLanguage;
	dword		population;			// only used with GetPublicAgeList query results
	dword		currentPopulation;	// only used with GetPublicAgeList query results
};

/*****************************************************************************
*
*   NetGameScore
*
***/

struct NetGameScore {
	unsigned	scoreId;
	unsigned	ownerId;
	UInt32		createdTime;
	wchar		gameName[kMaxGameScoreNameLength];
	unsigned	gameType;
	int			value;

	unsigned Read (const byte inbuffer[], unsigned bufsz, byte** end = nil);	// returns number of bytes read
	unsigned Write (ARRAY(byte) * buffer) const;								// returns number of bytes written

	void CopyFrom (const NetGameScore & score);
};

/*****************************************************************************
*
*   NetGameRank
*
***/

struct NetGameRank {
	unsigned	rank;
	int			score;
	wchar		name[kMaxPlayerNameLength];

	unsigned Read (const byte inbuffer[], unsigned bufsz, byte** end = nil);	// returns number of bytes read
	unsigned Write (ARRAY(byte) * buffer) const;								// returns number of bytes written

	void CopyFrom (const NetGameRank & fromRank);
};

/*****************************************************************************
*
*   Server vault structures
*
***/

//============================================================================
// NetVaultNode
//============================================================================
// Threaded apps: App is responsible for locking node->critsect before accessing *any* field in this struct
struct NetVaultNode : AtomicRef {
	enum RwOptions {
		kRwDirtyOnly	= 1<<0,	// READ : No meaning
								// WRITE: Only write fields marked dirty
		kRwUpdateDirty	= 1<<1,	// READ : Set dirty flag on fields read from stream
								// WRITE: Clear dirty flag on fields written to stream
	};
	
	enum CopyOptions {
		kCopySetDirty	= 1<<0,		// set dirty flag on changed dst fields
		kCopyOverwrite	= 1<<1,		// overwrite fields for which dst node already has values
		kCopyClear		= 1<<2,		// clear dst fields for which src node does not have values
	};
	
	// These flag values must not change unless all servers are
	// simultaneously replaced, so basically forget it.
	static const qword kNodeId			= (qword)1<< 0;
	static const qword kCreateTime		= (qword)1<< 1;
	static const qword kModifyTime		= (qword)1<< 2;
	static const qword kCreateAgeName	= (qword)1<< 3;
	static const qword kCreateAgeUuid	= (qword)1<< 4;
	static const qword kCreatorAcct		= (qword)1<< 5;
	static const qword kCreatorId		= (qword)1<< 6;
	static const qword kNodeType		= (qword)1<< 7;
	static const qword kInt32_1			= (qword)1<< 8;
	static const qword kInt32_2			= (qword)1<< 9;
	static const qword kInt32_3			= (qword)1<<10;
	static const qword kInt32_4			= (qword)1<<11;
	static const qword kUInt32_1		= (qword)1<<12;
	static const qword kUInt32_2		= (qword)1<<13;
	static const qword kUInt32_3		= (qword)1<<14;
	static const qword kUInt32_4		= (qword)1<<15;
	static const qword kUuid_1			= (qword)1<<16;
	static const qword kUuid_2			= (qword)1<<17;
	static const qword kUuid_3			= (qword)1<<18;
	static const qword kUuid_4			= (qword)1<<19;
	static const qword kString64_1		= (qword)1<<20;
	static const qword kString64_2		= (qword)1<<21;
	static const qword kString64_3		= (qword)1<<22;
	static const qword kString64_4		= (qword)1<<23;
	static const qword kString64_5		= (qword)1<<24;
	static const qword kString64_6		= (qword)1<<25;
	static const qword kIString64_1		= (qword)1<<26;
	static const qword kIString64_2		= (qword)1<<27;
	// blobs always come last
	static const qword kText_1			= (qword)1<<28;
	static const qword kText_2			= (qword)1<<29;
	static const qword kBlob_1			= (qword)1<<30;
	static const qword kBlob_2			= (qword)1<<31;
	
	CCritSect	critsect;
	
	qword		fieldFlags;
	qword		dirtyFlags;
	
	Uuid		revisionId;

	// Treat these as read-only or node flag fields will become invalid	
	// Threaded apps: Must be accessed with node->critsect locked	
	unsigned	nodeId;
	unsigned	createTime;
	unsigned	modifyTime;
	wchar *		createAgeName;
	Uuid		createAgeUuid;
	Uuid		creatorAcct;	// accountId of node creator
	unsigned	creatorId;		// playerId of node creator
	unsigned	nodeType;
	int			int32_1;
	int			int32_2;
	int			int32_3;
	int			int32_4;
	unsigned	uint32_1;
	unsigned	uint32_2;
	unsigned	uint32_3;
	unsigned	uint32_4;
	Uuid		uuid_1;
	Uuid		uuid_2;
	Uuid		uuid_3;
	Uuid		uuid_4;
	wchar *		string64_1;
	wchar *		string64_2;
	wchar *		string64_3;
	wchar *		string64_4;
	wchar *		string64_5;
	wchar *		string64_6;
	wchar *		istring64_1;
	wchar *		istring64_2;
	wchar *		text_1;
	wchar *		text_2;
	byte *		blob_1;	unsigned blob_1Length;
	byte *		blob_2;	unsigned blob_2Length;
	
	NetVaultNode ();
	~NetVaultNode ();

	// Threaded apps: Must be called with node->critsect locked	
	unsigned Read_LCS (const byte buffer[], unsigned bufsz, unsigned rwOpts);	// returns number of bytes read
	unsigned Write_LCS (ARRAY(byte) * buffer, unsigned rwOpts);					// returns number of bytes written
	
	bool Matches (const NetVaultNode * other);
	void CopyFrom (const NetVaultNode * other, unsigned copyOpts);
	
	// Threaded apps: Must be called with node->critsect locked	
	void SetNodeId (unsigned v);
	void SetCreateTime (unsigned v);
	void SetModifyTime (unsigned v);
	void SetCreateAgeName (const wchar v[]);
	void SetCreateAgeUuid (const Uuid & v);
	void SetCreatorAcct (const Uuid & v);
	void SetCreatorId (unsigned v);
	void SetNodeType (unsigned v);
	void SetInt32_1 (int v);
	void SetInt32_2 (int v);
	void SetInt32_3 (int v);
	void SetInt32_4 (int v);
	void SetUInt32_1 (unsigned v);
	void SetUInt32_2 (unsigned v);
	void SetUInt32_3 (unsigned v);
	void SetUInt32_4 (unsigned v);
	void SetUuid_1 (const Uuid & v);
	void SetUuid_2 (const Uuid & v);
	void SetUuid_3 (const Uuid & v);
	void SetUuid_4 (const Uuid & v);
	void SetString64_1 (const wchar v[]);
	void SetString64_2 (const wchar v[]);
	void SetString64_3 (const wchar v[]);
	void SetString64_4 (const wchar v[]);
	void SetString64_5 (const wchar v[]);
	void SetString64_6 (const wchar v[]);
	void SetIString64_1 (const wchar v[]);
	void SetIString64_2 (const wchar v[]);
	void SetText_1 (const wchar v[]);
	void SetText_2 (const wchar v[]);
	void SetBlob_1 (const byte v[], unsigned len);
	void SetBlob_2 (const byte v[], unsigned len);
	
	void SetText (qword fieldFlag, const wchar v[]);
	void SetBlob (qword fieldFlag, const byte v[], unsigned len);

	// These are only here to aid macro expansions (naming case matches field flags)
	inline unsigned GetNodeId () const { return nodeId; }
	inline unsigned GetCreateTime () const { return createTime; }
	inline unsigned GetModifyTime () const { return modifyTime; }
	inline wchar * GetCreateAgeName () const { return createAgeName; }
	inline Uuid GetCreateAgeUuid () const { return createAgeUuid; }
	inline Uuid GetCreatorAcct () const { return creatorAcct; }
	inline unsigned GetCreatorId () const { return creatorId; }
	inline unsigned GetNodeType () const { return nodeType; }
	inline int GetInt32_1 () const { return int32_1; }
	inline int GetInt32_2 () const { return int32_2; }
	inline int GetInt32_3 () const { return int32_3; }
	inline int GetInt32_4 () const { return int32_4; }
	inline unsigned GetUInt32_1 () const { return uint32_1; }
	inline unsigned GetUInt32_2 () const { return uint32_2; }
	inline unsigned GetUInt32_3 () const { return uint32_3; }
	inline unsigned GetUInt32_4 () const { return uint32_4; }
	inline Uuid GetUuid_1 () const { return uuid_1; }
	inline Uuid GetUuid_2 () const { return uuid_2; }
	inline Uuid GetUuid_3 () const { return uuid_3; }
	inline Uuid GetUuid_4 () const { return uuid_4; }
	inline wchar * GetString64_1 () const { return string64_1; }
	inline wchar * GetString64_2 () const { return string64_2; }
	inline wchar * GetString64_3 () const { return string64_3; }
	inline wchar * GetString64_4 () const { return string64_4; }
	inline wchar * GetString64_5 () const { return string64_5; }
	inline wchar * GetString64_6 () const { return string64_6; }
	inline wchar * GetIString64_1 () const { return istring64_1; }
	inline wchar * GetIString64_2 () const { return istring64_2; }
	// no blob "getters"
};


//============================================================================
inline void IVaultNodeSetString (
	qword			bit,
	NetVaultNode *	node,
	char **			pdst,
	const char		src[],
	unsigned		chars
) {
	FREE(*pdst);
	if (src && src[0])
		*pdst = StrDupLen(src, chars);
	else
		*pdst = StrDupLen("", chars);
	node->fieldFlags |= bit;
	node->dirtyFlags |= bit;
}

//============================================================================
inline void IVaultNodeSetString (
	qword			bit,
	NetVaultNode *	node,
	wchar **		pdst,
	const wchar		src[],
	unsigned		chars
) {
	FREE(*pdst);
	if (src && src[0])
		*pdst = StrDupLen(src, chars);
	else
		*pdst = StrDupLen(L"", chars);
	node->fieldFlags |= bit;
	node->dirtyFlags |= bit;
}

//============================================================================
template <typename T>
inline void IVaultNodeSetValue (
	qword			bit,
	NetVaultNode *	node,
	T *				pdst,
	const T &		src
) {
	*pdst = src;
	node->fieldFlags |= bit;
	node->dirtyFlags |= bit;
}

//============================================================================
inline void IVaultNodeSetBlob (
	qword			bit,
	NetVaultNode *	node,
	byte **			pdst,
	unsigned *		pdstLen,
	const byte		src[],
	unsigned		srcLen
) {
	FREE(*pdst);
	if (src) {
		*pdst = (byte*)MEMDUP(src, srcLen);
		*pdstLen = srcLen;
	}
	else {
		*pdst = nil;
		*pdstLen = 0;
	}
	node->fieldFlags |= bit;
	node->dirtyFlags |= bit;
}


//============================================================================
// NetVaultNodeFieldArray
//============================================================================
struct NetVaultNodeFieldArray {
	enum EWhereCondition {
		kAnd,
		kOr
	};
	enum ESqlType {
		kSqlInvalid,
		kSqlInt32,
		kSqlUInt32,
		kSqlUuid,
		kSqlString,
		kSqlCLob,
		KSqlBlob,
	};
	
	struct Field {
		void *			addr;
		const wchar *	name;
		Field (void * addr, const wchar name[])
		: addr(addr), name(name)
		{ }
	};
	ARRAY(Field)	fields;
	NetVaultNode *	node;

	NetVaultNodeFieldArray (NetVaultNode * node);
	~NetVaultNodeFieldArray ();

	void * GetFieldAddress (qword bit);
	const wchar * GetFieldName (qword bit);
	
	// client must lock node's local critical section before calling these.
	void GetFieldValueString_LCS (qword bit, wchar * dst, unsigned dstChars);	
	void BuildWhereClause_LCS (EWhereCondition condition, wchar * dst, unsigned dstChars);
	ESqlType GetSqlType_LCS (qword bit);
};


//============================================================================
// NetVaultNodeRef (packed because is sent over wire directly)
//============================================================================
#include <PshPack1.h>
struct NetVaultNodeRef {
	unsigned	parentId;
	unsigned	childId;
	unsigned	ownerId;
	bool		seen;
};
#include <PopPack.h>

//============================================================================
// SrvPackBuffer
//============================================================================

// Allocate a CSrvPackBuffer on the heap with one extra dword to allow for padding
#define SRV_ALLOC_BUFFER(bytes)										\
	new(ALLOC(sizeof(CSrvPackBuffer) + (bytes) + sizeof(dword)))	\
	CSrvPackBuffer(bytes + sizeof(dword))

// Allocate a CSrvPackBuffer on the stack with one extra dword to allow for padding
#define SRV_ALLOCA_BUFFER(bytes)										\
	new(_alloca(sizeof(CSrvPackBuffer) + (bytes) + sizeof(dword)))	\
	CSrvPackBuffer(bytes + sizeof(dword))

class CSrvPackBuffer {
public:
	CSrvPackBuffer (unsigned bytes);

	void * Alloc (unsigned bytes);
	void AddData (const void * ptr, unsigned bytes);
	void AddString (const wchar str[]);
	void AddDWordArray (const dword * arr, unsigned count);
	void AddDWordArray (const unsigned * arr, unsigned count);
	// add new "Add..." methods here as needed

	unsigned Size ();
	
private:
	byte * m_pos;
	byte * m_end;
	byte * m_data;
};

class CSrvUnpackBuffer {
public:
	CSrvUnpackBuffer (const void * buffer, unsigned count);

	const void *  GetData (unsigned bytes);
	const wchar * GetString ();
	const dword * GetDWordArray (unsigned count);
	
	unsigned BytesLeft ();
	bool ParseError ();

private:
	const byte * m_pos;
	const byte * m_end;
};