//===========================================================================//
// File: Connection.cpp                                  
// Project: MUNGA           Brick: Replicator 
// Contents:
//---------------------------------------------------------------------------//
//   Date    Who  Modification                                               //
// --------  ---  ---------------------------------------------------------- //
//	08/24/97  JMA  Infrastructure changes.									
// 08/25/97  ECH  Infrastructure changes.                                    //
//---------------------------------------------------------------------------//
// Copyright (C) 1994-1997, Virtual World Entertainment, Inc.                //
//                      PROPRIETARY AND CONFIDENTIAL                         //
//===========================================================================//

#include "AdeptHeaders.hpp"

#include "Connection.hpp"
#include "Replicator.hpp"

//#define HUNT_BUG "your_loginname_here"

//#############################################################################
//#########################    Connection    ###########################
//#############################################################################

Connection*
	Connection::Local = NULL;
Connection*
	Connection::Server = NULL;
Connection*
	Connection::Hermit = NULL;

const Receiver::MessageEntry
	Connection::MessageEntries[]=
{
	MESSAGE_ENTRY(Connection, Replicate),
	MESSAGE_ENTRY(Connection, Replicator)
};

Connection::ClassData*
	Connection::DefaultData = NULL;

Stuff::SafeChainOf<Replicator*>* g_pTempReplicators = NULL; // jcem
#ifdef _DEBUG
int g_nMechLabs = 0;
#endif // _DEBUG
//
//#############################################################################
//#############################################################################
//
void
	Connection::InitializeClass()
{
	Verify(!DefaultData);
	DefaultData =
		new ClassData(
			ConnectionClassID,
			"Adept::Connection",
			InBox::DefaultData,
			ELEMENTS(MessageEntries), MessageEntries
		);
	Register_Object(DefaultData);
}

//
//#############################################################################
//#############################################################################
//
void
	Connection::TerminateClass()
{
	Unregister_Object(DefaultData);
	delete DefaultData;
	DefaultData = NULL;
}

//
//#############################################################################
//#############################################################################
//
Connection::Connection(
	BYTE id,
	DWORD network_address,
	const char *name
):
	InBox(DefaultData, Network::ConnectionBoxID),
	allReplicators(NULL),
	nextReplicatorID(id)
{
	Check_Pointer(this);

	connectionID = id;
	networkAddress = network_address;
	connectionName = name;
	bytesToTransfer = 0;
	dataBuffer = NULL;

	// we dont add here due to the fact we don't really know
	// if this is the local connection or hermit connection at this point...

	for (int i = 0; i < 8192; ++i)
	{
		usedConnections[i] = 0x0;
	}

	replicatorCount = 0;
}

//
//#############################################################################
//#############################################################################
//
Connection::~Connection()
{
	if (Network::GetInstance() != NULL)
	{
		Network::GetInstance()->RemoveConnectionToStats(connectionID);
	}

	SafeChainIteratorOf<Replicator*> replicators(&allReplicators);
	Replicator *replicator;
	while ((replicator = replicators.GetCurrent()) != NULL)
	{
		Check_Object(replicator);
		Unregister_Object(replicator);
		delete replicator;
		replicators.First();
	}
}


//
//#############################################################################
//#############################################################################
//
void
	Connection::DeleteChildren(void)
{
	SafeChainIteratorOf<Replicator*> replicators(&allReplicators);
	Replicator *replicator;
	while ((replicator = replicators.GetCurrent()) != NULL)
	{
		Check_Object(replicator);
		Unregister_Object(replicator);
		delete replicator;
		replicators.First();
	}

	nextReplicatorID = ReplicatorID(connectionID);

	for (int i = 0; i < 8192; ++i)
	{
		usedConnections[i] = 0x0;
	}

	replicatorCount = 0;
}

//
//#############################################################################
//#############################################################################
//
void
	Connection::ReplicateMessageHandler(
		const Replicator::CreateMessage *message
	)
{
	Check_Object(this);
	Check_Object(message);
	Verify(message->messageID == ReplicateMessageID);

	//
	//-----------------------------------------------------------
	// Get the class data for the object to be replicated and the 
	// make method
	//-----------------------------------------------------------
	//
	RegisteredClass::ClassData *class_data =
		RegisteredClass::FindClassData(message->classID);
	Check_Object(class_data);
	Verify(class_data->IsDerivedFrom(Replicator::DefaultData));
	Replicator::Factory make_method = 
		Cast_Pointer(Replicator::ClassData*, class_data)->replicatorFactory;
	Check_Pointer(make_method);

	//
	//--------------------
	// Execute make method
	//--------------------
	//
	ReplicatorID base_id = message->replicatorID;
	(*make_method)(message, &base_id);
}

//
//#############################################################################
//#############################################################################
//
void
	Connection::ReplicatorMessageHandler(
		const Message *manager_message
	)
{
	Check_Object(this);
	Check_Object(manager_message);
	Verify(manager_message->messageID == ReplicatorMessageID);

	//
	//---------------------------
	// Get message for replicator
	//---------------------------
	//
	const Replicator::Message *replicator_message =
		reinterpret_cast<const Replicator::Message*>(
			reinterpret_cast<const char*>(manager_message)
			 + sizeof(*manager_message)
		);
	Check_Object(replicator_message);
	Verify(replicator_message->replicatorID != ReplicatorID::Null);

	#if defined(HUNT_BUG)
		SPEW((
			HUNT_BUG,
			"Received message for %d:%d",
			replicator_message->replicatorID.connectionID,
			replicator_message->replicatorID.localID
		));
	#endif

	//
	//--------------------
	// Find the replicator
	//--------------------
	//
	Replicator *replicator = FindReplicator(replicator_message->replicatorID);

	//
	//----------------------------------------------
	// If the replicator exists, send it the message
	//----------------------------------------------
	//
	if (replicator)
	{
		Check_Object(replicator);
		replicator->Receive(replicator_message);
	}
}

//
//#############################################################################
//#############################################################################
//
const ReplicatorID&
	Connection::GetNextReplicatorID()
{
    if (!this) {
        Check_Object(Connection::Hermit);
        return Connection::Hermit->GetNextReplicatorID();
    }
	Check_Object(this);


	++nextReplicatorID.localID;
	
	int loop_killer = 0;

	while (ISConnectionUsed(nextReplicatorID.localID))
	{
		++nextReplicatorID.localID;

		if (loop_killer > 65537)
			STOP(("No connections Left"));

		loop_killer++;
	}
	
	return nextReplicatorID;
}

//
//#############################################################################
//#############################################################################
//
void
	Connection::AddReplicator(Replicator *replicator)
{
	Check_Object(this);
	Check_Object(replicator);

	//
	//---------------------------------------------
	// Make sure that the replicator is safe to use
	//---------------------------------------------
	//
	Verify(!FindReplicator(replicator->GetReplicatorID()));
	allReplicators.Add(replicator);
	Verify(replicator->GetReplicatorID().connectionID == connectionID);
	if (replicator->GetReplicatorID().localID > nextReplicatorID.localID)
    {
		nextReplicatorID.localID = replicator->GetReplicatorID().localID;
    }


	ReplicatorCreated(replicator);

    if (g_pTempReplicators) { // jcem
        g_pTempReplicators->Add(replicator);
#ifdef _DEBUG
        gosASSERT(g_nMechLabs == 1);
#endif // _DEBUG
    } else {
#ifdef _DEBUG
        gosASSERT(g_nMechLabs <= 1);
#endif // _DEBUG
    }
}

//
//#############################################################################
//#############################################################################
//
void
	Connection::RemoveReplicator(Replicator *replicator)
{
	Check_Object(this);
	Check_Object(replicator);

	

	//
	//---------------------------------------------
	// Make sure that the replicator is safe to use
	//---------------------------------------------
	//

	ReplicatorDestroyed(replicator);


	Check_Object(FindReplicator(replicator->GetReplicatorID()));
	allReplicators.RemovePlug(replicator);


	replicator->owningConnection = NULL;
}

//
//#############################################################################
//#############################################################################
//
void
	Connection::ReplicatorCreated(
		Replicator *replicator
	)
{
	Check_Object(this);
	Check_Object(replicator);

	SetConnectionUsed(replicator->GetReplicatorID().localID);

	++replicatorCount;

#ifdef _ARMOR
	if (Stuff::ArmorLevel > 2)
	{
		Verify(allReplicators.GetSize() == replicatorCount);
	}
#endif

}

//
//#############################################################################
//#############################################################################
//
void
	Connection::ReplicatorDestroyed(Replicator *replicator)
{
	Check_Object(this);

	ClearConnectionUsed(replicator->GetReplicatorID().localID);

	--replicatorCount;

	#ifdef _ARMOR
	if (Stuff::ArmorLevel > 2)
	{
		Verify(allReplicators.GetSize()-1 == replicatorCount);
	}
#endif
}
//
//#############################################################################
//#############################################################################
//
void
	Connection::SetConnectionUsed(int connection)
{
	
	Verify(!ISConnectionUsed(connection));


	Check_Object(this);
	Verify(connection < 65536);

	int byte = connection>>3;
	int bit = connection&0x7;

	Verify(byte < 8192);

	usedConnections[byte] |= 0x1<<bit;
	

}

//
//#############################################################################
//#############################################################################
//
void
	Connection::ClearConnectionUsed(int connection)
{
	Check_Object(this);
	Verify(connection < 65536);

	Verify(ISConnectionUsed(connection));

	int byte = connection>>3;
	int bit = connection&0x7;
	
	Verify(byte < 8192);

	usedConnections[byte] &= ~(0x1<<bit);

	Verify(!ISConnectionUsed(connection));
}

//
//#############################################################################
//#############################################################################
//
bool
	Connection::ISConnectionUsed(int connection)
{
	Check_Object(this);
	Verify(connection < 65536);

	int byte = connection>>3;
	int bit = connection&0x7;

	Verify(byte < 8192);
	
	Check_Object(this);

	return (usedConnections[byte]&(0x1<<bit))?true:false;
}

//
//#############################################################################
//#############################################################################
//
void
	Connection::SendToMaster(
		Replicator *replicator,
		const Replicator::Message *replicator_message
	)
{
	Check_Object(this);
	Check_Object(replicator);
	Check_Object(replicator_message);

	Verify(replicator->GetReplicatorMode() == Replicator::ReplicantMode);
	Verify(replicator_message->replicatorID != ReplicatorID::Null);

	//
	//------------------------------------------------
	// Build a network message in dynamic build buffer
	//------------------------------------------------
	//
	#if defined(HUNT_BUG)
		SPEW((
			HUNT_BUG,
			"Sending message to master %d:%d",
			replicator_message->replicatorID.connectionID,
			replicator_message->replicatorID.localID
		));
	#endif
	size_t total_size =
		sizeof(Message) + replicator_message->messageLength;
	DynamicMemoryStream build_buffer(total_size);
	Message *manager_message =
		new (build_buffer.GetPointer()) Message(
			ReplicatorMessageID,
			total_size,
			0,
			replicator_message->messageFlags
		);
	Check_Object(manager_message);
	build_buffer.AdvancePointer(sizeof(*manager_message));
	Mem_Copy(
		build_buffer.GetPointer(),
		replicator_message,
		replicator_message->messageLength,
		build_buffer.GetBytesRemaining()
	);

	//
	//-------------
	// Send message
	//-------------
	//
	Send(manager_message, replicator->owningConnection);
}

//
//#############################################################################
//#############################################################################
//
void
	Connection::BroadcastToReplicants(
		Replicator *replicator,
		const Replicator::Message *replicator_message
	)
{
	Check_Object(this);
	Check_Object(replicator);
	Check_Object(replicator_message);

	Verify(replicator->GetReplicatorMode() == Replicator::MasterMode);
	Verify(replicator_message->replicatorID != ReplicatorID::Null);
	#if defined(HUNT_BUG)
		SPEW((
			HUNT_BUG,
			"Sending message to replicants of %d:%d",
			replicator_message->replicatorID.connectionID,
			replicator_message->replicatorID.localID
		));
	#endif

	//
	//------------------------------------------------
	// Build a network message in dynamic build buffer
	//------------------------------------------------
	//
	size_t total_size =
		sizeof(Message) + replicator_message->messageLength;
	DynamicMemoryStream build_buffer(total_size);
	Message *manager_message =
		new (build_buffer.GetPointer()) Message(
			ReplicatorMessageID,
			total_size,
			0,
			replicator_message->messageFlags
		);
	Check_Object(manager_message);
	build_buffer.AdvancePointer(sizeof(*manager_message));
	Mem_Copy(
		build_buffer.GetPointer(),
		replicator_message,
		replicator_message->messageLength,
		build_buffer.GetBytesRemaining()
	);

	//
	//-------------
	// Send message
	//-------------
	//
	ExclusiveBroadcast(manager_message);
}

//
//#############################################################################
//#############################################################################
//
Replicator*
	Connection::FindReplicator(const ReplicatorID &id)
{
	Check_Object(this);
	Check_Object(&id);
	Connection *connection;
	connection = this;

	if(id.connectionID != connectionID)
	{
		Check_Object(Network::GetInstance());
		connection = Network::GetInstance()->GetConnection(id.connectionID);
	}
	//
	//--------------------------------------------------------------------
	// For now, we will spin through the loop.  This will not be good soon
	//--------------------------------------------------------------------
	//
	SafeChainIteratorOf<Replicator*> replicators(&connection->allReplicators);
	Replicator *replicator;
	while ((replicator = replicators.ReadAndNext()) != NULL)
	{
		Check_Object(replicator);
		if (replicator->GetReplicatorID() == id)
			return replicator;
	}
	return NULL;
}

void Connection::DeleteReplicator(Replicator* p)
{
	delete p;
}
