#include "munga.h"
#pragma hdrstop

#include "simulate.h"
#include "update.h"
#include "app.h"

#if defined(TRACE_EXECUTE_WATCHERS)
	static BitTrace Execute_Watchers("Execute Watchers");
	#define SET_EXECUTE_WATCHERS() Execute_Watchers.Set()
	#define CLEAR_EXECUTE_WATCHERS() Execute_Watchers.Clear()
#else
	#define SET_EXECUTE_WATCHERS()
	#define CLEAR_EXECUTE_WATCHERS()
#endif

//#############################################################################
//########################    StateIndicator    ###############################
//#############################################################################

//#############################################################################
// Construction and Destruction
//

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateIndicator::StateIndicator():
	audioWatcherSocket(NULL),
	videoWatcherSocket(NULL),
	gaugeWatcherSocket(NULL)
{
	Check_Pointer(this);
	stateCount = 0;
	oldState = 0;
	currentState = 0;
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateIndicator::StateIndicator(unsigned max_states):
	audioWatcherSocket(NULL),
	videoWatcherSocket(NULL),
	gaugeWatcherSocket(NULL)
{
	Check_Pointer(this);
	stateCount = max_states;
	oldState = max_states;
	currentState = max_states;
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateIndicator::StateIndicator(const StateIndicator &state_indicator):
	audioWatcherSocket(NULL),
	videoWatcherSocket(NULL),
	gaugeWatcherSocket(NULL)
{
	Check_Pointer(this);

	// Do not perform deep copy of watchers
	stateCount = state_indicator.stateCount;
	oldState = state_indicator.oldState;
	currentState = state_indicator.currentState;
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateIndicator::~StateIndicator()
{
	Check(this);

	//
	// Manual deletion of existing watchers
	//
	{
		SChainIteratorOf<Component*> iterator(&audioWatcherSocket);
		#if DEBUG_LEVEL>2
			Component *component;
			while ((component = iterator.ReadAndNext()) != NULL)
			{
				Check(component);
				Dump(component->GetClassID());
			}
			Warn(iterator.GetSize() != 0);
		#endif
		iterator.DeletePlugs();
	}
	{
		SChainIteratorOf<Component*> iterator(&videoWatcherSocket);
		#if DEBUG_LEVEL>2
			Component *component;
			while ((component = iterator.ReadAndNext()) != NULL)
			{
				Check(component);
				Dump(component->GetClassID());
			}
			Warn(iterator.GetSize() != 0);
		#endif
		iterator.DeletePlugs();
	}
	{
		SChainIteratorOf<Component*> iterator(&gaugeWatcherSocket);
		#if DEBUG_LEVEL>2
			Component *component;
			while ((component = iterator.ReadAndNext()) != NULL)
			{
				Check(component);
				Dump(component->GetClassID());
			}
			Warn(iterator.GetSize() != 0);
		#endif
		iterator.DeletePlugs();
	}
	Check_Fpu();
}

//#############################################################################
// State stuff
//

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
StateIndicator&
	StateIndicator::operator=(const StateIndicator &state_indicator)
{
	// Do not perform assignment of watchers
	stateCount = state_indicator.stateCount;
	oldState = state_indicator.oldState;
	currentState = state_indicator.currentState;

	Check_Fpu();
	return *this;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
	StateIndicator::operator==(const StateIndicator &state_indicator) const
{
	Check_Fpu();
	return
	(
		stateCount == state_indicator.stateCount &&
		oldState == state_indicator.oldState &&
		currentState == state_indicator.currentState
	);
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	StateIndicator::SetState(unsigned new_state)
{
	Check(this);
	Verify(new_state < stateCount);

	//
	//--------------------------------------------------------------------------
	// See if the state really changes
	//
	// NOTE - the old state does change to the current state, simulating a loop
	//        in the state engine.  If it turns out that someone is watching the
	//        level of the state indicator and doing their own edge detection,
	//        this might possibly maybe screw something up
	//--------------------------------------------------------------------------
	//
	oldState = currentState;
	if (new_state == currentState)
	{
		return;
	}

	//
	//-------------------------------------------------------------------
	// If the state has changed, update the state values and then run any
	// watchers
	//-------------------------------------------------------------------
	//
	currentState = new_state;
	Component *watcher;

	SET_EXECUTE_WATCHERS();

	// Audio
	{
		SChainIteratorOf<Component*> iterator(audioWatcherSocket);
		Check(&iterator);
		while ((watcher = iterator.ReadAndNext()) != NULL)
		{
			watcher->Execute();
		}
	}

	// Video
	{
		SChainIteratorOf<Component*> iterator(videoWatcherSocket);
		Check(&iterator);
		while ((watcher = iterator.ReadAndNext()) != NULL)
		{
			watcher->Execute();
		}
	}

	// Gauge
	{
		SChainIteratorOf<Component*> iterator(gaugeWatcherSocket);
		Check(&iterator);
		while ((watcher = iterator.ReadAndNext()) != NULL)
		{
			watcher->Execute();
		}
	}

	CLEAR_EXECUTE_WATCHERS();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
std::ostream& operator << (std::ostream &strm, const StateIndicator &state_indicator)
{
   Check(&state_indicator);

   strm << "[" << state_indicator.stateCount << ",";
   strm << state_indicator.oldState << ",";
   strm << state_indicator.currentState << "]";

	return strm;
}

//#############################################################################
// Test Support
//
Logical
	StateIndicator::TestInstance() const
{
	return True;
}

//#############################################################################
//##########################    Simulation    #################################
//#############################################################################

//#############################################################################
// Virtual Data support
//
Derivation* Simulation::GetClassDerivations()
{
	static Derivation classDerivations(Receiver::GetClassDerivations(), "Simulation");
	return &classDerivations;
}

Simulation::SharedData
	Simulation::DefaultData(
		Simulation::GetClassDerivations(),
		Simulation::GetMessageHandlers(),
		Simulation::GetAttributeIndex(),
      Simulation::StateCount
	);

//#############################################################################
// Model support
//

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//##########################################################################
// Net clock - see SIMULATE.h for why the sender's timestamp is estimated
// rather than used as it stands.
//##########################################################################

namespace
{
	enum
	{
		netClockMaxPeers = 16,

		// Samples per rolling minimum. A peer sends one record per
		// simulation per frame, so at eight vehicles and 60 fps this is
		// well under a second - fast enough to follow a route change,
		// long enough that the minimum means something.
		netClockWindow = 128,

		// The furthest back we will believe a timestamp. Beyond this the
		// packet is stale or the estimate is wrong, and extrapolating a
		// vehicle half a second forward does more harm than the lag we
		// are correcting.
		netClockMaxLagTicks = 500
	};

	struct PeerClock
	{
		HostID	host;
		Logical	inUse;
		Logical	settled;
		long	offsetTicks;		// our clock - their clock
		long	windowMinTicks;
		int		windowCount;
	};

	PeerClock	gPeerClocks[netClockMaxPeers];
	HostID		gUpdateSender = 0;
	Logical		gUpdateSenderValid = False;

	Logical NetClockEnabled()
	{
		static int enabled = -1;
		if (enabled < 0)
		{
			const char *setting = getenv("RP412NETCLOCK");
			enabled = (setting != NULL && atoi(setting) == 0) ? 0 : 1;
			if (!enabled)
			{
				DEBUG_STREAM << "NetClock: disabled by RP412NETCLOCK=0 - "
					<< "replicants dead-reckon from arrival time\n" << std::flush;
			}
		}
		return enabled ? True : False;
	}

	PeerClock *FindPeer(HostID host)
	{
		PeerClock *free_slot = NULL;
		for (int i = 0; i < netClockMaxPeers; ++i)
		{
			if (gPeerClocks[i].inUse)
			{
				if (gPeerClocks[i].host == host)
				{
					return &gPeerClocks[i];
				}
			}
			else if (free_slot == NULL)
			{
				free_slot = &gPeerClocks[i];
			}
		}
		if (free_slot != NULL)
		{
			free_slot->inUse = True;
			free_slot->host = host;
			free_slot->settled = False;
			free_slot->offsetTicks = 0;
			free_slot->windowMinTicks = 0;
			free_slot->windowCount = 0;
		}
		return free_slot;
	}
}

void NetClock_BeginUpdate(HostID sender)
{
	gUpdateSender = sender;
	gUpdateSenderValid = True;
}

void NetClock_EndUpdate()
{
	gUpdateSenderValid = False;
}

void NetClock_Reset()
{
	memset(gPeerClocks, 0, sizeof(gPeerClocks));
	gUpdateSenderValid = False;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Simulation::ReadUpdateRecord(UpdateRecord *message)
{
	Check(this);
	Check_Pointer(message);

	//
	//------------------------------------------------------------------
	// When this update arrived is not when it was taken. Put lastUpdate
	// at the sender's sampling moment, expressed in our clock, so the
	// dead reckoner extrapolates over the network latency instead of
	// starting from scratch once it has already elapsed.
	//------------------------------------------------------------------
	//
	long now_ticks = Now().ticks;
	long local_ticks = now_ticks;

	PeerClock *peer = gUpdateSenderValid && NetClockEnabled()
		? FindPeer(gUpdateSender) : NULL;
	if (peer != NULL)
	{
		//
		// sample = trueOffset + oneWayLatency, so the running minimum
		// converges on the offset from above.
		//
		long sample = now_ticks - message->timeStamp.ticks;

		if (!peer->settled)
		{
			peer->settled = True;
			peer->offsetTicks = sample;
			peer->windowMinTicks = sample;
			peer->windowCount = 0;
			DEBUG_STREAM << "NetClock: host " << peer->host
				<< " first sample, offset " << sample << " ms\n" << std::flush;
		}
		else
		{
			if (sample < peer->windowMinTicks)
			{
				peer->windowMinTicks = sample;
			}
			if (sample < peer->offsetTicks)
			{
				peer->offsetTicks = sample;		// a shorter path: believe it now
			}
			if (++peer->windowCount >= netClockWindow)
			{
				//
				// Close the window: adopt its minimum even if it is
				// LARGER than the running estimate, which is how the
				// figure follows clock drift and a route that got
				// slower rather than staying pinned to one old packet.
				//
				long moved = peer->windowMinTicks - peer->offsetTicks;
				if (moved > 50 || moved < -50)
				{
					DEBUG_STREAM << "NetClock: host " << peer->host
						<< " offset " << peer->offsetTicks << " -> "
						<< peer->windowMinTicks << " ms\n" << std::flush;
				}
				peer->offsetTicks = peer->windowMinTicks;
				peer->windowMinTicks = sample;
				peer->windowCount = 0;
			}
		}

		local_ticks = message->timeStamp.ticks + peer->offsetTicks;

		//
		// Never ahead of our own clock, and never further back than we
		// are willing to extrapolate.
		//
		if (local_ticks > now_ticks)
		{
			local_ticks = now_ticks;
		}
		else if (now_ticks - local_ticks > netClockMaxLagTicks)
		{
			local_ticks = now_ticks - netClockMaxLagTicks;
		}
	}

	lastUpdate.ticks = local_ticks;
	SetSimulationState(message->simulationState);
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Simulation::WriteUpdateRecord(
		UpdateRecord *message,
		int update_model
	)
{
	Check(this);
	Check_Pointer(message);

	message->timeStamp = lastPerformance;
	message->simulationState = GetSimulationState();
	message->recordLength = sizeof(*message);
	message->recordID = (Word)update_model;
	lastUpdate = lastPerformance;
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Simulation::WriteSimulationUpdate(MemoryStream *update_stream)
{
	Check(this);
	Check(update_stream);

	//
	//-----------------
	// Write the update
	//-----------------
	//
	int bit=0;
	int update_model = updateModel;
	updateModel = 0;
	while (update_model)
	{
		
		if (update_model & 1)
		{
			UpdateRecord* update = (UpdateRecord*)update_stream->GetPointer();
			WriteUpdateRecord(update, bit);
			update_stream->AdvancePointer(update->recordLength);
		}
		update_model >>= 1;
		++bit;
	}
	Check_Fpu();
}

//#############################################################################
// Construction and Destruction
//

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Simulation::Simulation(
	Simulation::ClassID class_ID,
	Simulation::SharedData &virtual_data
):
	Receiver(class_ID, virtual_data),
	simulationState(GetSharedData()->stateCount),
	audioWatcherSocket(NULL),
	videoWatcherSocket(NULL),
	gaugeWatcherSocket(NULL),
   effectWatcherSocket(NULL)
{
	Check_Pointer(this);

	SetSimulationState(DefaultState);
	lastPerformance = Now();
	lastUpdate = lastPerformance;
	activePerformance = &Simulation::DoNothingOnce;
	updateModel = 0;
   simulationFlags = 0;
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Simulation::~Simulation()
{
	Check(this);

	//
	// Watchers should be deleted by renderers by now
	//
	#if DEBUG_LEVEL>0
		{
			SChainIteratorOf<Component*> iterator(&audioWatcherSocket);
			Verify(iterator.GetSize() == 0);
		}
		{
			SChainIteratorOf<Component*> iterator(&videoWatcherSocket);
			Verify(iterator.GetSize() == 0);
		}
		{
			SChainIteratorOf<Component*> iterator(&gaugeWatcherSocket);
			Verify(iterator.GetSize() == 0);
		}
	#endif
	Check_Fpu();
}

//#############################################################################
// Attribute Support
//
const Simulation::AttributePointer
	Simulation::NullAttribute = NULL;

const Simulation::IndexEntry
	Simulation::AttributePointers[]=
{
	{
		Simulation::SimulationStateAttributeID,
		"SimulationState",
		(Simulation::AttributePointer)&Simulation::simulationState
	}
};

Simulation::AttributeIndexSet& Simulation::GetAttributeIndex()
{
	static Simulation::AttributeIndexSet attributeIndex(ELEMENTS(Simulation::AttributePointers),
		Simulation::AttributePointers
	);
	return attributeIndex;
}

void*
	Simulation::GetAttributePointer(Simulation::AttributeID attribute)
{
	Check(this);

	AttributePointer attr =
		GetSharedData()->activeAttributeIndex->Find(attribute);
	Check_Fpu();
	if (attr == NullAttribute)
	{
		return NULL;
	}
	else
	{
		return &(this->*attr);
	}
}

void*
	Simulation::GetAttributePointer(const char* attribute_name)
{
	Check(this);

	AttributePointer attr =
		GetSharedData()->activeAttributeIndex->Find(attribute_name);
	Check_Fpu();
	if (attr == NullAttribute)
	{
		return NULL;
	}
	else
	{
		return &(this->*attr);
	}
}

//#############################################################################
// Simulation Support
//
void
	Simulation::PerformAndWatch(
		const Time& till,
		MemoryStream *update_stream
	)
{
	Check(this);
	Check(&till);

	Scalar slice = till - lastPerformance;
	lastPerformance = till;

	Perform(slice);
	if (!AreWatchersDelayed())
	{
		ExecuteWatchers();
	}
	WriteSimulationUpdate(update_stream);

	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Simulation::DoNothingOnce(Scalar)
{
	NeverExecute();
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Simulation::DoNothing(Scalar)
{
	Check_Fpu();
}

//#############################################################################
// Watcher Support
//
void
	Simulation::ExecuteWatchers()
{
	SET_EXECUTE_WATCHERS();

	Component *watcher;

	// Audio
	{
		SChainIteratorOf<Component*> iterator(audioWatcherSocket);
		while ((watcher = iterator.ReadAndNext()) != NULL)
		{
			watcher->Execute();
		}
	}

	// Video
	{
		SChainIteratorOf<Component*> iterator(videoWatcherSocket);
		while ((watcher = iterator.ReadAndNext()) != NULL)
		{
			watcher->Execute();
		}
	}

	// Gauge
	{
		SChainIteratorOf<Component*> iterator(gaugeWatcherSocket);
		while ((watcher = iterator.ReadAndNext()) != NULL)
		{
			watcher->Execute();
		}
	}

	// Effect
	{
		SChainIteratorOf<Component*> iterator(effectWatcherSocket);
		while ((watcher = iterator.ReadAndNext()) != NULL)
		{
			watcher->Execute();
		}
	}
	CLEAR_EXECUTE_WATCHERS();
}

//#############################################################################
// Test Support
//

Logical
	Simulation::TestInstance() const
{
	return IsDerivedFrom(*GetClassDerivations());
}

//#############################################################################
//###################    Simulation::AttributeIndexSet    #####################
//#############################################################################

const Simulation::AttributeIndexSet
	Simulation::AttributeIndexSet::NullSet;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Simulation__AttributeIndexSet::~Simulation__AttributeIndexSet()
{
	if (attributeIndex)
	{
		Unregister_Pointer(attributeIndex);
		delete[] attributeIndex;
	}
};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
	Simulation::AttributeIndexSet::Build(
		Simulation::AttributeID count,
		const Simulation::IndexEntry index_table[],
		const Simulation::AttributeIndexSet *inheritance
	)
{
	//
	//-------------------------------------------------------
	// Find out the highest message type we have to deal with
	//-------------------------------------------------------
	//
	Check(this);
	Check_Pointer(index_table);
	entryCount = 0;
	Simulation::AttributeID i;
	for (i=0; i<count; ++i)
	{
		if (index_table[i].entryID > entryCount)
		{
			entryCount = index_table[i].entryID;
		}
	}
	if (inheritance)
	{
		Check(inheritance);
		if (entryCount<inheritance->entryCount)
		{
			entryCount = inheritance->entryCount;
		}
		#if DEBUG_LEVEL>0
		else if (entryCount > inheritance->entryCount)
		{
			i = inheritance->entryCount+1;
			goto Check_Table;
		}
		#endif
	}
	else
	{
		Verify(entryCount == count);
		#if DEBUG_LEVEL>0
		i = 1;
Check_Table:
			while (i <= entryCount)
			{
				int j;
				for (j=0; j<count; ++j)
				{
					if (index_table[j].entryID == i)
					{
						break;
					}
				}
				if (j == count)
				{
					break;
				}
	    ++i;
			}
			Verify(i > count);
		#endif
	}

	//
	//-----------------------------------------------------------------------
	// Allocate the memory for the new handler set, and copy the inherited
	// handlers to the new table.  We are guaranteed to have enough space for
	// the inherited table
	//-----------------------------------------------------------------------
	//
	attributeIndex = new Simulation::IndexEntry[entryCount];
	Check_Pointer(attributeIndex);
	Register_Pointer(attributeIndex);
	i = 0;
	if (inheritance)
	{
		for (; i<inheritance->entryCount; ++i)
		{
			attributeIndex[i] = inheritance->attributeIndex[i];
		}
	}

	//
	//----------------------------------------------------------------------
	// Step through the new table supplied, placing each handler in the slot
	// determined by the message type
	//----------------------------------------------------------------------
	//
	for (i=0; i<count; ++i)
	{
		Verify(!inheritance || index_table[i].entryID > inheritance->entryCount);
		attributeIndex[index_table[i].entryID-1] = index_table[i];
	}
	Check_Fpu();
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Simulation::AttributePointer
	Simulation::AttributeIndexSet::Find(const char* attribute_name) const
{
	Check(this);
	Check_Pointer(attribute_name);

	for (int attribute=0; attribute<entryCount; ++attribute)
	{
		if (!strcmp(attribute_name, attributeIndex[attribute].entryName))
		{
			Check_Fpu();
			return attributeIndex[attribute].entryAddress;
		}
	}
	Check_Fpu();
	return Simulation::NullAttribute;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
const Simulation::IndexEntry*
	Simulation::AttributeIndexSet::FindEntry(const char* attribute_name) const
{
	Check(this);
	Check_Pointer(attribute_name);

	for (int attribute=0; attribute<entryCount; ++attribute)
	{
		if (!strcmp(attribute_name, attributeIndex[attribute].entryName))
		{
			Check_Fpu();
			return &attributeIndex[attribute];
		}
	}
	Check_Fpu();
	return NULL;
}

void
	Simulation::RequestEncore(Encore encore)
{
	Check(this);
	SetWatcherDelay();

	Check(application);
	UpdateManager *updater = application->GetUpdateManager();
	Check(updater);
	updater->RequestEncore(this, encore);
}

#if defined(TEST_CLASS) && 0
	#include "model.tcp"
#endif
