#include <cassert>
#include <fstream>
#include <iostream>
using namespace std;

#include <circleD2.h>
#include <circleD2test.h>
#include <commandline.h>
#include <gobj.h>
#include <graphmisc.h>
#include <menusystem.h>
#include <zpr.h>


circleD2<point2<double>,double> * circleD2test::Aptr;
boxOBBhalfspaceD2<point2<double>,double> * circleD2test::Bptr;
bool * circleD2test::help = 0;


gobjContainer circleD2test::shapes(true);


void circleD2test::keyboard01(unsigned char key, int x, int y)
{
  static double delta = 0.1;

  assert(Aptr!=0);
  assert(Bptr!=0);

  switch (key)
  {
    case 27:
      exit(0);
      break;

    case 'j': Bptr->center.x += delta; break; 
    case 'J': Bptr->center.x -= delta; break; 
    case 'k': Bptr->center.y += delta; break; 
    case 'K': Bptr->center.y -= delta; break; 
    case 'l': 
    {
      transrotate2D tr(delta); 
      tr.eval(Bptr->arm1);
      tr.eval(Bptr->arm2);
      break;
    }

    case 'a': Aptr->center.x += delta; break; 
    case 'A': Aptr->center.x -= delta; break; 
    case 's': Aptr->center.y += delta; break; 
    case 'S': Aptr->center.y -= delta; break; 

    case '+': delta *= 10.0; if (delta==0.0) delta=0.1; break;
    case '-': delta /= 10.0; break;

    case 'h': if (help!=0) *help = !*help; break;
  }

  update01();
  glutPostRedisplay();
}


void circleD2test::display01()
{
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  gobj::global->draw();

  glerrordisplay();
  
  glutSwapBuffers();
}

void circleD2test::test01(int & argc, char** argv)
{
  glutInit(&argc,argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowSize(800,600);
  glutCreateWindow("");
  glutDisplayFunc(display01);
  glutKeyboardFunc(keyboard01);

  OpenGLinitialisation();

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_CULL_FACE);
  glEnable(GL_NORMALIZE);

  zpr zz;

  xGraphics.set();

  commandline cmd(argc,argv);

  string in;

  cmd.mapvar(in,"in");
  if ( in.empty() )
  {
    cout << "error: in=filename expected" << endl;
    return;
  }

  ifstream filein(in.c_str());
  assert(filein.good()==true);
  if (filein.good()==false)
    return;

  typedef point2<double> pt2;

  pt2 center;
  pt2 arm1;
  pt2 arm2;
  double arm1len;
  double arm2len;

  filein >> center;
  filein >> arm1len;
  circleD2<pt2,double> A(center,arm1len);

  filein >> center;
  filein >> arm1;
  filein >> arm2;
  filein >> arm1len;
  filein >> arm2len;
  boxOBBhalfspaceD2<pt2,double> 
    B(center,arm1,arm2,arm1len,arm2len);

  Aptr = & A;
  Bptr = & B;
  gobjpush(&shapes);

  update01();

  menusystem * menu = 
    new menusystem(0,0,true,point2<GLint>(60,30),10);

  gobjSwitch<> * menuswitch = new gobjSwitch<>(menu,true);
  help = & menuswitch->isdrawn;
  gobjpush(menuswitch);

  menu->addfont12("Circle and Box Intersection");
  menu->addnewline();
  menu->addnewline();
  menu->addfont10("j J   Move box B left or right.");
  menu->addnewline();
  menu->addfont10("k K   Move box B up or down.");
  menu->addnewline();
  menu->addfont10("l L   Rotate box B.");
  menu->addnewline();

  menu->addfont10("a A   Move box A left or right.");
  menu->addnewline();
  menu->addfont10("s S   Move box A up or down.");
  menu->addnewline();

  menu->addnewline();
  menu->addfont10("+ -   Increase or decrease change.");
  menu->addnewline();
  menu->addfont10("h    Toggle this help menu.");
  menu->addnewline();
  menu->addfont10("ESC      Quit");

  zz.update();
  glutMainLoop();
}

void circleD2test::update01()
{
  assert(Aptr!=0);
  assert(Bptr!=0);

  vector< point2<double> > pts(4);

  shapes.nuke();

  shapes.push(new gobjglColor3ub(184,134,11));

  typedef point3<double> pt3;

  gobjMyCircle * cir = new gobjMyCircle();
  shapes.push(cir);
  shapes.push
  ( 
    new gobjMyCircleDraw
    (
      Aptr->radius,
      pt3(Aptr->center.x,Aptr->center.y,0.0), 
      *cir
    ) 
  );

  Bptr->cornerpoints(pts[0],pts[1],pts[2],pts[3]);

  shapes.push(new gobjglBegin(GL_LINES));

  shapes.push(new gobjglColor3ub(0,191,255));

  shapes.push(new gobjglVertex2f(pts[0]));
  shapes.push(new gobjglVertex2f(pts[1]));
  shapes.push(new gobjglVertex2f(pts[1]));
  shapes.push(new gobjglVertex2f(pts[2]));
  shapes.push(new gobjglVertex2f(pts[2]));
  shapes.push(new gobjglVertex2f(pts[3]));
  shapes.push(new gobjglVertex2f(pts[3]));
  shapes.push(new gobjglVertex2f(pts[0]));

  shapes.push(new gobjglColor3ub(255,0,255));
  shapes.push(new gobjglVertex2f(Aptr->center));
  shapes.push(new gobjglVertex2f(Bptr->center));

  shapes.push(new gobjglEnd());

  static GLUquadricObj * qobj = gluNewQuadric();

  bool intersection = (Aptr->intersects(*Bptr));
  if (intersection)
  {
    double transparency=0.4;

    shapes.push(new gobjglEnable(GL_BLEND));
    shapes.push(
      new gobjglBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) );
    shapes.push(
      new gobjglColor4f(1.0,0.0,0.0,transparency));

    shapes.push(new gobjglBegin(GL_TRIANGLES));

    Bptr->cornerpoints(pts[0],pts[1],pts[2],pts[3]);
    shapes.push(new gobjglVertex2f(pts[0]));
    shapes.push(new gobjglVertex2f(pts[1]));
    shapes.push(new gobjglVertex2f(pts[2]));
    shapes.push(new gobjglVertex2f(pts[2]));
    shapes.push(new gobjglVertex2f(pts[3]));
    shapes.push(new gobjglVertex2f(pts[0]));
    shapes.push(new gobjglEnd());

    shapes.push(new gobjglPushMatrix());
    shapes.push(new gobjglTranslatef(Aptr->center.x,Aptr->center.y,0.0));

    shapes.push( new gobjgluDisk(qobj, 0.0, Aptr->radius, 30, 1) );
    shapes.push(new gobjglPopMatrix());

    shapes.push(new gobjglDisable(GL_BLEND));
  }
}



