/*
 * Author: Håvard Rast Blok
 * E-mail: hblok@usa.net
 * Web   : www.hblok.net
 */

import java.awt.Frame;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import com.hermetica.magician.GL;
import com.hermetica.magician.CoreGL;
import com.hermetica.magician.CoreGLU;
import com.hermetica.magician.GLDrawable;
import com.hermetica.magician.GLEventListener;
import com.hermetica.magician.GLU;
import com.hermetica.magician.GLComponent;
import com.hermetica.magician.GLComponentFactory;
import com.hermetica.magician.GLCapabilities;
import com.hermetica.magician.GLUQuadric;

public class StartClass extends Frame implements GLEventListener
{
  	private final double sqrt2 = Math.sqrt( 2.0 );
 	private final double sqrt2_div2 = sqrt2/2;
	private final float sqrt2_div2f = (float)sqrt2_div2;
	
	// The OpenGL state machine
	private GL gl;
	private GLU glu;
	
	// The OpenGL component to render onto
	private static GLComponent glc;
	private int width = 900;
	private int height = 500;
	
	private MouseHandler mouseHandler;
	
	//mouse move variables
	private int lastx;
	private int lasty;
	private float rotateX;
	private float rotateY;
	private boolean mouseMoving;


/******************************************************/
  public static void main( String argv[] )
 {
	 StartClass k = new StartClass();
	 //k.startDemo();
  }
/******************************************************/

  public StartClass()
  {
	
		gl = new CoreGL(); 
		glu = new CoreGLU();
		
		// Prepare drawing environment
		setLayout( new BorderLayout() );
		glc = GLComponentFactory.createGLComponent( getWidth(), getHeight() );
		add( "Center", glc );
		pack();
		show();
		
		// Setup the context capabilities */
		GLCapabilities cap = glc.getContext().getCapabilities();
		cap.setDepthBits( 12 );
		cap.setPixelType( GLCapabilities.RGBA );
		cap.setColourBits( 24 );
		cap.setRedBits( 1 );
		cap.setDoubleBuffered( GLCapabilities.DOUBLEBUFFER );
		
		// Register the GLComponentListener with the GLComponent
		glc.addGLEventListener( this );
		
		mouseHandler = new MouseHandler();
		glc.addMouseListener(mouseHandler);
		glc.addMouseMotionListener(mouseHandler);
		
		//vc = new ViewController( this, glc );
		addWindowListener( new CloseWindowAndExit() );
		
		// Initialize the component
		glc.initialize();
		
  }
	
	// Returns the width and height of the demo */
	public int getWidth()
	{
		return width;
	}
	public int getHeight()
	{
		return height;
	}
	
	public void initialize( GLDrawable component )
	{
	
		// Here we set the attributes that will be constant
		// during the rendering contexts lifetime
		gl.glEnable(GL.GL_DEPTH_TEST);
		gl.glDepthFunc(GL.GL_LESS);
		
		// prepare ligthsource
		float ambient[] = {0.0f,0.0f,0.0f,1.0f };
		float diffuse[] = {1.0f,1.0f,1.0f,1.0f };
		float position[] = {1.0f,1.0f,1.0f,0.0f };
		float lmodel_ambient[] = {0.4f,0.4f,0.4f,1.0f };
		
		gl.glLightfv(GL.GL_LIGHT0, GL.GL_AMBIENT, ambient);
		gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, diffuse);
		gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, position);
		
		gl.glEnable(GL.GL_LIGHT0);
		gl.glEnable(GL.GL_LIGHTING);
		gl.glEnable(GL.GL_COLOR_MATERIAL);
		
		// smooth the drawing
		gl.glShadeModel(GL.GL_SMOOTH);
		gl.glEnable(GL.GL_NORMALIZE);
		
		// set background to white
		gl.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
		
	}

  // Handles viewport resizing
  public void reshape( GLDrawable component, int x, int y, int width, int height )
  {
		// Setup the viewport
		
		gl.glViewport( component, 0, 0, width, height );
		gl.glMatrixMode( GL.GL_PROJECTION );
		gl.glLoadIdentity();
		glu.gluPerspective( 35.0, (float) width/height, 0.5, 50.0 );
		gl.glMatrixMode( GL.GL_MODELVIEW );
	
  }

  // produce the image
	public void display( GLDrawable component )
	{
		System.out.println("StartClass.display - start");
	
		// Clear the color and depth buffers.
		 gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
			
		// Set up for scene
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glLoadIdentity();
		
		// position the eye relative to scene
		glu.gluLookAt(	30.0f,0.0f,10.0f,  // eye
							0.0f,0.0f,15.0f,   // looking at
							0.0f,0.0f,1.0f);   // is up

		//rotate for mouse move
		gl.glRotatef( rotateX, 1.0f, 0.0f, 0.0f );
		gl.glRotatef( rotateY, 0.0f, 1.0f, 0.0f );


	}
	

  // Returns a GL pipeline from the listener
	public GL getGL()
	{
		return gl;
	}
	
	class MouseHandler implements MouseListener, MouseMotionListener
	{
		/** methods required for MouseListener and MouseMotionListener interfaces */
		public void mouseReleased(MouseEvent e)
		{
			/** object is not moving anymore */
			mouseMoving=false;
			/** repainting the complete tree */
			glc.repaint();
		}
		
		public void mouseEntered(MouseEvent e) {}
		public void mouseExited(MouseEvent e) {}
		public void mouseMoved(MouseEvent e) {}
		public void mouseClicked(MouseEvent e) {}
		
		public void mousePressed(MouseEvent e)
		{
			/** record mouse down coordinates */
			lastx = e.getX();
			lasty = e.getY();
			mouseMoving=true;
		}
		
	
		public void mouseDragged(MouseEvent e)
		{
			/** create a rotation quaternion that tracks the mouse movement */	
			int x = e.getX();
			int y = e.getY();
			//Dimension dim = e.getComponent().getSize();
			int width = getWidth();
			int height = getHeight();
	
			
			//find angles to rotate
			//when dragging mouse along the X-axis of the screen,
			//it makes sense to rotate around the Y-axis of the module (at least in this example)
			rotateY += (180.0f*((float)(x-lastx)/(float)(width)));
			rotateX += (-180.0f*((float)(y-lasty)/(float)(height)));
			
			lastx = x;
			lasty = y;
			
			glc.repaint();
		}
	}
	
	//inner class to handle closeing window
	
	class CloseWindowAndExit extends WindowAdapter
	{
		public void windowDeiconified( WindowEvent evt )
		{
			if ( glc.isRunning() )
			{
				glc.resume();
			}
		}
		
		public void windowIconified( WindowEvent evt )
		{
			if ( glc.isRunning() )
			{
				glc.suspend();
			}
		}
	
		public void windowClosing( WindowEvent e )
		{
			glc.destroy();
			dispose();
			System.exit( 0 );
		}
	}
	
}


