#pragma once

#include "l4net.h"
#include "l4app.h"
#include "..\munga\spooler.h"
#include "..\munga\interest.h"
#include "..\munga\apptask.h"

//##########################################################################
//####################   SpoolingInterestManager   #########################
//##########################################################################

class SpoolingInterestManager:
	public InterestManager
{
public:
	SpoolingInterestManager();
	~SpoolingInterestManager();

	void
		LoadInterestArenas(Mission *mission);
	void
		LoadMission(Mission *mission);
	void
		ReceiveNetworkPacket(
			NetworkPacket *packet,
			Receiver::Message *packet_message
		);
	void
		Shutdown();
};

//##########################################################################
//###################   L4SpoolingNetworkManager   #########################
//##########################################################################

class L4SpoolingNetworkManager:
	public L4NetworkManager
{
public:
	L4SpoolingNetworkManager();
	~L4SpoolingNetworkManager();

	void
		ReceiveNetworkPacket(
			NetworkPacket *packet,
			Receiver::Message *packet_message
		);
	void
		StartConnecting(Mission *mission);
};

//##########################################################################
//###################   L4PlaybackNetworkManager   #########################
//##########################################################################

class L4PlaybackNetworkManager:
	public NetworkManager
{
public:
	L4PlaybackNetworkManager();
	~L4PlaybackNetworkManager();

	void
		StartConnecting(Mission *mission);

	Logical
		Shutdown();

	Logical
		CheckBuffers(NetworkPacket*);
};

//##########################################################################
//###################    L4SpoolingApplication    ##########################
//##########################################################################

class L4SpoolingApplication:
	public L4Application
{
public:
	L4SpoolingApplication(
		HINSTANCE hInstance,
		HWND hWnd,
		ResourceFile *resource,
     ApplicationID application_ID
	);
	~L4SpoolingApplication();

	SpoolingInterestManager*
		GetInterestManager()
			{
				return
					(SpoolingInterestManager*)Application::GetInterestManager();
			}

	L4SpoolingNetworkManager*
		GetNetworkManager()
			{
				return
					(L4SpoolingNetworkManager*)Application::GetNetworkManager();
			}

	MissionReviewApplicationManager*
		GetApplicationManager()
			{
				return
					(MissionReviewApplicationManager*)
						Application::GetApplicationManager();
			}

protected:
	Registry*
		MakeRegistry();
	InterestManager*
		MakeInterestManager();
	NetworkManager*
		MakeNetworkManager();

	Mission*
		MakeMission(
			NotationFile *notation_file,
			ResourceFile *resources
		);

	VideoRenderer*
		MakeVideoRenderer();
	AudioRenderer*
		MakeAudioRenderer();
	GaugeRenderer*
		MakeGaugeRenderer(int *secondaryIndex, int *aux1Index, int *aux2Index);

	Entity*
		MakeViewpointEntity(Entity__MakeMessage *);

	void
		Initialize();
	void
		LoadBackgroundTasks();
	Logical
		Shutdown(int remainingApps);


	void
		ReceiveNetworkPacket(
			NetworkPacket *packet,
			Receiver::Message *packet_message
		);

	Logical
		ExecuteForeground(
			Time start_of_frame,
			Scalar frame_duration
		);
	void
		ExecuteBackgroundTask();

protected:
	Logical
		missionSpooled;

public:
	static Derivation *GetClassDerivations();
	static SharedData DefaultData;

	static const HandlerEntry
		MessageHandlerEntries[];
	//static MessageHandlerSet MessageHandlers;
	static MessageHandlerSet& GetMessageHandlers();

	void
		LoadMissionMessageHandler(Message *message);
	void
		RunMissionMessageHandler(RunMissionMessage *message);
	void
		StopMissionMessageHandler(StopMissionMessage *message);
	void
		AbortMissionMessageHandler(AbortMissionMessage *message);

	Logical
  	TestInstance() const;
};

extern L4SpoolingApplication * &l4_spooling_application;

//##########################################################################
//########################    SpoolerTask    ###############################
//##########################################################################

class SpoolerTask:
	public ApplicationTask
{
public:
	SpoolerTask();
	~SpoolerTask();

	void
		Execute();

	virtual void
		DispatchPacket(NetworkPacket *packet);
	virtual long
		GetTimeBias();
};
