
#ifndef _JL_Render_Thread_H_
#define _JL_Render_Thread_H_

#include <stdlib.h>
#include <iostream.h>

#include "planecache.h"
#include "ray.h"

#include "thread.h"
#include "workqueue.h"
#include "render_worker_list.h"

#define RW(num) (&Render_Thread::_worker_list[num])
#define QUEUE(rw) (Render_Thread::_worker_list[rw]._local_work_queue)
#define FRUSTUM(rw, fnum) (Render_Thread::_worker_list[rw]._local_work_queue[fnum])
#define RWNUM (Render_Thread::_worker_list.Size())

#define SUM_CS(var) CS.var + ((CS._frame_id == CS._prev->_frame_id) ? CS._prev->var : 0) + ((CS._frame_id == CS._next->_frame_id) ? CS._next->var : 0)

void PrintStats (CycleState &CS);

class Render_Thread : public Thread {

	friend class Render_Worker;

	private:
	        WorkQueue               **_levels;
		int                     _num_levels;

//		ProtectedWorkQueue	_work_queue;
		WorkRec				*_current_work;
		Ray					_ray;
		int					_y;

		// for workers:
		CycleState			*_current_CS;
		GlobalState			*_current_GS;


		int					_time_start_frame_seconds;
		int					_time_start_frame_useconds;
		int                                     _desired_useconds;

		int DistributeWork(int sslevel, WorkRec *&root);
		void SubdivideFrustaToLevel (int maxlevel, WorkRec *&root);
		WorkQueue *InterleaveWorkRecs (int level);

		//called by the render workers; this does load balancing
		//returns NULL if it's time for the rw to stop
		WorkQueue * GimmeWork (Render_Worker *caller, int &startrec, int &numrecstodo);

	public:
		static Render_Worker_List	_worker_list; //writable only by render_thread!

		Render_Thread();
		Render_Thread(const Render_Thread &R) { CopyFrom(R); }
		virtual ~Render_Thread();

		Render_Thread& CopyFrom(const Render_Thread&);
		Render_Thread& operator=(const Render_Thread &R) { return CopyFrom(R); }

//		friend ostream& operator<<(ostream&, const Render_Thread&);
//		friend istream& operator>>(istream&, Render_Thread&);


		virtual void InitThread(GlobalState&);

		virtual void BeginCycle(CycleState&, GlobalState&);
		virtual int Work(CycleState&, GlobalState&) {cerr << "Render Thread should never work; its kids shoud!" << endl; assert (1==0); return 0;}
		virtual int AnyWorkLeft(CycleState&, GlobalState&);
		virtual void EndCycle(CycleState&, GlobalState&);

		virtual void ShutdownThread();


		void SetNumberOfWorkers(int w);

//		int AllWorkersDone();

#define CAM_MOVED_BIT (1 << 0)
#define WIN_SIZE_CHANGED_BIT (1 << 1)
#define SUPER_SAMPLING_CHANGED_BIT (1 << 2)
		static int Scene_Changed; //if the camera moved since the last time we checked

                static int _times_up;
                static int _timer_valid;
};


#endif
