/*==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==*/
#include "plClientGuid.h"
#include "hsStream.h"
#include <sstream>
#include "plNetCommon.h"
#include "pnMessage/plMessage.h"
#include "plSockets/plNet.h"

plClientGuid::plClientGuid()
:fPlayerID(0)
,fCCRLevel(0)
,fFlags(0)
,fProtectedLogin(false)
,fBuildType(plNetCommon::BuildType::kUnknown)
,fSrcAddr(0)
,fSrcPort(0)
,fReserved(false)
{
	fAccountUUID.Clear();
}

void plClientGuid::SetAccountUUID(const plUUID * v )
{
	fAccountUUID.CopyFrom( v );
	if ( !fAccountUUID.IsNull() )
		fFlags|=kAccountUUID;
	else
		fFlags&=~kAccountUUID;
}

void plClientGuid::SetAccountUUID(const plUUID & v )
{
	SetAccountUUID( &v );
}

void plClientGuid::SetBuildType(UInt8 type)
{
	fBuildType=type;
	fFlags|=kBuildType;
}

void plClientGuid::SetPlayerID(UInt32 id)
{
	fPlayerID=id;
	if ( fPlayerID )
	{
		fFlags|=kPlayerID;
		fFlags&=~kTempPlayerID;
	}
	else
		fFlags&=~kPlayerID;
}

void plClientGuid::SetTempPlayerID(UInt32 id)
{
	fPlayerID=id;
	if ( fPlayerID )
	{
		fFlags&=~kPlayerID;
		fFlags|=kTempPlayerID;
	}
	else
	{
		fFlags&=~kTempPlayerID;
	}
}

void plClientGuid::SetPlayerName( const char * v )
{
	fPlayerName = v?v:"";
	if ( fPlayerName.size() )
		fFlags|=kPlayerName;
	else
		fFlags&=~kPlayerName;
}

void plClientGuid::SetCCRLevel(UInt8 v)
{
	fCCRLevel=v;
	fFlags|=kCCRLevel;
}

void plClientGuid::SetProtectedLogin(bool b)
{
	fProtectedLogin=b;
	fFlags |= kProtectedLogin;
}

void plClientGuid::SetSrcAddr( UInt32 v )
{
	fSrcAddr = v;
	if ( fSrcAddr )
		fFlags|=kSrcAddr;
	else
		fFlags&=~kSrcAddr;
}

void plClientGuid::SetSrcAddrFromStr( const char * s )
{
    hsAssert(false, "eric, port me");
}

void plClientGuid::SetSrcPort( UInt16 v )
{
	fSrcPort = v;
	if ( fSrcPort )
		fFlags|=kSrcPort;
	else
		fFlags&=~kSrcPort;
}

void plClientGuid::SetReserved(bool b)
{
	fReserved=b;
	fFlags |= kReserved;
}

void plClientGuid::SetClientKey(const std::string& key)
{
	fClientKey = key;
	if ( fClientKey.size() )
		fFlags|=kClientKey;
	else
		fFlags&=~kClientKey;
}

const char * plClientGuid::GetSrcAddrStr() const
{
    hsAssert(false, "eric, port me");
    static const char foo[] = "";
    return foo;
}

std::string plClientGuid::AsStdString() const
{
#define kComma  ","
#define kEmpty	""
	const char * spacer = kEmpty;

	std::stringstream ss;

	ss << "[";

	if (IsFlagSet(kPlayerID))
	{
		ss << spacer << "Pid:" << fPlayerID;
		spacer = kComma;
	}
	else if (IsFlagSet(kTempPlayerID))
	{
		ss << spacer << "tPd:" << fPlayerID;
		spacer = kComma;
	}
	if (IsFlagSet(kPlayerName))
	{
		ss << spacer << "Plr:" << fPlayerName;
	}
	if (IsFlagSet(kCCRLevel))
	{
		ss << spacer << "CCR:" << (int)fCCRLevel;
		spacer = kComma;
	}
	if (IsFlagSet(kProtectedLogin))
	{
		ss << spacer << "Pro:" << (int)fProtectedLogin;
		spacer = kComma;
	}
	if (IsFlagSet(kBuildType))
	{
		ss << spacer << "Bld:" << plNetCommon::BuildType::BuildTypeStr(fBuildType);
		spacer = kComma;
	}
	if ( IsFlagSet(kSrcAddr) )
	{
		ss << spacer << "Addr:" << GetSrcAddrStr();
		spacer = kComma;
	}
	if ( IsFlagSet(kSrcPort) )
	{
		ss << spacer << "Port:" << (int)fSrcPort;
		spacer = kComma;
	}
	if (IsFlagSet(kAccountUUID))
	{
		ss << spacer << "plUUID:" << fAccountUUID.AsStdString();
		spacer = kComma;
	}
	if ( IsFlagSet(kReserved))
	{
		ss << spacer << "Res:" << (int)fReserved;
		spacer = kComma;
	}
	if (IsFlagSet(kClientKey))
	{
		ss << spacer << "ClientKey:" << fClientKey;
		spacer = kComma;
	}
	ss	<< "]";

	return ss.str().c_str();
}

std::string plClientGuid::AsLogString() const
{
#define kSemicolon	";"
	const char* spacer = kSemicolon;

	std::stringstream ss;

	if (IsFlagSet(kAccountUUID))
	{
		ss << "AcctUUID=" << fAccountUUID.AsStdString();
		ss << spacer;
	}
	if (IsFlagSet(kPlayerID))
	{
		ss << "PlayerID=" << fPlayerID;
		ss << spacer;
	}
//	else if (IsFlagSet(kTempPlayerID))
//	{
//		ss << "tempPlayerID:" << fPlayerID;
//		ss << spacer;
//	}
	if ( IsFlagSet(kSrcAddr) )
	{
		ss << "SrcAddr=" << GetSrcAddrStr();
		ss << spacer;
	}
	if ( IsFlagSet(kSrcPort) )
	{
		ss << "SrcPort=" << (int)fSrcPort;
		ss << spacer;
	}
	if (IsFlagSet(kCCRLevel))
	{
		ss << "CCRLevel=" << (int)fCCRLevel;
		ss << spacer;
	}
	if (IsFlagSet(kProtectedLogin))
	{
		ss << "Protected=" << (int)fProtectedLogin;
		ss << spacer;
	}
	if (IsFlagSet(kBuildType))
	{
		ss << "Build=" << plNetCommon::BuildType::BuildTypeStr(fBuildType);
		ss << spacer;
	}
	if (IsFlagSet(kReserved))
	{
		ss << "Reserved=" << (int)fReserved;
		ss << spacer;
	}
	if (IsFlagSet(kClientKey))
	{
		ss << "ClientKey=" << fClientKey;
		ss << spacer;
	}

	return ss.str().c_str();
}

void plClientGuid::Read(hsStream * s, hsResMgr* mgr)
{
	s->LogSubStreamStart("push me");
	s->LogReadSwap(&fFlags,"Flags");
	if (IsFlagSet(kAccountUUID))
	{
		s->LogSubStreamPushDesc("AcctUUID");
		fAccountUUID.Read( s );
	}
	if (IsFlagSet(kPlayerID))
		s->LogReadSwap(&fPlayerID,"PlayerID");
	else if (IsFlagSet(kTempPlayerID))
		s->LogReadSwap(&fPlayerID,"TempPlayerID");
	if (IsFlagSet(kPlayerName))
	{
		s->LogSubStreamPushDesc("PlayerName");
		plMsgStdStringHelper::Peek( fPlayerName, s );
	}
	if (IsFlagSet(kCCRLevel))
		s->LogReadSwap(&fCCRLevel,"CCRLevel");
	if (IsFlagSet(kProtectedLogin))
		s->LogReadSwap(&fProtectedLogin,"ProtectedLogin");
	if (IsFlagSet(kBuildType))
		s->LogReadSwap(&fBuildType,"BuildType");
	if (IsFlagSet(kSrcAddr))
		s->LogReadSwap(&fSrcAddr,"SrcAddr");
	if (IsFlagSet(kSrcPort))
		s->LogReadSwap(&fSrcPort,"SrcPort");
	if (IsFlagSet(kReserved))
		s->LogReadSwap(&fReserved,"Reserved");
	if (IsFlagSet(kClientKey))
	{
		s->LogSubStreamPushDesc("ClientKey");
		plMsgStdStringHelper::Peek( fClientKey, s );
	}
	s->LogSubStreamEnd();
}

void plClientGuid::Write(hsStream * s, hsResMgr* mgr)
{
	s->WriteSwap(fFlags);
	if (IsFlagSet(kAccountUUID))
		fAccountUUID.Write( s );
	if (IsFlagSet(kPlayerID))
		s->WriteSwap(fPlayerID);
	else if (IsFlagSet(kTempPlayerID))
		s->WriteSwap(fPlayerID);
	if (IsFlagSet(kPlayerName))
		plMsgStdStringHelper::Poke( fPlayerName, s );
	if (IsFlagSet(kCCRLevel))
		s->WriteSwap(fCCRLevel);
	if (IsFlagSet(kProtectedLogin))
		s->WriteSwap(fProtectedLogin);
	if (IsFlagSet(kBuildType))
		s->WriteSwap(fBuildType);
	if (IsFlagSet(kSrcAddr))
		s->WriteSwap(fSrcAddr);
	if (IsFlagSet(kSrcPort))
		s->WriteSwap(fSrcPort);
	if (IsFlagSet(kReserved))
		s->WriteSwap(fReserved);
	if (IsFlagSet(kClientKey))
		plMsgStdStringHelper::Poke( fClientKey, s );
}

void plClientGuid::CopyFrom(const plClientGuid * other)
{
	fFlags = other->fFlags;
	fAccountUUID.CopyFrom( &other->fAccountUUID );
	fPlayerID = other->fPlayerID;
	fPlayerName = other->fPlayerName;
	fCCRLevel = other->fCCRLevel;
	fProtectedLogin = other->fProtectedLogin;
	fBuildType = other->fBuildType;
	fSrcAddr = other->fSrcAddr;
	fSrcPort = other->fSrcPort;
	fReserved = other->fReserved;
	fClientKey = other->fClientKey;
}

void plClientGuid::UpdateFrom(const plClientGuid * other)
{
	if ( !HasAccountUUID() && other->HasAccountUUID() )
		SetAccountUUID( other->GetAccountUUID() );
	if ( !HasPlayerID() && other->HasPlayerID() )
		SetPlayerID( other->GetPlayerID() );
	if ( !HasPlayerName() && other->HasPlayerName() )
		SetPlayerName( other->GetPlayerName() );
	if ( !HasProtectedLogin() && other->HasProtectedLogin() )
		SetProtectedLogin( other->GetProtectedLogin() );
	if ( !HasCCRLevel() && other->HasCCRLevel() )
		SetCCRLevel( other->GetCCRLevel() );
	if ( !HasBuildType() && other->HasBuildType() )
		SetBuildType( other->GetBuildType() );
	if ( !HasSrcAddr() && other->HasSrcAddr() )
		SetSrcAddr( other->GetSrcAddr() );
	if ( !HasSrcPort() && other->HasSrcPort() )
		SetSrcPort( other->GetSrcPort() );
	if ( !HasReservedBit() && other->HasReservedBit() )
		SetReserved( other->IsReserved() );
	if ( !HasClientKey() && other->HasClientKey() )
		SetClientKey( other->GetClientKey() );
}

void plClientGuid::Clear()
{
	plClientGuid tmp;
	CopyFrom( &tmp );
}

bool plClientGuid::IsEqualTo(const plClientGuid * other) const
{
	return
		fFlags == other->fFlags &&
		fAccountUUID.IsEqualTo( &other->fAccountUUID ) &&
		fPlayerID == other->fPlayerID &&
		fPlayerName == other->fPlayerName &&
		fCCRLevel == other->fCCRLevel &&
		fProtectedLogin == other->fProtectedLogin &&
		fBuildType == other->fBuildType &&
		fReserved == other->fReserved &&
		fClientKey == other->fClientKey;
}

bool operator==(const plClientGuid & X, const plClientGuid & Y)
{
	return ( X.fAccountUUID.IsEqualTo( &Y.fAccountUUID )&&X.fPlayerID==Y.fPlayerID&&X.fFlags==Y.fFlags);
}
bool operator!=(const plClientGuid & X, const plClientGuid & Y)
{
	return ( !X.fAccountUUID.IsEqualTo( &Y.fAccountUUID )||X.fPlayerID!=Y.fPlayerID||X.fFlags!=Y.fFlags);
}
bool operator<(const plClientGuid & X, const plClientGuid & Y)
{
	return ( X.fAccountUUID.CompareTo( &Y.fAccountUUID )<0||X.fPlayerID<Y.fPlayerID);
}