#ifndef _RWVIS_H
#define _RWVIS_H

#include "visman.h"
#include "rwlog.h"
#include "cyclestate.h"

//DrawFrustumPlanes is in debugwin.C.
void DrawFrustumPlanes (WorkRec *wr, CycleState &CS, float planesize, const Vec4 &basecolor, int back);

class RWUseKDTreeVis : public Vis {
    const LogEntry *_start;
public:
  RWUseKDTreeVis (const Vis *parent, const LogEntry *someevent) : Vis (parent, someevent) {strcpy (_type, "RWUseKDTreeVis"); _start = VisManager::FindVisStart (this, someevent);}

  void Display (const LogEntry *current) const {}
  
  char *StatusLine (const LogEntry *ours) const  {
    char *scratch;
    scratch = new char [200];
    if (IsStartEvent (ours))
      {
	RW_UseKDTree_Start_Entry *s;
	s = (RW_UseKDTree_Start_Entry *)ours->_data;
	sprintf (scratch, "sending ray %d, %d into the scene alone.", s->_x, s->_y);
	return scratch;
      }
    else if (IsEndEvent (ours))
      {
	RW_UseKDTree_End_Entry *e;
	e = (RW_UseKDTree_End_Entry *)ours->_data;
	sprintf (scratch, "finished sending ray %d, %d into the scene;", e->_x, e->_y);
	if (e->_givenhit.hitcell)
	  strcat (scratch, " hit!");
	else
	  strcat (scratch, " no hit");
	return scratch;
      }
    else
      return NULL;
  }
  
  const LogEntry *GetStartEntry (void) const {return _start;}

  int IsOurs (const LogEntry *en) const {return (IsStartEvent (en) || IsEndEvent (en));}
  int IsStartEvent (const LogEntry *en) const {return (en->_event == RW_UseKDTree_Start);}
  int IsEndEvent (const LogEntry *en) const {return (en->_event == RW_UseKDTree_End);}

};


class RWDoOneRayFCVis : public Vis {
    const LogEntry *_start;
public:
  RWDoOneRayFCVis (const Vis *parent, const LogEntry *someevent) : Vis (parent, someevent) {strcpy (_type, "RWDoOneRayFCVis"); _start = VisManager::FindVisStart (this, someevent);}

  void Display (const LogEntry *current) const {
    RW_DoOneRayFC_Start_Entry *s = (RW_DoOneRayFC_Start_Entry *)_start->_data;
    glEnable (GL_BLEND);
    glDisable (GL_DEPTH_TEST);
    glBlendFunc (GL_CONSTANT_ALPHA_EXT, GL_ONE_MINUS_CONSTANT_ALPHA_EXT);
    glBlendColorEXT (0, 0, 0, .5);
    
    glColor3f (0., 1., 0.);
    // draw ray from start to intersect point
    glBegin(GL_LINES);
    // from start vertex (given in the start entry)
    glVertex3fv(s->_R.ArrayForGL());
    //to some distance along the ray
    glVertex3fv((s->_R + (1000 * s->_D)).ArrayForGL());
    glEnd();
    
    _KDTreeNode *cell = s->_WR->_cur_cell;
    if (cell)
      {
	glColor3fv (cell_color);
	cell->_bounds.drawWireFrame();

	#if 0
	WorkRec *wr = s->_WR;
	void *place;
	RayCastable *obj;
	wr->_incident->Reset (place);
	while (place)
	  {
	    obj = wr->_incident->Peek (place)->_obj;
	    wr->_incident->Next (place);
	    glColor3f (0., .5, .5);
	    obj->bbox().drawWireFrame();
	  }
	
	wr->_straddlers->Reset (place);
	while (place)
	  {
	    obj = wr->_straddlers->Peek (place)->_obj;
	    wr->_straddlers->Next (place);
	    glColor3f (0., .5, .5);
	    obj->bbox().drawWireFrame();
	  }
#endif
      }
    
    glDisable (GL_BLEND);
    return;
  }
  
  char *StatusLine (const LogEntry *ours) const  {
    char *scratch;
    scratch = new char [200];
    if (IsStartEvent (ours))
      {
	RW_DoOneRayFC_Start_Entry *s;
	s = (RW_DoOneRayFC_Start_Entry *)ours->_data;

	sprintf (scratch, "frustum #%d is firing %d, %d ray at its objs.", s->_WR->_f_num, s->_x, s->_y);
	return scratch;
      }
    else if (IsEndEvent (ours))
      {
	RW_DoOneRayFC_End_Entry *e;
	e = (RW_DoOneRayFC_End_Entry *)ours->_data;
	
	sprintf (scratch, "frustum %d finished firing %d, %d ray at its objs.", e->_WR->_f_num, e->_x, e->_y);

	if (e->_hit.hitcell)
	  strcat (scratch, " hit!");
	else
	  {
	    if (e->_alltheway)
	      strcat (scratch, " no hit w/in the cell; on to k-d tree");
	    else
	      strcat (scratch, " no hit w/in the cell; stopping.");
	  }
	return scratch;
      }
    else
      return NULL;
  }
  
  const LogEntry *GetStartEntry (void) const {return _start;}

  int IsOurs (const LogEntry *en) const {return (IsStartEvent (en) || IsEndEvent (en));}
  int IsStartEvent (const LogEntry *en) const {return (en->_event == RW_DoOneRayFC_Start);}
  int IsEndEvent (const LogEntry *en) const {return (en->_event == RW_DoOneRayFC_End);}

};

class RWWorkVis : public Vis {
    const LogEntry *_start;
public:
  RWWorkVis (const Vis *parent, const LogEntry *someevent) : Vis (parent, someevent) {strcpy (_type, "RWWorkVis"); _start = VisManager::FindVisStart (this, someevent);}

  void Display (const LogEntry *current) const {
    RW_Work_Start_Entry *s;
    s = (RW_Work_Start_Entry *)_start->_data;
    extern CycleState *UI_CS;
    DrawFrustumPlanes (s->_WR, *UI_CS, 5, Vec4 (.4, .0, .5), 0);
  }
  
  char *StatusLine (const LogEntry *ours) const  {
    char *scratch;
    scratch = new char [200];
    if (IsStartEvent (ours))
      {
	RW_Work_Start_Entry *s;
	s = (RW_Work_Start_Entry *)ours->_data;
	const Frustum &f = s->_f;
	
	sprintf (scratch, "frustum #%d (%d, %d) - (%d, %d) firing its rays.", s->_WR->_f_num, f._x1, f._y1, f._x2, f._y2);
	return scratch;
      }
    else if (IsEndEvent (ours))
      {
	RW_Work_End_Entry *e;
	e = (RW_Work_End_Entry *)ours->_data;
	const Frustum &f = e->_f;
	
	sprintf (scratch, "frustum #%d (%d, %d) - (%d, %d) finished firing its rays.", e->_WR->_f_num, f._x1, f._y1, f._x2, f._y2);
	return scratch;
      }
    else if (ours->_event == RW_Work_CastRay) {
	RW_Work_CastRay_Entry *castray;
	castray = (RW_Work_CastRay_Entry *)ours->_data;
	
	sprintf (scratch, "Casting ray %d, %d", castray->_x, castray->_y);
	if (castray->_confirm)
	  strcat (scratch, " (and confirming)");
	return scratch;
    }
    else if (ours->_event == RW_Work_ConfirmRay) {
	RW_Work_ConfirmRay_Entry *confirmray;
	confirmray = (RW_Work_ConfirmRay_Entry *)ours->_data;
	
	sprintf (scratch, "Confirming ray %d, %d", confirmray->_x, confirmray->_y);
	return scratch;
    }
    else
      {
	cerr << "unknown event " << ours->_name << " given to RWWorkVis" << endl;
	return NULL;
      }
  }
  
  const LogEntry *GetStartEntry (void) const {return _start;}

  int IsOurs (const LogEntry *en) const {return (IsStartEvent (en) || IsEndEvent (en) || (en->_event == RW_Work_CastRay) || (en->_event == RW_Work_ConfirmRay));}
  int IsStartEvent (const LogEntry *en) const {return (en->_event == RW_Work_Start);}
  int IsEndEvent (const LogEntry *en) const {return (en->_event == RW_Work_End);}

};

#endif
