package com.io7m.javagl1;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.GLProfile;
import javax.media.opengl.fixedfunc.GLMatrixFunc;

import com.jogamp.newt.event.KeyEvent;
import com.jogamp.newt.event.KeyListener;
import com.jogamp.newt.event.WindowAdapter;
import com.jogamp.newt.event.WindowEvent;
import com.jogamp.newt.opengl.GLWindow;
import com.jogamp.opengl.util.FPSAnimator;

public final class JavaGL1 implements GLEventListener, KeyListener
{
  static {
    GLProfile.initSingleton(true);
  }

  private static void initGL()
  {
    final GLProfile profile = GLProfile.getDefault();
    final GLCapabilities capabilities = new GLCapabilities(profile);
    final GLWindow window = GLWindow.create(capabilities);

    window.setSize(300, 300);
    window.setVisible(true);
    window.setTitle("NEWT Window Test");
    window.addWindowListener(new WindowAdapter() {
      @Override public void windowDestroyNotify(final WindowEvent arg0)
      {
        System.exit(0);
      }
    });

    final JavaGL1 test0 = new JavaGL1();
    window.addGLEventListener(test0);
    window.addKeyListener(test0);

    final FPSAnimator animator = new FPSAnimator(window, 1);
    animator.add(window);
    animator.start();
  }

  public static void main(final String[] args)
  {
    JavaGL1.initGL();
  }

  @Override public void dispose(final GLAutoDrawable drawable)
  {
    System.out.println("info: dispose");
  }

  @Override public void init(final GLAutoDrawable drawable)
  {
    System.out.println("info: init");
  }

  private void perspective (final GL2 gl, double width, double height, double fov_y, double z_near, double z_far)
  {
    final double aspect_ratio = width / height;
    final double fr_height = Math.tan(fov_y / 360 * Math.PI) * z_near;
    final double fr_width = fr_height * aspect_ratio;
    gl.glFrustum(-fr_width, fr_width, -fr_height, fr_height, z_near, z_far);
  }
  
  int screen_width = 0;
  int screen_height = 0;
  
  private float cam_pos_x = 0.0f;
  private float cam_pos_y = 0.0f;
  private float cam_pos_z = -50.0f;

  private void location()
  {
    System.out.println("info: location: x: " + this.cam_pos_x + " y: " + this.cam_pos_y + " z: " + this.cam_pos_z);
  }

  private void render(final GL2 gl)
  {
    System.out.println("info: render " + System.nanoTime());
    
    gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
    gl.glLoadIdentity();
    this.perspective(gl, this.screen_width, this.screen_height, 45.0, 0.1, 100.0);
    
    gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
    gl.glLoadIdentity();

    gl.glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
    gl.glClear(GL.GL_COLOR_BUFFER_BIT);

    gl.glTranslatef(0.0f, 0.0f, -50.f);
    gl.glColor3f((float) Math.random(), (float) Math.random(), (float) Math.random());
    gl.glBegin(GL.GL_TRIANGLES);
    gl.glVertex3f(this.cam_pos_x, this.cam_pos_y, 0.0f);
    gl.glVertex3f(this.cam_pos_x, this.cam_pos_y + 20.f, 0.0f);
    gl.glVertex3f(this.cam_pos_x + 20.f, this.cam_pos_y, 0.0f);
    gl.glEnd();
  }

  @Override public void display(final GLAutoDrawable drawable)
  {
    System.out.println("info: display " + System.nanoTime());

    final GL2 gl = drawable.getGL().getGL2();
    this.render(gl);
  }

  @Override public void reshape(final GLAutoDrawable drawable,
                                final int x,
                                final int y,
                                final int width,
                                final int height)
  {
    System.out.println("info: resize " + x + "," + y + "+" + width + "x" + height);
    
    this.screen_width = width;
    this.screen_height = height;
    
    final GL2 gl = drawable.getGL().getGL2();
    gl.glViewport(0, 0, width, height);
  }

  @Override public void keyPressed(final KeyEvent arg0)
  {
    // Nothing.
  }

  @Override public void keyReleased(final KeyEvent event)
  {
    System.out.println("info: key " + event.getKeyChar());

    switch (event.getKeyChar()) {
      case 'w':
        this.cam_pos_z += 10.0f;
        break;
      case 's':
        this.cam_pos_z -= 10.0f;
        break;
      case 'a':
        this.cam_pos_x += 10.0f;
        break;
      case 'd':
        this.cam_pos_x -= 10.0f;
        break;
      case 'f':
        this.cam_pos_y += 10.0f;
        break;
      case 'v':
        this.cam_pos_y -= 10.0f;
        break;
      default:
        break;
    }

    this.location();
  }

  @Override public void keyTyped(final KeyEvent arg0)
  {
    // Nothing.
  }
}
