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

#include "hsTypes.h"
#include "hsStlUtils.h"
#include "hsBitVector.h"
#include "plNetCommon/plNetServerSessionInfo.h"
#include "plNetCommon/plNetCommon.h"
#include "plMessage/plLinkToAgeMsg.h"

class plMessage;
struct plNCAgeJoiner;
struct plNCAgeLeaver;

class plNetLinkingMgr
{
	static void NCAgeJoinerCallback (
		plNCAgeJoiner *			joiner,
		unsigned				type,
		void *					notify,
		void *					userState
	);
	
	static void NCAgeLeaverCallback (
		plNCAgeLeaver *			leaver,
		unsigned				type,
		void *					notify,
		void *					userState
	);

	friend struct NCAgeJoinerCallback;
	friend struct NCAgeLeaverCallback;
	
	static void ExecNextOp ();


	plNetLinkingMgr();
	plNetLinkingMgr(const plNetLinkingMgr &);

	enum Cmds
	{
		kNilCmd,
		// Sent to a player to have them call us back with info for linking to their age.
		kLinkPlayerHere,
		// Offer link to player.
		kOfferLinkToPlayer,
		// Offer link to another player from a public linking book (to my instance of the age w/out going through personal age)
		kOfferLinkFromPublicBook,
		// Sent to a player to have them link to their last age 
		kLinkPlayerToPrevAge
	};

	bool IPreProcessLink( void );
	void IPostProcessLink( void );
	bool IProcessLinkingMgrMsg( plLinkingMgrMsg * msg );
	bool IProcessLinkToAgeMsg( plLinkToAgeMsg * msg );

	bool IDispatchMsg( plMessage * msg, UInt32 playerID );


public:
	static plNetLinkingMgr * GetInstance();
	hsBool MsgReceive( plMessage *msg );	// TODO: Make this a hsKeyedObject so we can really handle messages.
	void Update();

	bool IsEnabled( void ) const { return fLinkingEnabled;}
	void SetEnabled( bool b );
	
	bool LinkedIn () const { return  fLinkedIn &&  fLinkingEnabled; }
	bool Linking () const  { return !fLinkedIn && !fLinkingEnabled; }

	// Link to an age.
	void LinkToAge( plAgeLinkStruct * link, UInt32 playerID=kInvalidPlayerID );
	void LinkToAge( plAgeLinkStruct * link, const char* linkAnim, UInt32 playerID=kInvalidPlayerID );
	// Link to my last age.
	void LinkToPrevAge( UInt32 playerID=kInvalidPlayerID );	
	// Link to my Personal Age
	void LinkToMyPersonalAge( UInt32 playerID=kInvalidPlayerID );
	// Link to my Neighborhood Age
	void LinkToMyNeighborhoodAge( UInt32 playerID=kInvalidPlayerID );
	// Link a player here.
	void LinkPlayerHere( UInt32 playerID );
	// Link player to specified age
	void LinkPlayerToAge( plAgeLinkStruct * link, UInt32 playerID );
	// Link player back to his last age
	void LinkPlayerToPrevAge( UInt32 playerID );
	// Link us to a players age.
	void LinkToPlayersAge( UInt32 playerID );
	// Offer a link to player.
	void OfferLinkToPlayer( const plAgeLinkStruct * info, UInt32 playerID, plKey replyKey );
	void OfferLinkToPlayer( const plAgeInfoStruct * info, UInt32 playerID );
	void OfferLinkToPlayer( const plAgeLinkStruct * info, UInt32 playerID );
	// Leave the current age
	void LeaveAge (bool quitting);

	// link info
	plAgeLinkStruct * GetAgeLink() { return &fAgeLink; }
	plAgeLinkStruct * GetPrevAgeLink() { return &fPrevAgeLink; }

	// lobby info
	void SetLobbyAddr( const char * ipaddr ) { fLobbyInfo.SetServerAddr( ipaddr );}
	void SetLobbyPort( int port ) { fLobbyInfo.SetServerPort( port );}
	const plNetServerSessionInfo * GetLobbyServerInfo( void ) const { return &fLobbyInfo;}

	// helpers
	static std::string GetProperAgeName( const char * ageName );	// attempt to fix wrong case age name.

private:
	bool				fLinkingEnabled;
	bool				fLinkedIn;

	// The age we are either joining or are joined with.
	plAgeLinkStruct		fAgeLink;

	// The age we just left.
	plAgeLinkStruct		fPrevAgeLink;

	// The lobby we want to talk to.
	plNetServerSessionInfo	fLobbyInfo;
};


#endif // plNetLinkingMgr_h_inc