#include "kdtreesubdividevis.h"
#include "kdtreelog.h"
#include "objlist.h"
#include "prim.h"
#include "kdtree.h"
#include "bounds3d.h"
#include <GL/gl.h>
#include <stdio.h>

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

void KDTreeSubdivideVis::Display (const LogEntry *upto) const {
  // draw objects here
  const LogEntry *temp2 = _start;
  ObjList *list=((KDTreeSubdivide_Start_Entry *)temp2->_data)->_obj_list;
  void *place;
  RayCastable *obj;
  
  list->Reset (place);
  while (place) 
    {
      obj = list->Peek (place);
      // set color for objects here
      //glColor3f(0.0,0.0,1.0);  // blue
      //obj->Draw(RayCastable::WIREFRAME);// or (RayCastable::FILLED);
      // set color for bboxes here
      //glColor3f(0.0,0.0,1.0);  // blue
      glColor3fv (obj->GetRepresentativeColor().ArrayForGL());
      obj->bbox().drawWireFrame();// or drawFilled();
      list->Next(place);
    }   
  
  const LogEntry * temp = _start;
  
  KDTreeSubdivide_TryPlane_Entry *bestYet = NULL;
  // set color for drawing old parts of kdTree here
  GLfloat oldWidth;
  glGetFloatv(GL_LINE_WIDTH, &oldWidth);
  glLineWidth(oldWidth+1);
  glColor3f(0.0,1.0,0.0);  // green
  while (temp != upto) {
    //draw nodes
    switch (temp->_event) {
    case KDTreeSubdivide_Start:
      KDTreeSubdivide_Start_Entry *s;
      s = (KDTreeSubdivide_Start_Entry *)temp->_data;
      // draw node
      s->_node->_bounds.drawWireFrame();
      break;
    case KDTreeSubdivide_TryPlane:
      KDTreeSubdivide_TryPlane_Entry *t;
      t = (KDTreeSubdivide_TryPlane_Entry *)temp->_data;
      if (t->_is_best_so_far) {
	bestYet = t;
      }
      break;
    case KDTreeSubdivide_End:
      //KDTreeSubdivide_End_Entry *e;
      //e = (KDTreeSubdivide_End_Entry *)temp->_data;
      bestYet = NULL;
      break;
    case KDTreeSubdivide_Reject:
      //KDTreeSubdivide_Reject_Entry *r;
      //r = (KDTreeSubdivide_Reject_Entry *)temp->_data;
      break;
    default:
      break;
    }
    temp = temp->_next;
  }

  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  glLineWidth(oldWidth+2);

  //draw new part of tree
  switch (upto->_event) {
  case KDTreeSubdivide_Start:
    KDTreeSubdivide_Start_Entry *s;
    s = (KDTreeSubdivide_Start_Entry *)upto->_data;
    // highlight this node
    glEnable (GL_BLEND);
    glColor4f(1.0,0.6,0.0,0.3);  // orange
    s->_node->_bounds.drawFilled();
    glDisable (GL_BLEND);
    // update ui
    break;

  case KDTreeSubdivide_Reject:
    KDTreeSubdivide_Reject_Entry *r;
    r = (KDTreeSubdivide_Reject_Entry *)upto->_data;
    // highlight this node
    glColor3f(1.0,0.6,0.0);  //orange
    r->_node->_bounds.drawWireFrame();
    // highlight this plane
    //   (different color because it's rejected)
    glColor3f(1.0,0.0,0.0);  // red
    // update ui
    break;

  case KDTreeSubdivide_TryPlane:
    KDTreeSubdivide_TryPlane_Entry *t;
    t = (KDTreeSubdivide_TryPlane_Entry *)upto->_data;
    // highlight this node
    glColor3f(1.0,0.6,0.0);  //orange
    t->_node->_bounds.drawWireFrame();
    // highlight this plane
    //   (different color if (t->_is_best_so_far))
    glEnable (GL_BLEND);
    if (t->_is_best_so_far) {
      glColor4f(1.0,0.4,1.0,0.3);  // pink
      bestYet = t;
    }
    else
      glColor4f(1.0,1.0,0.0,0.3);  // yellow
    
    Bounds3d *plane2;
    switch(t->_axis) {
    case 0: //x
      plane2 = new Bounds3d(t->_where, t->_where,
			    t->_node->_bounds.ymin(),
			    t->_node->_bounds.ymax(),
			    t->_node->_bounds.zmin(),
			    t->_node->_bounds.zmax());
      break;
    case 1: //y
      plane2 = new Bounds3d(t->_node->_bounds.xmin(),
			    t->_node->_bounds.xmax(),
			    t->_where, t->_where,
			    t->_node->_bounds.zmin(),
			    t->_node->_bounds.zmax());
      break;
    case 2: //z
      plane2 = new Bounds3d(t->_node->_bounds.xmin(),
			    t->_node->_bounds.xmax(),
			    t->_node->_bounds.ymin(),
			    t->_node->_bounds.ymax(),
			    t->_where, t->_where);
      break;
    default:
      break;
    }
    //plane2->drawWireFrame();
    plane2->drawFilled();
    delete plane2;

    glDisable (GL_BLEND);

    // update ui
    break;

  case KDTreeSubdivide_End:
    //KDTreeSubdivide_End_Entry *e;
    //e = (KDTreeSubdivide_End_Entry *)upto->_data;
    // update ui
    break;

  default:
    break;
  }
  glLineWidth(oldWidth);

  glEnable (GL_BLEND);

  //draw plane that's "bestYet" here
  if (bestYet) {
    glColor4f(1.0,0.4,1.0,0.3);  // pink
    Bounds3d *plane;
    switch(bestYet->_axis) {
    case 0: //x
      plane = new Bounds3d(bestYet->_where, bestYet->_where,
			   bestYet->_node->_bounds.ymin(),
			   bestYet->_node->_bounds.ymax(),
			   bestYet->_node->_bounds.zmin(),
			   bestYet->_node->_bounds.zmax());
      break;
    case 1: //y
      plane = new Bounds3d(bestYet->_node->_bounds.xmin(),
			   bestYet->_node->_bounds.xmax(),
			   bestYet->_where, bestYet->_where,
			   bestYet->_node->_bounds.zmin(),
			   bestYet->_node->_bounds.zmax());
      break;
    case 2: //z
      plane = new Bounds3d(bestYet->_node->_bounds.xmin(),
			   bestYet->_node->_bounds.xmax(),
			   bestYet->_node->_bounds.ymin(),
			   bestYet->_node->_bounds.ymax(),
			   bestYet->_where, bestYet->_where);
      break;
    default:
      break;
    }
    plane->drawFilled();
    delete plane;
  } else {  //no bestYet
    //    zeroBest();
  }

  glDisable (GL_BLEND);
}

char * KDTreeSubdivideVis::StatusLine (const LogEntry *entry) const {
  char * _msg = new char[150];
  
  switch (entry->_event) {
  case KDTreeSubdivide_Start:
    KDTreeSubdivide_Start_Entry *s;
    s = (KDTreeSubdivide_Start_Entry *)entry->_data;
    sprintf (_msg, "%s %s %d %s", entry->_name, ": starting with ", s->_obj_list->Size()," object.");
    break;
  case KDTreeSubdivide_Reject:
    KDTreeSubdivide_Reject_Entry *r;
    r = (KDTreeSubdivide_Reject_Entry *)entry->_data;
    // update ui
    switch (r->_why) {
    case FewObjects:
      sprintf (_msg, "%s %s %d %s", entry->_name, ": node with ", r->_node->_objs->Size()," object decided to reject.(too few objects)");
      break;
    case ParentsUnproductive:
      sprintf (_msg, "%s %s %d %s", entry->_name, ": node with ", r->_node->_objs->Size()," object decided to reject.(parents unproductive)");
      break;
    default:
      break;
    }
    break;
  case KDTreeSubdivide_TryPlane:
    KDTreeSubdivide_TryPlane_Entry *t;
    t = (KDTreeSubdivide_TryPlane_Entry *)entry->_data;
    // update ui
    sprintf (_msg, "%s %s %c %s %.2f", entry->_name, ": tried ", (char)(t->_axis + 'X')," as splitting plane at location ", t->_where);
    break;
  case KDTreeSubdivide_End:
    sprintf (_msg, "Subdivide ended");
    break;
  default:
    break;
  }
  
  return _msg;
}
