#include <GL/glut.h>
#include <math.h>
#include <stdio.h>
#include <string.h>

// Define a constant for the value of PI
#define GL_PI 3.1415f

GLfloat xRot = 0.0f;
GLfloat yRot = 0.0f;

static int MenuID, SubMenuID;

int wired = 0;


void BitmapText( GLfloat x, GLfloat y, char *string )
{
  int len, i;
  glRasterPos2f( x, y );
  len = (int) strlen ( string );
  for ( i = 0; i < len; i++ ){
    glutBitmapCharacter ( GLUT_BITMAP_HELVETICA_18, string[i] );
  }
}

void StrokeText( char *string )
{
  int len, i;
  len = (int) strlen ( string );
  for ( i = 0; i < len; i++ ){
    glutStrokeCharacter ( GLUT_STROKE_ROMAN, string[i] );
  }
}

// Called to draw scene
void RenderScene(void)
{
  // Clear the window with current clearing color
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  BitmapText(-20, 20, "Hello World!");

  glPushMatrix();
  glRotatef(xRot, 1.0f, 0.0f, 0.0f);
  glRotatef(yRot, 0.0f, 1.0f, 0.0f);

  // >> Modellezo programresz

  if(wired) {
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  } else {
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  }

  glColor3f(1.0, 1.0, 1.0);
  glutSolidCube(15);

  glColor3f(1.0, 0.0, 0.0);

  glPushMatrix();
  glTranslatef(-3.0, -5.0, 7.53);
  glScalef(0.1, 0.1, 0.1);
  StrokeText("1");
  glPopMatrix();

  glPushMatrix();
  glRotatef(90, 0.0, 1.0, 0.0 );
  glTranslatef(-3.0, -5.0, 7.53);
  glScalef(0.1, 0.1, 0.1);
  StrokeText("2");
  glPopMatrix();

  glPushMatrix();
  glRotatef(180, 0.0, 1.0, 0.0 );
  glTranslatef(-3.0, -5.0, 7.53);
  glScalef(0.1, 0.1, 0.1);
  StrokeText("3");
  glPopMatrix();

  glPushMatrix();
  glRotatef(270, 0.0, 1.0, 0.0 );
  glTranslatef(-3.0, -5.0, 7.53);
  glScalef(0.1, 0.1, 0.1);
  StrokeText("4");
  glPopMatrix();

  glPushMatrix();
  glRotatef(90, 1.0, 0.0, 0.0 );
  glTranslatef(-3.0, -5.0, 7.53);
  glScalef(0.1, 0.1, 0.1);
  StrokeText("5");
  glPopMatrix();

  glPushMatrix();
  glRotatef(-90, 1.0, 0.0, 0.0 );
  glTranslatef(-3.0, -5.0, 7.53);
  glScalef(0.1, 0.1, 0.1);
  StrokeText("6");
  glPopMatrix();

  // << Modellezo programresz

  glPopMatrix();
  
  // Flush drawing commands
  glutSwapBuffers();
}

// This function does any needed initialization on the rendering
// context. 
void SetupRC()
{
  // Black background
  glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
  glEnable(GL_DEPTH_TEST);
}

void SpecialKeys(int key, int x, int y)
{
  // ...
  int state;

  if(key == GLUT_KEY_UP)
    xRot-= 5.0f;
  
  if(key == GLUT_KEY_DOWN)
    xRot += 5.0f;
  
  if(key == GLUT_KEY_LEFT)
    yRot -= 5.0f;
  
  if(key == GLUT_KEY_RIGHT)
    yRot += 5.0f;
  
  if(xRot > 356.0f)
    xRot = 0.0f;
  
  if(xRot < 0.0f)
    xRot = 355.0f;
  
  if(yRot > 356.0f)
    yRot = 0.0f;
  
  if(yRot < -1.0f)
    yRot = 355.0f;

  printf("Funkciobillentyu lenyomva, kodja %d, pozicio (%d,%d). ", key, x, y);
  state = glutGetModifiers();
  if(state & GLUT_ACTIVE_SHIFT)
    printf("SHIFT lenyomva. ");
  if(state & GLUT_ACTIVE_CTRL)
    printf("CTRL lenyomva. ");
  if(state & GLUT_ACTIVE_ALT)
    printf("ALT lenyomva. ");
  printf("\n");
  fflush(stdout);

  // Refresh the Window
  glutPostRedisplay();
}

void Keyboard(unsigned char key, int x, int y)
{
  // ...
  int state;

  printf("Billentyu lenyomva, kodja %c, pozicio (%d,%d). ", key, x, y);
  state = glutGetModifiers();
  if(state & GLUT_ACTIVE_SHIFT)
    printf("SHIFT lenyomva. ");
  if(state & GLUT_ACTIVE_CTRL)
    printf("CTRL lenyomva. ");
  if(state & GLUT_ACTIVE_ALT)
    printf("ALT lenyomva. ");
  printf("\n");
  fflush(stdout);

  glutPostRedisplay();
}

void Timer(int value)
{
  printf("Timer esemeny (%d)\n", value);

  glutPostRedisplay();
  glutTimerFunc(1000, Timer, value + 1);
}

void ProcessMenu(int value)
{
  switch( value )
    {
    case 1:
      wired = !wired;
      break;
      
    case 2:
      exit(0);
      break;
      
    }
  
  glutPostRedisplay();
}

void Idle()
{

  glutPostRedisplay();
}

void ChangeSizeOrtho(int w, int h)
{
  GLfloat nRange = 25.0f;
  
  // Prevent a divide by zero
  if(h == 0)
    h = 1;
  
  // Set Viewport to window dimensions
  glViewport(0, 0, w, h);
  
  // Reset projection matrix stack
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  
  // Establish clipping volume (left, right, bottom, top, near, far)
  if (w <= h) 
    glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
  else 
    glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);
  
  // Reset Model view matrix stack
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}

void ChangeSizePerspective(GLsizei w, GLsizei h)
{
  GLfloat fAspect;
  
  // Prevent a divide by zero
  if(h == 0)
    h = 1;
  
  // Set Viewport to window dimensions
  glViewport(0, 0, w, h);
  
  fAspect = (GLfloat)w/(GLfloat)h;
  
  // Reset coordinate system
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  
  // Produce the perspective projection
  gluPerspective(60.0f,    // fovy
		 fAspect,  // aspect
		 10.0,     // zNear
		 100.0     // zFar
		 );
  gluLookAt(0.0, 0.0, 50.0, // eye
	    0.0, 0.0, 0.0,  // center
	    0.0, 1.0, 0.0   // up
	    );
  
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
}

int main(int argc, char* argv[])
{
  // >> Inicializalas

  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
  //glutInitWindowSize(300, 300);
  glutCreateWindow("GLUT Alap");

  // << Inicializalas

  /* Főmenü készítése */
  MenuID = glutCreateMenu( ProcessMenu );
  glutAddMenuEntry( "Wired/Filled rendering", 1 );
  glutAddMenuEntry( "Exit", 2 );
  glutAttachMenu( GLUT_RIGHT_BUTTON ); /* Menü a jobb egérgomb lenyomására jelenik majd meg. */

  // >> Callback fuggvenyek

  glutReshapeFunc(ChangeSizeOrtho); // Parhuzamos vetites
  //glutReshapeFunc(ChangeSizePerspective); // Perspektiv vetites

  glutSpecialFunc(SpecialKeys);
  glutKeyboardFunc(Keyboard);
  glutDisplayFunc(RenderScene);
  //glutTimerFunc(1000, Timer, 1); // 1 mp mulva meghivodik a Timer() fuggveny
  //glutIdleFunc(Idle); // Idle(), ha nem tortenik semmi
  
  // << Callback fuggvenyek

  SetupRC();
  glutMainLoop();
  
  return 0;
}