/*==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/>.

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==*/
#ifndef plNetServerSessionInfo_h_inc
#define plNetServerSessionInfo_h_inc

#include "hsTypes.h"
#include "hsStlUtils.h"
#include "../pnFactory/plCreatable.h"
#include "../pnNetCommon/plNetServers.h"
#include "../plNetCommon/plSpawnPointInfo.h"
#include "../plUUID/plUUID.h"


class hsStream;
class hsResMgr;
class plVaultAgeInfoNode;
class plVaultAgeLinkNode;

///////////////////////////////////////////////////////////////////
// Holds info that describes an age

class plAgeInfoStruct : public plCreatable
{
	mutable UInt8			fFlags;

	// Age dataset name "Neighborhood"
	std::string		fAgeFilename;

	// Age string ID "Bevin"
	std::string		fAgeInstanceName;

	// Age guid. Same as game server guid.
	plUUID	fAgeInstanceGuid;

	// User-defined age name: "My Teledahn"
	std::string		fAgeUserDefinedName;

	// User-defined age description "This is Joe's Neighborhood"
	std::string		fAgeDescription;

	// A modifier to user-defined name to make it unique in gui lists.
	// Assigned by vault server.
	Int32			fAgeSequenceNumber;
	
	// The language of the client that created this age
	Int32			fAgeLanguage;

	mutable std::string		fDisplayName;

	enum
	{
		kHasAgeFilename			= 1<<0,
		kHasAgeInstanceName		= 1<<1,
		kHasAgeInstanceGuid		= 1<<2,
		kHasAgeUserDefinedName	= 1<<3,
		kHasAgeSequenceNumber	= 1<<4,
		kHasAgeDescription		= 1<<5,
		kHasAgeLanguage			= 1<<6,
	};

	void	SetFlag( UInt8 bit, bool on=true ) const { (on)?fFlags|=bit:fFlags&=~bit;}
	void	ClearFlag( UInt8 bit ) { fFlags&=~bit;}
	bool	IsFlagSet( UInt8 bit ) const { return (fFlags&bit)!=0;}

public:
	plAgeInfoStruct()
	: fFlags( 0 )
	, fAgeSequenceNumber( 0 )
	, fAgeLanguage( -1 )
	{}

	CLASSNAME_REGISTER( plAgeInfoStruct );
	GETINTERFACE_ANY( plAgeInfoStruct, plCreatable );

	void	Clear();
	void	UpdateFlags() const;
	void	CopyFrom( const plAgeInfoStruct * other ) { *this=*other; }
	void	CopyFrom( const plVaultAgeInfoNode * node );
	void	CopyFrom(const struct NetAgeInfo & info);
	bool	IsEqualTo( const plAgeInfoStruct * other ) const;

	const char * GetAgeFilename() const { return fAgeFilename.c_str(); }
	const char * GetAgeInstanceName() const { return fAgeInstanceName.c_str(); }
	const plUUID * GetAgeInstanceGuid() const { return &fAgeInstanceGuid; }
	const char * GetAgeUserDefinedName() const { return fAgeUserDefinedName.c_str(); }
	const char * GetAgeDescription() const { return fAgeDescription.c_str(); }
	UInt32	GetAgeSequenceNumber() const { return fAgeSequenceNumber; }
	UInt32	GetAgeLanguage() const { return fAgeLanguage; }

	void	SetAgeFilename( const char * v );
	void	SetAgeInstanceName( const char * v );
	void	SetAgeInstanceGuid( const plUUID * v );
	void	SetAgeUserDefinedName( const char * v );
	void	SetAgeDescription( const char * v );
	void	SetAgeSequenceNumber( UInt32 v );
	void	SetAgeLanguage( UInt32 v );

	bool	HasAgeFilename() const { return IsFlagSet( kHasAgeFilename ); }
	bool	HasAgeInstanceName() const { return IsFlagSet( kHasAgeInstanceName ); }
	bool	HasAgeInstanceGuid() const { return IsFlagSet( kHasAgeInstanceGuid ) && fAgeInstanceGuid.IsSet(); }
	bool	HasAgeUserDefinedName() const { return IsFlagSet( kHasAgeUserDefinedName ); }
	bool	HasAgeDescription() const { return IsFlagSet( kHasAgeDescription ); }
	bool	HasAgeSequenceNumber() const { return IsFlagSet( kHasAgeSequenceNumber ); }
	bool	HasAgeLanguage() const { return IsFlagSet( kHasAgeLanguage ); }

	void	Read( hsStream * s, hsResMgr* );
	void	Write( hsStream * s, hsResMgr* );

	const char * GetDisplayName() const;

	std::string AsStdString() const;
};

////////////////////////////////////////////////////////////////////

class plAgeLinkStruct : public plCreatable
{
	UInt16				fFlags;

	// Where we want to link.
	plAgeInfoStruct		fAgeInfo;

	// The linking rule to use. See plNetCommon::LinkingRules
	Int8				fLinkingRules;

	// Where to spawn avatar when we load the age specified in fAgeInfo
	plSpawnPointInfo	fSpawnPoint;

	// Override PLS/MCP load balancing rules for CCRs.
	UInt8				fAmCCR;

	// If this is a child age link, who is the parent
	//    ...Age dataset name  like "Neighborhood"
	std::string			fParentAgeFilename;

	enum
	{
		kHasAgeInfo			= 1<<0,
		kHasLinkingRules	= 1<<1,
		kHasSpawnPt_DEAD	= 1<<2,
		kHasSpawnPt_DEAD2	= 1<<3,
		kHasAmCCR			= 1<<4,
		kHasSpawnPt			= 1<<5,
		kHasParentAgeFilename	= 1<<6,
	};

	void	SetFlag( UInt16 bit, bool on=true ) { (on)?fFlags|=bit:fFlags&=~bit;}
	void	ClearFlag( UInt16 bit ) { fFlags&=~bit;}
	bool	IsFlagSet( UInt16 bit ) const { return (fFlags&bit)!=0;}

public:
	plAgeLinkStruct();
	CLASSNAME_REGISTER( plAgeLinkStruct );
	GETINTERFACE_ANY( plAgeLinkStruct, plCreatable );

	plAgeInfoStruct * GetAgeInfo() { return &fAgeInfo; }
	const plAgeInfoStruct * GetAgeInfo() const { return &fAgeInfo; }

	const char * GetParentAgeFilename() const { return fParentAgeFilename.c_str(); }
	void	SetParentAgeFilename( const char * v );

	void	CopyFrom( const plAgeLinkStruct * other );
	void	CopyFrom( const plVaultAgeLinkNode * node );
	bool	IsEqualTo( const plAgeLinkStruct * other ) const;
	void	Clear();

	bool	HasAgeInfo() const { return IsFlagSet( kHasAgeInfo ); }
	bool	HasLinkingRules() const { return IsFlagSet( kHasLinkingRules ); }
	bool	HasSpawnPt() const { return IsFlagSet( kHasSpawnPt ); }
	bool	HasAmCCR() const { return IsFlagSet( kHasAmCCR ); }
	bool	HasParentAgeFilename() const { return IsFlagSet( kHasParentAgeFilename ); }

	void	SetLinkingRules( int v ) { SetFlag( kHasLinkingRules ); fLinkingRules=v; }
	int		GetLinkingRules() const { return fLinkingRules; }
	void	SetSpawnPoint( const plSpawnPointInfo & point ) { SetFlag( kHasSpawnPt ); fSpawnPoint=point; }
	plSpawnPointInfo & SpawnPoint() { return fSpawnPoint; }
	const plSpawnPointInfo & SpawnPoint() const { return fSpawnPoint; }
	void	SetAmCCR( bool v ) { SetFlag( kHasAmCCR ); fAmCCR=v?1:0; }
	bool	GetAmCCR() const { return fAmCCR!=0; }

	void	Read( hsStream * s, hsResMgr* );
	void	Write( hsStream * s, hsResMgr* );

	std::string AsStdString() const;
};


////////////////////////////////////////////////////////////////////
// Holds info that describes a server session
//

class plNetServerSessionInfo : public plCreatable
{
	UInt8			fFlags;
	std::string		fServerName;
	UInt8			fServerType;
	std::string		fServerAddr;
	UInt16			fServerPort;
	plUUID	fServerGuid;

	enum
	{
		kHasServerName	= 1<<0,
		kHasServerType	= 1<<1,
		kHasServerAddr	= 1<<2,
		kHasServerPort	= 1<<3,
		kHasServerGuid	= 1<<4,
	};

	void	SetFlag( UInt8 bit ) { fFlags|=bit;}
	void	ClearFlag( UInt8 bit ) { fFlags&=~bit;}
	bool	IsFlagSet( UInt8 bit ) const { return (fFlags&bit)!=0;}

public:
	plNetServerSessionInfo()
	: fServerType(plNetServerConstants::kInvalidLo)
	, fServerPort(0)
	, fFlags(0)
	{}
	CLASSNAME_REGISTER( plNetServerSessionInfo );
	GETINTERFACE_ANY( plNetServerSessionInfo, plCreatable );

	void SetServerName(const char * val);
	void SetServerType(UInt8 val);
	void SetServerAddr(const char * val);
	void SetServerPort(UInt16 val);
	void SetServerGuid(const plUUID * val);
	void CopyServerGuid(const plUUID & val);

	const char *	GetServerName() const { return fServerName.c_str();}
	UInt8			GetServerType() const { return fServerType;}
	const char *	GetServerAddr() const { return fServerAddr.c_str(); }
	UInt16			GetServerPort() const { return fServerPort; }
	const plUUID *GetServerGuid() const { return &fServerGuid; }
	plUUID *	GetServerGuid() { return &fServerGuid; }

	bool HasServerName() const { return IsFlagSet(kHasServerName);}
	bool HasServerType() const { return IsFlagSet(kHasServerType);}
	bool HasServerAddr() const { return IsFlagSet(kHasServerAddr);}
	bool HasServerPort() const { return IsFlagSet(kHasServerPort);}
	bool HasServerGuid() const { return IsFlagSet(kHasServerGuid);}
	bool IsFullyQualified() const
	{
		return
			IsFlagSet(kHasServerName)&&
			IsFlagSet(kHasServerType)&&
			IsFlagSet(kHasServerAddr)&&
			IsFlagSet(kHasServerPort)&&
			IsFlagSet(kHasServerGuid);
	}

	void Clear();
	void CopyFrom(const plNetServerSessionInfo * other);
	bool IsEqualTo(const plNetServerSessionInfo * other) const;
	virtual std::string AsStdString() const;
	virtual std::string AsLogString() const;

	void Read(hsStream* s, hsResMgr* mgr=nil);
	void Write(hsStream* s, hsResMgr* mgr=nil);

	// WriteVersion writes the current version of this creatable and ReadVersion will read in
	// any previous version.
	virtual void ReadVersion(hsStream* s, hsResMgr* mgr);
	virtual void WriteVersion(hsStream* s, hsResMgr* mgr);
};

////////////////////////////////////////////////////////////////////

//class plVaultAgeInfoNode;
//class plAgeLinkingInfo : public plCreatable
//{
//	int				fLinkingRules;
//	UInt32			fPlayerID;
//	hsBool8			fSuperUser;
//	mutable plAgeInfoStruct	fAgeInfo;
//	mutable plNetServerSessionInfo fServerInfo;
//
//public:
//	plAgeLinkingInfo();
//
//	CLASSNAME_REGISTER( plAgeLinkingInfo );
//	GETINTERFACE_ANY( plAgeLinkingInfo, plCreatable );
//
//	int		GetLinkingRules( void ) const { return fLinkingRules;}
//	void	SetLinkingRules( int v ) { fLinkingRules=v;}
//	UInt32	GetPlayerID( void ) const { return fPlayerID;}
//	void	SetPlayerID( UInt32 v ) { fPlayerID=v;}
//	void	SetSuperUser(bool b) { fSuperUser=b;	}
//	bool	GetSuperUser() const { return fSuperUser ? true : false;	}
//
//	plAgeInfoStruct * GetAgeInfo();
//	const plAgeInfoStruct * GetAgeInfo() const;
//	
//	// initializes info with age name and guid for you.
//	plNetServerSessionInfo * GetServerInfo();
//	const plNetServerSessionInfo * GetServerInfo() const;
//	const plNetServerSessionInfo * AsServerInfo() const;
//
//	void Clear( void );
//	void CopyFrom( const plAgeLinkingInfo * other );
//	void CopyFrom( const plVaultAgeInfoNode * node );
//	void CopyFrom( const plNetServerSessionInfo * info );
//	void CopyFrom( const plAgeInfoStruct * info );
//
//	void Read(hsStream* s, hsResMgr* mgr=nil);
//	void Write(hsStream* s, hsResMgr* mgr=nil);
//
//	std::string AsStdString() const;
//};

#endif // plNetServerSessionInfo_h_inc