/* -----------------------------------------------------------------------------
	GSFramework
	Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
----------------------------------------------------------------------------- */


#ifndef	__NIONETCLIENTWORKERTHREAD__
#define	__NIONETCLIENTWORKERTHREAD__


		#include "network_enet/enet_network.h"
		#include "filesystem/io_handle.h"
		#include "container/narray.h"
		#include "container/nlist.h"
		#include "nstring/nstring.h"
		#include "thread/thread.h"
		#include "thread/mutex.h"


namespace GS {
	namespace IO {

//-----------------------------------------------------------------------------
struct	NetWorkerBaseTask
{
enum TaskType
{	TypeOpen = 0, TypeClose, TypeSeek, TypeTell, TypeRead, TypeHash	};

		TaskType	type;

		// [EJ] a full memory barrier is required when accessing these two variables
		Threading::Atomic32 processed;
		Threading::Atomic32 success;
};
struct	NetWorkerOpenTask : public NetWorkerBaseTask
{
		String		path;
		Mode		mode;
		NetWorkerOpenTask(const char *p, Mode m) : path(p), mode(m) { type = TypeOpen; }
		int			handle;
};
struct	NetWorkerCloseTask : public NetWorkerBaseTask
{
		int			handle;
		NetWorkerCloseTask(int h) : handle(h) { type = TypeClose; }
};
struct	NetWorkerSeekTask : public NetWorkerBaseTask
{
		int			handle;
		ptrdiff_t	offset;
		Base::SeekRef seek_ref;
		NetWorkerSeekTask(int h, ptrdiff_t o, Base::SeekRef ref) : handle(h), offset(o), seek_ref(ref) { type = TypeSeek; }
		size_t		pos;
};
struct	NetWorkerTellTask : public NetWorkerBaseTask
{
		int			handle;
		NetWorkerTellTask(int h) : handle(h) { type = TypeTell; }
		size_t		pos;
};
struct	NetWorkerReadTask : public NetWorkerBaseTask
{
		int			handle;
		void		*data;
		size_t		size;
		NetWorkerReadTask(int h, void *p, size_t s) : handle(h), data(p), size(s) { type = TypeRead; }
		size_t		read_size;
};
struct	NetWorkerHashTask : public NetWorkerBaseTask
{
		String		path;
		NetWorkerHashTask(const char *p) : path(p) { type = TypeHash; }
		String		hash;
};
//-----------------------------------------------------------------------------

/*
	@short	I/O Network worker thread.
	@author	Emmanuel Julien (ejulien@owloh.com)
*/
class	NetWorkerThread : public Threading::Thread, public Network::Enet
{
		String		ip;
		int			port;

		void		*server_peer;
		int			handshaking;

		Array <char> response;
		bool		WaitServerResponse();
		void		ClearServerResponse();

		void		ProcessIOPacket(const void *, size_t);

virtual	void		OnPeerConnection(void *peer);
virtual	void		OnPacketReceived(void *peer, const void *, size_t);
virtual	void		OnConnectionClosed(void *peer);

virtual	void		Execute();

		Threading::Mutex task_mutex;
		List <NetWorkerBaseTask *> task_queue;

		bool		ProcessOpenTask(NetWorkerOpenTask &);
		bool		ProcessCloseTask(NetWorkerCloseTask &);
		bool		ProcessSeekTask(NetWorkerSeekTask &);
		bool		ProcessTellTask(NetWorkerTellTask &);
		bool		ProcessReadTask(NetWorkerReadTask &);
		bool		ProcessHashTask(NetWorkerHashTask &);
		void		ProcessTask(NetWorkerBaseTask &);

		Threading::Atomic32 running;

public:

		bool		IsConnected() const { return asbool(server_peer); }

		bool		QueueTask(NetWorkerBaseTask &);
		bool		CancelTask(NetWorkerBaseTask &);

		bool		Start(const char *ip, int port);
		void		Stop();

		NetWorkerThread();
};

	} // IO
} // GS


#endif	// __NIONETCLIENTWORKERTHREAD__
