#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <iostream>
using namespace std;

#include <limits> // for std::numeric_limits
#include <string> // for std::string
#include <fstream> // file I/O
#include <cstdlib>
#include <cmath>

int  background_width = 0;
int  background_height = 0;
char *background_data;

int display_width = 0;
int display_height = 0;

void init();
void reshape(int w, int h);
void display();
void loadTexturePPM( const char * filename );
std::ifstream& skipComment(std::ifstream &strm);

int main(int argc, char ** argv)
{
  cout << "Starte: Kapitel 2 - Uebung 1\n";
  // Initialize GLUT.
  glutInit(&argc, argv);
  // Set the initial display mode
  glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH);
  glutInitWindowSize(800,536);
  glutInitWindowPosition(100,100);
  glutCreateWindow("AR-Buch - Kapitel 2 - Uebung 1");

  init();

  // Hand display funtion to GLUT
  glutDisplayFunc(display);
  // Hand reshape function to GLUT
  glutReshapeFunc(reshape);

  // Tell the program we are not done yet
  glutMainLoop();
}

// Initialize GLUT settings
void init()
{
  // Load texture: loads picture into global variables "background_*"
  loadTexturePPM("Hintergrundbild.ppm");

  glShadeModel (GL_SMOOTH);
  // Background color
  glClearColor (0,0,0,0);
  glClearDepth (1.0f);
  glEnable (GL_DEPTH_TEST);
  glDepthFunc (GL_LEQUAL);
  glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

  // Setup lighting
  glEnable(GL_LIGHTING);
  float global_ambient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
  glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
  float specular[] = {1.0f, 1.0f, 1.0f , 1.0f};
  glLightfv(GL_LIGHT0, GL_SPECULAR, specular);
  float position[] = { -0.5f, 1.0f, 1.2f, 1.0f };
  glLightfv(GL_LIGHT0, GL_POSITION, position);
  glEnable(GL_LIGHT0);

  // We later only use lighting for the teapot
  // Cubes otherwise look strange
  // We thus turn it off here and will enable there again
  glDisable(GL_LIGHTING);

  return;
}

// Execute on window resize (and thus on window open, too)
void reshape (int w, int h)
{
  if ( h==0 ) {
    h = 1;
  }

  display_width = w;
  display_height = h;

  glViewport (0, 0, (GLsizei) w, (GLsizei) h);
  glMatrixMode (GL_PROJECTION);
  glLoadIdentity ();

  // Your Stuff goes here

  glMatrixMode (GL_MODELVIEW);
}


// Do all the drawings
void display()
{
  // Clear Screen and Depth Buffer
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  
  // Reset The Current Modelview Matrix
  glLoadIdentity();

  // Load Background Image
  glMatrixMode (GL_PROJECTION);
  glPushMatrix();
    glLoadIdentity();
    gluOrtho2D( 0.0, display_width, 0.0, display_height );
    glRasterPos2i( 0, display_height-1 );
    glPixelZoom(((float)display_width /(float)background_width )*1.0000001f
     , -((float)display_height/(float)background_height)*1.0000001f);
    glDrawPixels( background_width, background_height, GL_RGB, GL_UNSIGNED_BYTE, background_data );
  glPopMatrix();

  glMatrixMode (GL_MODELVIEW);
  glClear(GL_DEPTH_BUFFER_BIT);

  // Your Stuff goes here

  //Draw everything to the screen
  glFlush();

  glutSwapBuffers();
}

//-----------------------------   Load PPM stuff -------------------------------

// Load a PPM file as texture
void loadTexturePPM( const char * filename )
{
  int maxcolor;
  std::string magic;

  // open texture data
  std::ifstream ifs( filename );
  if ( !ifs ) {
    std::cerr << "Unable to open file" << filename << " for reading\n";
    exit(1);
  }

  skipComment(ifs)>>magic;
  skipComment(ifs)>>background_width;
  skipComment(ifs)>>background_height;
  skipComment(ifs)>>maxcolor;

  char c;
  while(isspace(c=ifs.get()));
  ifs.putback(c);

  int colorsize = (maxcolor<256) ? 1 : 2;
  background_data = new char[background_width*background_height*3*colorsize];
  std::streamsize getcount = ifs.rdbuf()->sgetn( background_data, background_width*background_height*3*colorsize );

  ifs.close();

  return;
}

// Skip comments
std::ifstream& skipComment(std::ifstream &strm)
{
  char c;
  const int c_MAX_LINESIZE=std::numeric_limits<int>::max();

  if(!strm) {
    return strm;
  }

  while(isspace(c=strm.get())) ;


  if(c=='#') {
    //skip the rest of the line
    strm.ignore(c_MAX_LINESIZE, '\n');
    return skipComment(strm);
  } else if (c!=EOF) {
    strm.putback(c);
  }
  return strm;
}

