#include "kdtreelog.h"
#include "logentry.h"
#include <GL/gl.h>
#include "bounds3d.h"
#include <stdio.h>
#include <iostream.h>
#include "kdtreenodeintersectvis.h"
#include "prim.h"

KDTreeNodeIntersectVis::KDTreeNodeIntersectVis (const Vis *parent, const LogEntry *someevent) : Vis (parent, someevent) {
  strcpy (_type, "KDTreeNodeIntersect");

  _start = VisManager::FindVisStart (this, someevent);
}

void
KDTreeNodeIntersectVis::Display(const LogEntry* upto) const {
  KDTreeNodeIntersect_Start_Entry *s = (KDTreeNodeIntersect_Start_Entry*)_start->_data;
  // draw start node in hilited wireframe
  glColor3f(1.0,0.6,0.0);  // orange
  s->_node->_bounds.drawWireFrame();

  // variables for start point box of ray
  Bounds3d ptbox;
  Vec4 dim;
  float mindim;

  float m; // multiple for _D when determining 2nd pt along ray

  glColor3f(0.0,1.0,0.0); // green
  // draw box around start point of ray for orientation
  ptbox.IncludePoint (s->_R);
  dim = s->_node->_bounds[1] - s->_node->_bounds[0];
  mindim = MAXFLOAT;
  if (dim[0] < mindim && dim[0] != 0.) mindim = dim[0];
  if (dim[1] < mindim && dim[1] != 0.) mindim = dim[1];
  if (dim[2] < mindim && dim[2] != 0.) mindim = dim[2];
  mindim *= .06;
  ptbox[1] += Vec4 (mindim, mindim, mindim);
  ptbox[0] -= Vec4 (mindim, mindim, mindim);
  ptbox.drawFilled ();
  
  // search from current node back to start node and look
  //  for 1st newbest and assign m...if none, m=maxloc
  const LogEntry *curr;
  curr = upto;
  int found = 0;
  while ((curr->_event != KDTreeNodeIntersect_Start) && (!found)) {
    if (curr->_event == KDTreeNodeIntersect_NewBest) {
      KDTreeNodeIntersect_NewBest_Entry *n = (KDTreeNodeIntersect_NewBest_Entry*)curr->_data;
      m = n->_hit.t;
      n->_hit.obj->Draw(RayCastable::FILLED);
      found = 1;
    }
    curr = curr->_prev;
  }
  if (!found)
    m = s->_maxloc;
  else
    glColor3f (1., 0., 0.); //ray turns red when it hits something

  // draw ray
  glBegin(GL_LINES);
  // from start vertex
  glVertex3f( s->_R[0], s->_R[1], s->_R[2] );
  // to multiple of direction vector
  glVertex3f( (s->_R[0] + m*(s->_D[0])),
	      (s->_R[1] + m*(s->_D[1])),
	      (s->_R[2] + m*(s->_D[2])) );
  glEnd();

  switch (upto->_event)
    {
    case KDTreeNodeIntersect_Obj:
      KDTreeNodeIntersect_Obj_Entry *o = (KDTreeNodeIntersect_Obj_Entry*)upto->_data;
      o->_obj->Draw(RayCastable::FILLED);
      break;
    }
}

char * KDTreeNodeIntersectVis::StatusLine (const LogEntry *ours) const {
  char *scratch;
switch (ours->_event)
    {
    case KDTreeNodeIntersect_Start:
      scratch = new char [100];
      sprintf (scratch, "starting old-school ray/k-d cell intersect");
      return scratch;

    case KDTreeNodeIntersect_NewBest:
      scratch = new char [100];
      sprintf (scratch, "     That object was the closest intersection so far.");
      return scratch;

    case KDTreeNodeIntersect_Obj:
      KDTreeNodeIntersect_Obj_Entry *o;
      o = (KDTreeNodeIntersect_Obj_Entry *)(ours->_data);
      scratch = new char [300];
      sprintf (scratch, "Checking for an intersection with this object.");
      if (!o->_pastbbox)
	strcat (scratch, "  The object's bounding box is beyond the bb of the current best intersection.");
      return scratch;
      
    case KDTreeNodeIntersect_End:
      KDTreeNodeIntersect_End_Entry *d;
      d = (KDTreeNodeIntersect_End_Entry *)(ours->_data);
      scratch = new char [200];
      if (d->_why == AllObjsEnd)
	sprintf (scratch, "finished old-school k-d cell intersect");
      else
	sprintf (scratch, "Remaining intersected objects beyond current best.");
      return scratch;
    default:
      cerr << "unknown event " << ours->_name << " for kdtreeintersect.statusline" << endl;
      return newStr(ours->_name);
    }
}
