/*
	NetworkRequest.hpp
	Author: Patrick Baggett <ptbaggett@762studios.com>, James Russell <jcrussell@762studios.com>
	Created: 12/03/2013
 
	Purpose: 
 
	Cancel-able network thread request, similar to ZThreadRequest, but
	with more cancellation points.

	Used to communicate between any other thread and the NetworkService 
	thread. The "payload" field contains the message's data, and the event 
	is used to cancel and signal when the request has been handled. For some 
	requests, no response is required; these are called "responseless" and 
	have no SST_Event object associated. Obviously, they cannot be waited on 
	nor canceled -- they are simply "fire and forget".
 
	License:
 
	Copyright 2013, 762 Studios.
 
*/

#ifndef __ZNETWORKREQUEST_HPP
#define __ZNETWORKREQUEST_HPP

#include <SST/SST_Concurrency.h>

class ZNetworkRequest
{
public:
	// result enumeration
	enum RequestResult {
		RESULT_CANCELED,		// nope
		RESULT_FINISHED,		// yep
		RESULT_INPROGRESS		// go away
	};

	// type enumeration
	enum RequestType {
		REQUEST_CONNECT,		// connect to another simulation
		REQUEST_DISCONNECT,		// disconnect from a server
		REQUEST_RESET,			// immediately disconnect (no notice)
		REQUEST_STOP_NETWORK,	// stop the network thread
	};

	// public member variables
	uint8_t		  Payload[64];	// generic data payload, used to input data and read results back
	RequestType	  Type;			// request type
	RequestResult Result;		// in progress, success, or failure

	// c'tor
	ZNetworkRequest(RequestType type, bool needEvent = true)	
		: Type(type), Result(RESULT_INPROGRESS) {
		FinishedEvent = needEvent ? SST_Concurrency_CreateEvent() : NULL;
		SST_Atomic_StoreRelease(&Canceled, 0);			
	}
	
	// d'tor
	~ZNetworkRequest() {
		if (FinishedEvent) {
			SST_Concurrency_DestroyEvent(FinishedEvent);
		}
	}

	// getters
	bool IsResponseless()	{ return (FinishedEvent == NULL); }
	bool WaitFinished()		{ return (SST_Concurrency_WaitEvent(FinishedEvent, SST_WAIT_INFINITE) != 0); }
	bool CheckFinished()	{ return (SST_Concurrency_WaitEvent(FinishedEvent, 0) != 0); }
	void Cancel()			{ Canceled = 1; }
	bool IsCancelPending()	{ return (Canceled != 0); }

	// used to signal the request should be finished or canceled
	void MarkFinished() { Result = RESULT_FINISHED; SST_Concurrency_SignalEvent(FinishedEvent); }
	void MarkCanceled() { Result = RESULT_CANCELED; SST_Concurrency_SignalEvent(FinishedEvent); }

private:
	SST_Event	 FinishedEvent;	// when signaled, the request has been completed
	volatile int Canceled;		// when non-zero, the network thread will not attempt to process it
};

#endif
