/*
	ZNetworkUpdateStream.hpp
	Author: James Russell <jcrussell@762studios.com>
	Created: 9/13/2015

	Purpose: 

	Exists for the express purpose of holding onto network events and property updates 
	that the simulation wants to send out, and providing them to the network system when
	the network system requires them.

	In addition, holds onto network events and updates received until the simulation asks 
	for them.

	License:

	TODO

*/

#pragma once

#ifndef _ZNETWORKUPDATESTREAM_HPP
#define _ZNETWORKUPDATESTREAM_HPP

#include <ZSTL/ZArray.hpp>
#include <ZUtil/ZUtil.hpp>

#include "ZNetworkEvent.hpp"
#include "ZPropertyBufferUpdate.hpp"

// forward decl
class ZSimulation;

// typedefs
typedef ZArray<ZNetworkEvent*, ZArrayAllocator<ZNetworkEvent*, 128>>				  NetworkEventQueue;
typedef ZArray<ZPropertyBufferUpdate*, ZArrayAllocator<ZPropertyBufferUpdate*, 1024>> NetworkUpdateQueue;

// class decl
class ZNetworkUpdateStream {
public:

	// event constructor and destructor function
	typedef ZNetworkEvent* (*EventConstructor)();
	typedef void (*EventDestructor)(ZNetworkEvent*);

	// c'tor
	ZNetworkUpdateStream();

	// d'tor
	~ZNetworkUpdateStream();

	/*
	Maps an event type to an event constructor and destructor.  Events will not be properly recreated
	unless the type is mapped to a constructor function.
	*/
	void MapEventAlloc(nID type, EventConstructor ctor, EventDestructor dtor);

	/*
	Allocator for events and updates.  The version without id will be called by the network
	system - the deserialize method will fill out the id.
	*/
	ZNetworkEvent*		   AllocEvent(nID type);
	ZPropertyBufferUpdate* AllocUpdate(eID id);
	ZPropertyBufferUpdate* AllocUpdate();
	
	/*
	Deallocation for events and updates.
	*/
	void DeallocEvent(ZNetworkEvent* e);
	void DeallocUpdate(ZPropertyBufferUpdate* u);

	/*
	Enqueues an event or update to sync across the network.
	*/
	void EnqueueOutgoingEvent(ZNetworkEvent* e);
	void EnqueueOutgoingUpdate(ZPropertyBufferUpdate* u);
	void EnqueueOutgoingUpdates(NetworkUpdateQueue& q);

	/*
	Enqueues an event or update to be processed here.
	*/
	void EnqueueIncomingEvent(ZNetworkEvent* e);
	void EnqueueIncomingEvents(NetworkEventQueue& q);
	void EnqueueIncomingUpdate(ZPropertyBufferUpdate* u);
	void EnqueueIncomingUpdates(NetworkUpdateQueue& q);

	/*
	Read outgoing events or updates to sync across the network.
	*/
	void ReadOutgoingEvents(NetworkEventQueue& out);
	void ReadOutgoingUpdates(NetworkUpdateQueue& out);

	/*
	Processes events or updates that have been enqueued.
	*/
	void ProcessIncomingEvents(ZSimulation& sim);
	void ProcessIncomingUpdates(ZSimulation& sim);

private:
	DISABLE_COPY_AND_ASSIGN(ZNetworkUpdateStream);

	ZMutex			   EventMutex[2];	// mutex for event queues (incoming / outgoing)
	ZMutex			   UpdateMutex[2];	// mutex for update queues (incoming / outgoing)

	NetworkEventQueue  Events[2];		// buffered events (incoming / outgoing)
	NetworkUpdateQueue Updates[2];		// buffered updates (incoming / outgoing)

	ZHashMap<nID, 
		ZPair<EventConstructor, EventDestructor>> Constructors; // ctor and dtor for network events
};


#endif