#include <iostream>
using namespace std;

#include <commandline.h>
#include <graphmisc.h>
#include <mathdefaults.h>
#include <pointsgraph.h>
#include <windowscaleD2.h>
#include <windowscaleD2test.h>
#include <zpr.h>

string windowscaleD2test::doc[] = 
{
  "",
  "Basic tests converting between 2D windows on windowscaleD2 class.",
  ""
};

windowscaleD2test* windowscaleD2test::windowtest=0;

int windowscaleD2test::test001(int argc, char** argv)
{
  windowscaleD2 w1;
  w1.unitwindow();

  assertreturnOS( w1.isinside(.2,.7) );
  assertreturnOS( ! w1.isinside(-.2,.7) );

  string s1(".2 -1 5.7 8");
  windowscaleD2 w2;
  w2.serializeInverse(s1);
  cout << "w2=" << (stringc)w2 << endl;
  
  windowscaleD2 w3 = windowscaleD2::unitcentered;
  w3.scalexy(2.0);
  w3.update();
  cout << "w3=" << (stringc) w3 << endl;

  double x;
  double y;
  x=-1.0;
  y=-1.0;
  cout << SHOW(x) << " " << SHOW(y) << endl;
  cout << "Convert from window w3 to w2" << endl;
  w2.convertfrom(x,y,w3);
  cout << SHOW(x) << " " << SHOW(y) << endl;
  assertreturnOS( x==.2);
  assertreturnOS( y==-1);
  
  x=1.0;
  y=1.0;
  cout << SHOW(x) << " " << SHOW(y) << endl;
  cout << "Convert from window w3 to w2" << endl;
  w2.convertfrom(x,y,w3);
  cout << SHOW(x) << " " << SHOW(y) << endl;
  assertreturnOS( x==5.7);
  assertreturnOS( y==8);

  return 0;
}

void windowscaleD2test::keyboard01
(
  unsigned char key, 
  int x, 
  int y
)
{
  switch (key)
  {
    case 27:
      exit(0);
      break;

    case 'r':
    {
      cout << "Resetting the camera." << endl;
      glMatrixMode(GL_MODELVIEW);

      glLoadIdentity();
      gluLookAt
      (
        0.0, 0.0, 2.0,  // Eye  - creates a x: [-2,2] y: [-2,2] screen.
        0.0, 0.0, 0.0,  // Center
        0.0, 1.0, 0.0   // Up
      );
      glutPostRedisplay();
    }
    break;

    case 'i':
    {
      if (windowtest==0)
        break; 
      cout << "graph=6 example, incrementing time." << endl;

      assert(windowtest!=0);
      windowscaleD2test& wt(*windowtest);

      wt.f04time += windowtest->f04timedx;
      wt.f04pg->push_back(wt.f04(wt.f04time)); 
      glutPostRedisplay();
    }
    break;


  }
}

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

  gobj::global->draw();

  glerrordisplay();
  
  glutSwapBuffers();
}


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

  OpenGLinitialisation();

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

  xGraphics.set();

  //pointsgraph* pg = new pointsgraph();
  //pg->screen.construct(-1.0,-2.0,1.0,2.0);
  //pg->world.construct(0.0,0.0,2.0,2.0);
  pointsgraph* pg = new pointsgraph(
    windowscaleD2(-1.0,-2.0,1.0,2.0),
    windowscaleD2(0.0,0.0,2.0,2.0));

  commandline cmd(argc,argv);

  int graph=1;
  cmd.mapvar(graph,"graph");

  switch (graph)
  {
    case 1: 
    {
      // y =1-x^2 x=[-1,1]
      y01 f01;
      pg->samplefunction(f01,1000);
    }
    break;

    case 2:
    {
      y01 f01;
      pg->samplefunction(f01,1000);
//for (uint i=0; i<pg->pts.size(); ++i)
//  {  cout << i << ": " <<  pg->pts[i] << endl; }
  
//cout << SHOW((stringc)(pg->screen)) << endl;
      pg->world.shiftxy((double)-1.0,(double)-1.0);
      pg->screen_rescaley();
    }
    break;

    case 3:
    {
      y02 f01;
      pg->screen.xmin=0;
      pg->screen.xmax=PI*2;
      pg->samplefunction(f01,200);
      pg->world.shiftxy((double)-1.0,(double)-1.0);
      pg->screen_rescaley();
for (uint i=0; i<pg->pts.size(); ++i)
  {  cout << i << ": " <<  pg->pts[i] << endl; }
cout << SHOW((stringc)(pg->screen)) << endl;
    }
    break;

    case 4:
    {
      // Turned off with singularity.
      pointsgraph::isinside=false; 
      y03 f01;
      double h=3.0;
      pg->domain(-h,h);
      pg->samplefunction(f01,8);
      pg->world.shiftxy((double)-1.0,(double)-1.0);
//      pg->screen_rescaley();
for (uint i=0; i<pg->pts.size(); ++i)
  {  cout << i << ": " <<  pg->pts[i] << endl; }
    };

    case 5:
    {
      y02 f01;
      pg->domain(-PI*3,PI*3);
      pg->samplefunction(f01,200);
      pg->domain(-PI*0.5,PI*0.5);
      pg->clipwindow=true;
      pg->world.shiftxy((double)-1.0,(double)-1.0);
      pg->screen_rescaley();
for (uint i=0; i<pg->pts.size(); ++i)
  {  cout << i << ": " <<  pg->pts[i] << endl; }
cout << SHOW((stringc)(pg->screen)) << endl;
cout << "Function with larger domain created." << endl;
cout << "  Displaying a section of the sin graph." << endl;
    }
    break;

    case 6:
    {
      windowtest=this;

      delete pg;
      f04pg = new pointsgraphtime(10);
      pg = f04pg;
      pg->screen = 
        windowscaleD2(0.0,-1.0,1.0,1.0);
      pg->world = 
        windowscaleD2(-1.0,-1.0,1.0,1.0);
      pg->update();

      f04time=0.0;
      f04pg->push_back( f04(f04time) );
      f04timedx=0.1;

    }
    break;

  }

/*
  uint N=10;
  double dx = 1.0;
  dx /= (N-1);

  double x;
  double y;
  for (uint i=0; i<N; ++i)
  {
    x = dx*i;
    pg->screen.unitscaleInverse_x(x);
    f01(y,x);
    
    pg->pts.push_back( point2<double>(x,y) ); 
  }
*/

  gobjpush(new gobjglPushAttrib(GL_CURRENT_BIT));
  gobjpush(new gobjglPushAttrib(GL_LIGHTING_BIT));
  gobjpush(new gobjglColor3d(1.0,.02,.13));
  gobjpush(new gobjglDisable(GL_LIGHTING));
  gobjpush(pg);
  gobjpush(new gobjglPopAttrib());
  gobjpush(new gobjglPopAttrib());

  pointsgraph_axes_circle* a2 = new pointsgraph_axes_circle();
  double xval[] = { 0,1,2,-1,-2 };
  copy(xval,xval+5,back_inserter(a2->xaxis));
  double yval[] = { 1,2,-1,-2 };
  copy(yval,yval+4,back_inserter(a2->yaxis));
  a2->update();
  gobjpush(a2);
  

  zpr zz;
  zz.update();
  glutMainLoop();
}


