#ifndef _WRVIS_H
#define _WRVIS_H

#include "visman.h"
#include "wrlog.h"

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

  void Display (const LogEntry *current) const {}
  
  char *StatusLine (const LogEntry *ours) const  {
    if (IsOurs (ours))
      {
	WR_FrustumSubdivided_Entry *s = (WR_FrustumSubdivided_Entry *)ours->_data;
	char *scratch = new char [200];
	sprintf (scratch, "subdividing frustum #%d (%d, %d) - (%d, %d) to #%d, %d, %d, %d", s->_WR->_f_num, s->_WR->_frustum._x1, s->_WR->_frustum._y1, s->_WR->_frustum._x2, s->_WR->_frustum._y2, s->_WR->_kids[0]->_f_num, s->_WR->_kids[1]->_f_num, s->_WR->_kids[2]->_f_num, s->_WR->_kids[3]->_f_num);
	if (s->_had_objs)
	  strcat (scratch, " because it had objs.");
	else
	  strcat (scratch, " because it went into different cells.");
	return scratch;
      }
    else
      {
	cerr << ours->_name << " had unknown event type" << endl;
	return NULL;
      }
  }
  
  const LogEntry *GetStartEntry (void) const {return _start;}

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

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

  void Display (const LogEntry *current) const {
    glEnable (GL_BLEND);
    glDisable (GL_DEPTH_TEST);
    glBlendFunc (GL_CONSTANT_ALPHA_EXT, GL_ONE_MINUS_CONSTANT_ALPHA_EXT);
    glBlendColorEXT (0, 0, 0, .5);
    WR_EatCurCell_Entry *s = (WR_EatCurCell_Entry *)_start->_data;
    s->_cell->Draw (1,0);
    
    //draw all the objs in wireframe
    void *place;
    RayCastable *obj;
    _KDTreeNode *cell = s->_cell;
    glColor3fv (obj_color);
    cell->_objs->Reset (place);
    while (place)
      {
	obj = cell->_objs->Peek (place);
	cell->_objs->Next (place);
	obj->bbox().drawWireFrame();
      }
    
    //draw the objs we kept in full!
    WorkRec *wr = s->_WR;
    wr->_incident->Reset (place);
    while (place)
      {
	obj = wr->_incident->Peek (place)->_obj;
	wr->_incident->Next (place);
	obj->Draw (RayCastable::FILLED);
      }
    wr->_straddlers->Reset (place);
    while (place)
      {
	obj = wr->_straddlers->Peek (place)->_obj;
	wr->_straddlers->Next (place);
	obj->Draw (RayCastable::FILLED);
      }
    glDisable (GL_BLEND);
  }
  
  char *StatusLine (const LogEntry *ours) const  {
    if (IsOurs (ours))
      {
	WR_EatCurCell_Entry *s = (WR_EatCurCell_Entry *)ours->_data;
	char *scratch = new char [200];
	sprintf (scratch, "frustum #%d (%d, %d) - (%d, %d) clipped against the %d objs in its cell, %d survived", s->_WR->_f_num, s->_WR->_frustum._x1, s->_WR->_frustum._y1, s->_WR->_frustum._x2, s->_WR->_frustum._y2, s->_num_cell_objs, s->_num_clipped_objs);
	return scratch;
      }
    else
      {
	cerr << ours->_name << " had unknown event type" << endl;
	return NULL;
      }
  }
  
  const LogEntry *GetStartEntry (void) const {return _start;}

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

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

  void Display (const LogEntry *current) const {
    WR_FrustumWalked_Entry *s = (WR_FrustumWalked_Entry *)_start->_data;
    s->_src->Draw (1,0);
    glColor3f (0., 1., 0.); //green
    s->_dest->_bounds.drawWireFrame();
  }
  
  char *StatusLine (const LogEntry *ours) const  {
    if (IsOurs (ours))
      {
	WR_FrustumWalked_Entry *s = (WR_FrustumWalked_Entry *)ours->_data;
	char *scratch = new char [200];
	sprintf (scratch, "frustum #%d (%d, %d) - (%d, %d) walking into another cell", s->_WR->_f_num, s->_WR->_frustum._x1, s->_WR->_frustum._y1, s->_WR->_frustum._x2, s->_WR->_frustum._y2);
	return scratch;
      }
    else
      {
	cerr << ours->_name << " had unknown event type" << endl;
	return NULL;
      }
  }
  
  const LogEntry *GetStartEntry (void) const {return _start;}

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

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

  void Display (const LogEntry *current) const {
    if (!IsEndEvent (current)) return;
    
    glEnable (GL_BLEND);
    glBlendFunc (GL_CONSTANT_ALPHA_EXT, GL_ONE_MINUS_CONSTANT_ALPHA_EXT);
    glBlendColorEXT (0, 0, 0, .25);
    
    WR_FindNextCells_End_Entry *e;
    e = (WR_FindNextCells_End_Entry *)current->_data;
    
    glColor3f (1., 0., 0.);
    e->_WR->_cur_cell->_bounds.drawFilled();
    for (int i = 0; i < 4; i++)
      {
	if (e->_WR->_cell_corner_goesto[i])
	  {
	    glColor3fv (e->_WR->_cell_corner_goesto[i]->_debug_color.ArrayForGL());
	    e->_WR->_cell_corner_goesto[i]->_bounds.drawFilled();
	  }
      }
    glDisable (GL_BLEND);
  }
  
  char *StatusLine (const LogEntry *ours) const  {
    char *scratch;
    scratch = new char [200];
    if (IsStartEvent (ours))
      {
	WR_FindNextCells_Start_Entry *s;
	s = (WR_FindNextCells_Start_Entry *)ours->_data;
	sprintf (scratch, "frustum #%d (%d, %d) - (%d, %d) finding the next cells for its 5 interior rays", s->_WR->_f_num, s->_WR->_frustum._x1, s->_WR->_frustum._y1, s->_WR->_frustum._x2, s->_WR->_frustum._y2);
	return scratch;
      }
    else if (IsEndEvent (ours))
      {
	WR_FindNextCells_End_Entry *e;
	e = (WR_FindNextCells_End_Entry *)ours->_data;
	sprintf (scratch, "frustum #%d (%d, %d) - (%d, %d) finished finding the next cells", e->_WR->_f_num, e->_WR->_frustum._x1, e->_WR->_frustum._y1, e->_WR->_frustum._x2, e->_WR->_frustum._y2);
	return scratch;
      }
    else
      {
	cerr << "unknown event in wrfindnextcellsvis::statusline" << endl;
	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 == WR_FindNextCells_Start);}
  int IsEndEvent (const LogEntry *en) const {return (en->_event == WR_FindNextCells_End);}

};

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

  void Display (const LogEntry *current) const {}
  
  char *StatusLine (const LogEntry *ours) const  {
    if (ours->_event == WR_FloodYes)
      {
	WR_FloodYes_Entry *s = (WR_FloodYes_Entry *)ours->_data;
	char *scratch = new char [200];
	sprintf (scratch, "frustum #%d (%d, %d) - (%d, %d) flooded with a known hit!", s->_WR->_f_num, s->_WR->_frustum._x1, s->_WR->_frustum._y1, s->_WR->_frustum._x2, s->_WR->_frustum._y2);
	return scratch;
      }
    else if (ours->_event == WR_FloodNo)
      {
	WR_FloodYes_Entry *s = (WR_FloodYes_Entry *)ours->_data;
	char *scratch = new char [200];
	sprintf (scratch, "frustum #%d (%d, %d) - (%d, %d) flooded with empties!", s->_WR->_f_num, s->_WR->_frustum._x1, s->_WR->_frustum._y1, s->_WR->_frustum._x2, s->_WR->_frustum._y2);
	return scratch;
      }
    else
      {
	cerr << "unknown event " << ours->_name << ", #" << ours->_event << " in wrfloodvis::statusline" << endl;
	return NULL;
      }
  }
  
  const LogEntry *GetStartEntry (void) const {return _start;}

  int IsOurs (const LogEntry *en) const {return (en == _start);}
  int IsStartEvent (const LogEntry *en) const {return (IsOurs (en));}
  int IsEndEvent (const LogEntry *en) const {return (IsOurs (en));}
};
#endif
