#ifndef __WHITTED_TRACER_WORKER_H__
#define __WHITTED_TRACER_WORKER_H__

#include <queue>
#include <wx/thread.h>
#include "3dmath.h"
#include "RayStream.h"
#include "Random.h"
#include "AbstractSampler.h"
#include "RenderTileData.h"
#include "RayCaster.h"

#define COMPUTE_LUMINANCE 0

namespace VRUT
{

	class WhittedRenderer;

	// class RayTracingThread is worker for RayTracer rendering
	class WhittedRendererWorker : public wxThread
	{

	private:

		// instance of the renderer for which is be render
		WhittedRenderer * renderer;
		//	set true, when thread don't have work
		int myTID;
		wxSemaphore semaphore;
		bool exit;
		friend class RayTracer;

		// Render buffers
		struct
		{
			Vector2 pixels[MAX_RAYS_IN_BUNDLE];
			Vector4 colors[MAX_RAYS_IN_BUNDLE];
			Vector4 normalDepth[MAX_RAYS_IN_BUNDLE];
			Vector4 diffuse[MAX_RAYS_IN_BUNDLE];
			struct CastAndShadeBuffers
			{
				Vector4 bounceColors[MAX_RAYS_IN_BUNDLE];
				Vector4 diffuseColors[MAX_RAYS_IN_BUNDLE];
				Vector4 texColors[MAX_RAYS_IN_BUNDLE];
				bool usedTexs[MAX_RAYS_IN_BUNDLE];
			} casBuffers;
			struct
			{
				Vector4 lightColors[MAX_RAYS_IN_BUNDLE];
				Vector4 shadowColors[MAX_RAYS_IN_BUNDLE];
				Vector3 normals[MAX_RAYS_IN_BUNDLE];
			} shadeBuffers;
			RayCaster::Buffers rayCasterBuffers;
		} renderBuffers;
		
		// tiles being rendered remotely
		std::vector<RenderTileData> remoteTiles;
		
		/// vector of received tiles - possible optimization  might be a list if multiple workers acquire the data
		std::queue<RenderTileData *> receivedTiles;
		wxCriticalSection receivedTilesLock;

		RayStream * inputRayStream;
		RayStream * outputRayStream;
		RayStream * shadowRayStream;

#if COMPUTE_LUMINANCE
		Vector2 sumLuminance;
#endif

	public:
		// rendering mode
		enum { NORMAL, MASTER, SLAVE };
		int mode;

		RandomGenerator rng;

		// stack using in traversing ray tracer BVH - every thread has own
		WhittedRendererWorker(WhittedRenderer * renderer, int myTID);
		virtual ~WhittedRendererWorker(void);
		virtual ExitCode Entry(void);

		// delete the queue of received tiles that have not been processed
		void ClearTileQueue(void)
		{
			while (!receivedTiles.empty()) {
				delete receivedTiles.front();
				receivedTiles.pop();
			}
		}

		// Exits the thread when current work cycle is finished
		void Exit()
		{
			exit = true;
			semaphore.Post();
		}

		friend class WhittedRenderer;
		friend class PathRenderer;

	};

}

#endif /* __WHITTED_TRACER_WORKER_H__ */
