#include <iostream>
using namespace std;


#include <commandline.h>
#include <gobj.h>
#include <graphmisc.h>
#include <maze005.h>
#include <mazedisp03.h>
#include <mazematrixD2.h>
#include <mazematrixD2createmaze.h>

#include <zpr.h>


string maze005::doc[] = 
{
  "",
  "$ ./main prog=14 m=10 n=20 dx=0.15 backgroundcolor=0,255,0 wallcolor=0,25,255 randozize=0 id=1 origin=-1.4,-.5,0 - Display m by n maze."
};

mazegameD2state01* maze005::mg = 0;
mazegameD2solver01* maze005::ms = 0;
mazedisp03* maze005::md = 0;
bool* maze005::help = 0;
menusystem* maze005::messages = 0;

// http://www.codeproject.com/KB/openGL/GLUT_WINDOW_TEMPLATE.aspx
void maze005::special01(int key, int x, int y)
{
  assert(mg!=0);
  assert(md!=0);

  switch (key)
  {
    case GLUT_KEY_LEFT : mg->currentmove(3); break;
    case GLUT_KEY_RIGHT : mg->currentmove(1); break;
    case GLUT_KEY_UP : mg->currentmove(0); break;
    case GLUT_KEY_DOWN : mg->currentmove(2); break;
  }

  glutPostRedisplay();
}

void maze005::keyboard01
(
  unsigned char key, 
  int x, 
  int y
)
{
  assertreturn(mg!=0);
  assertreturn(md!=0);
  assertreturn(ms!=0);
  assertreturn(messages);

  switch (key)
  {
    case 'q': exit(0); break;

    case 's': 
      if (!(*ms)) ++(*ms);
      break;
    case 'S':
      for ( ; !(*ms); ++(*ms) );
      break;
    case 'h': 
      *help = !(*help); break;

    case '1':
      messages->addfont10paragraphs((stringc)(*mg),50); break;
    case '2':  messages->scrolldown(); break;
    case '3':  messages->scrollup(); break;
    case '4':  messages->clear(); break;

    case 'p':  md->pipes = ! md->pipes; md->gx.update(); break;
    case 'w':  md->walls = ! md->walls; md->gx.update(); break;
    case 'i':  md->displaycellid= ! md->displaycellid; md->gx.update(); break;

  }

  glutPostRedisplay();
}

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

  assert(gobj::global);

  gobj::global->draw();

  glerrordisplay();
  
  glutSwapBuffers();
}


void maze005::reshape01(intc width_,intc height_)
{
  zpr::reshape(width_,height_);
  assert(md);
//  assert(md->bp02);
//  md->bp02->update();
}

void maze005::menubuild()
{
  menusystem * menu = 
    new menusystem(point2<GLint>(60,30),10);
  menu->fontcolor = point4<float>(218.0/255.0,165.0/255.0,32.0/255.0,0.75);

  menu->addfont12("Maze Game [prototype 02]",2);
  
  menu->addfont10("[page up] move up",1);
  menu->addfont10("[page down] move down",1);
  menu->addfont10("[< home] move left",1);
  menu->addfont10("[end >] move right",2);

  menu->addfont10("[s] solver 1 step",1);
  menu->addfont10("[S] solve maze",1);
  menu->addfont10("[h] Toggle the menu",2);

  menu->addfont10("[p] Toggle pipes",1);
  menu->addfont10("[w] Toggle walls",1);
  menu->addfont10("[i] Toggle cell id",2);

  menu->addfont10("[1] Print settings",1);
  menu->addfont10("[2] scroll down",1);
  menu->addfont10("[3] scroll up",1);
  menu->addfont10("[4] clear",2);

  menu->addfont10("[q] Quit",1);

  menu->lightingdisable();

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

  // The messages menu
  messages = 
    new menusystem(point2<GLint>(60,250),10);
  gobjpush(messages);
  messages->fontcolor = point4<float>(1.0,0.0,0.0,0.8);
  messages->lightingdisable();
}

maze005::maze005(int argc, char** argv)
  : xGraphics(true)
{
  glutInit(&argc,argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  glutInitWindowSize(800,600);
  glutCreateWindow("");
  glutDisplayFunc(maze005::display01);
  glutKeyboardFunc(maze005::keyboard01);
  glutSpecialFunc(maze005::special01);


  OpenGLinitialisation();

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

  xGraphics.set();

  commandline cmd(argc,argv);

  // Construct the maze.

  mg = new mazegameD2state01();

  cmd.mapvar(mg->m,"m");
  cmd.mapvar(mg->n,"n");
  cmd.mapvar(mg->randomize,"randomize");

  cmd.mapvar(mg->proper,"proper");
  cmd.mapvar(mg->deletewall,"deletewall");

  mg->game01();
  assert(mg->valid());

  md = new mazedisp03(*mg);
  md->game01default();

  cmd.mapvar(md->dx,"dx");

  cmd.mapvar(md->displaycellid,"id");

  cmd.mapvar(md->pipes,"pipes");
  graphmisc::colornormalize(md->pipecolor,cmd,"pipecolor");

  cmd.mapvar(md->walls,"walls");
  graphmisc::colornormalize(md->wallcolor,cmd,"wallcolor");

  string originstr("(0,0)");
  cmd.mapvar(originstr,"origin");
  md->origin.serializeInverseBrackets(originstr);

  graphmisc::colornormalize(md->backgroundcolor,cmd,"backgroundcolor");

  cmd.mapvar(md->endpointratio,"endpointratio");
  graphmisc::colornormalize(md->endpointcolor,cmd,"endpointcolor");

  graphmisc::colornormalize(md->currentposcolor,cmd,"currentposcolor");

cout << mg->settings() << md->settings() << endl;

  ms = new mazegameD2solver01(*mg);

}


void maze005::eval()
{
  assert(md);
  assert(ms);

  gobjpush(new gobjglTranslated(md->origin.x,md->origin.y,0.0));

  gobjpush(new gobjglClearColor(md->backgroundcolor));
  gobjpush(new gobjglClear(GL_COLOR_BUFFER_BIT));

  zpr zz;
  // Because zpr overides reshape function in constructor.
  glutReshapeFunc(maze005::reshape01);

  assert(md);
  zz.mousecallback = & md->mousecallback;
  md->zm = new zprmouse(zz);

  md->construct();
  gobjpush(md);

  ms->reset();

  menubuild();

  zz.update();
  glutMainLoop();
}


