/**
 * Anima: A singular journey
 * CS470 Capstone Project
 * Shawn Aldridge
 */


package anima;

import com.sun.opengl.util.Animator;
import com.sun.opengl.util.FPSAnimator;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLCanvas;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.glu.GLU;
import javax.swing.JFrame;
import java.awt.event.*;
import com.sun.opengl.util.GLUT;
import javax.media.opengl.GLCapabilities;
import java.util.LinkedList;
import java.util.ArrayList;
import javax.swing.Timer;




/**
 * Display and controls for second level of Anima
 */
public class CutScene1 extends JFrame implements GLEventListener {

    GLCanvas canvas;
    float xgap, avX, avY, obstructOdds, shinyOdds;
    GL gl;
    int iteration, counter, problem, problemCounter, score, answer, time;
    LinkedList rowPositions, solutions;
    ArrayList obstructions, shinies;
    boolean avUp, avDown, avLeft, avRight, done;
    Sound background;
    float[] avatar, lines, shiny, ambientLight, lightPosition, whiteLight, glow;
    //Timer timer;




    public CutScene1()
    {
        super();
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        canvas = new GLCanvas();

        //setUndecorated(true);
        //setBounds(400, 400, 1200, 600);


        xgap = (float)(10.0 / 14.0);//gap between columns

        avX = avY = 5;
        avUp = false;
        avDown = false;
        avLeft = false;
        avRight = false;
        obstructOdds = 0.2f;
        shinyOdds = 0.02f;
        counter = 0;
        iteration = 0;

        done = false;


        lines = new float[4];
        lines[0] = 0.0f;
        lines[1] = 1.0f;
        lines[2] = 0.0f;
        lines[3] = 1.0f;

        lightPosition = new float[4];
        lightPosition[0] = 5.0f;
        lightPosition[1] = 5.0f;
        lightPosition[2] = 20.0f;
        lightPosition[3] = 1.0f;

        whiteLight = new float[4];
        whiteLight[0] = 1.0f;
        whiteLight[1] = 1.0f;
        whiteLight[2] = 1.0f;
        whiteLight[3] = 1.0f;

        ambientLight = new float[4];
        ambientLight[0] = 0.4f;
        ambientLight[1] = 0.4f;
        ambientLight[2] = 0.4f;
        ambientLight[3] = 1.0f;

        avatar = new float[4];
        avatar[0] = 0.0f;
        avatar[1] = 0.0f;
        avatar[2] = 1.0f;
        avatar[3] = 1.0f;

        shiny = new float[4];
        shiny[0] = 0.0f;
        shiny[1] = 0.0f;
        shiny[2] = 1.0f;
        shiny[3] = 1.0f;

        glow = new float[4];
        glow[0] = 1.0f;
        glow[1] = 0.0f;
        glow[2] = 0.0f;
        glow[3] = 1.0f;



        background = new Sound();
        //background.play("C:/Users/Owner/Documents/NetBeansProjects/anima/industry.wav");

        GLCapabilities caps = new GLCapabilities();
        caps.setDoubleBuffered(true);
        caps.setHardwareAccelerated(true);

        canvas.setFocusable(true);
        add(canvas);

        final FPSAnimator animator = new FPSAnimator(canvas, 60);
        setUndecorated(true);
        setExtendedState(this.MAXIMIZED_BOTH);

        setLocationRelativeTo(null);
        setVisible(true);
        animator.start();

    }

    /**
     * Sets my intial OpenGL state variables
     * @param drawable
     */
    public void init(GLAutoDrawable drawable) {

        gl = drawable.getGL();
        GLU glu = new GLU();

        // Setup the drawing area and shading mode
        gl.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        gl.glShadeModel(GL.GL_SMOOTH);
        gl.glEnable(GL.GL_DEPTH_TEST);

        gl.glEnable(GL.GL_LIGHTING);
        gl.glEnable(GL.GL_LIGHT0);
        gl.glEnable(GL.GL_DEPTH_TEST);

        gl.glMatrixMode(GL.GL_PROJECTION);
        gl.glLoadIdentity();
        gl.glOrtho(0, 10, 0, 10, 10, -10); //left, right, down, up, near, far
        gl.glMatrixMode(GL.GL_MODELVIEW);

    }

    /**
     * Method called when window is resized, included strictly as backup, as application
     * is displayed in full screen
     * @param drawable
     * @param x
     * @param y
     * @param width
     * @param height
     */
    public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) {
        gl = drawable.getGL();

        gl.glViewport(0, 0, width, height);

        gl.glMatrixMode(GL.GL_PROJECTION); /* switch matrix mode */
        gl.glLoadIdentity();
        gl.glOrtho(0, 10, 0, 10, 10, -10);
        gl.glMatrixMode(GL.GL_MODELVIEW); /* return to modelview mode */
    }


    /**
     * Draws the smaller orb used as an avatar in the first level
     * @param gl
     * @param avPosition
     * @param avY
     */
    private void avatar(GL gl, float x, float y)
    {
        gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE, avatar, 0);
        gl.glBegin(GL.GL_TRIANGLE_FAN);
        for(int i = 0; i < 180; i++)
        {
            float xcoor = (float)((0.04 * Math.cos(i)) + x);
            float ycoor = (float)(0.04 * Math.sin(i) + y);
            gl.glVertex2f(xcoor, ycoor);

            xcoor = (float)(0.04 * Math.cos(i + 0.1) + x);
            ycoor = (float)(0.04 * Math.sin(i + 0.1) + y);
            gl.glVertex2f(xcoor, ycoor);
        }
        gl.glEnd();
    }

    private void shiny(GL gl, ArrayList shinies)
    {
        gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE, shiny, 0);
        //gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_EMISSION, glow, 0);

        gl.glColor3f(1.0f, 0.82f, 0.0f);
        gl.glBegin(GL.GL_POLYGON);
        gl.glVertex2f((Float)shinies.get(0) + 0.25f, (Float)shinies.get(1) + 0.25f);
        gl.glVertex2f((Float)shinies.get(0) + 0.5f, (Float)shinies.get(1));
        gl.glVertex2f((Float)shinies.get(0) + 0.25f, (Float)shinies.get(1) - 0.25f);
        gl.glVertex2f((Float)shinies.get(0), (Float)shinies.get(1));
        gl.glEnd();
    }

    /**
     * Display method for OpenGL, gets called in a continuous loop by the animator
     * @param drawable
     */
    public void display(GLAutoDrawable drawable) {
        gl = drawable.getGL();
        GLU glu = new GLU();
        GLUT glut = new GLUT();


        // Clear the drawing area
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);


        gl.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, lightPosition, 0);
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_DIFFUSE, whiteLight, 0);
        gl.glLightfv(GL.GL_LIGHT0, GL.GL_SPECULAR, whiteLight, 0);
        gl.glLightModelfv(GL.GL_LIGHT_MODEL_AMBIENT, ambientLight, 0);
        // Reset the current matrix to the "identity"
        gl.glLoadIdentity();

        
        if((iteration > 500) && (iteration < 600))
        {
            gl.glMatrixMode(GL.GL_MODELVIEW);
            gl.glLoadIdentity();
            glu.gluLookAt((float)(iteration - 500) /50.0, 0.0, 10.0, (float)(iteration - 500) /50.0, 0.0, 0.0, 0.0, 1.0, 0.0);
        }else if((iteration  > 600) && (iteration < 800))
        {
            glu.gluLookAt(2.0f, 0.0, 10.0, 2.0f, 0.0, 0.0, 0.0, 1.0, 0.0);
            gl.glScalef((float)(1 + (0.01 * (iteration - 600))), (float)(1 + (0.01 * (iteration - 600))), 0.0f);
        }else if((iteration  > 800) && (iteration < 900))
        {
            glu.gluLookAt(2.0f, 0.0, 10.0, 2.0f, 0.0, 0.0, 0.0, 1.0, 0.0);
            gl.glScalef((float)2.0, (float)2.0, 0.0f);
            gl.glRotatef((float)(0.9 * (iteration - 800)), 1.0f, 0.0f, 0.0f);
        }else if((iteration  > 900) && (iteration < 1200))
        {
            gl.glLoadIdentity();
            glu.gluPerspective(90.0, 16.0/9.0, 1, 10);
            glu.gluLookAt(1.0f, 0.0, 0.2, 1.0f, 0.3, 0.0, 0.0, 0.0, 1.0);
        }else if(iteration > 1200) System.exit(1);


        gl.glBegin(GL.GL_LINES);
        gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE, lines, 0);

       
        //obtuse mass of absurdly dense vertex code
        for(int i = 0; i < 16; i++)
        {
            //right
            gl.glVertex2f(0, (float)(i * 0.1));
            gl.glVertex2f(3, (float)(i * 0.1));
            //up
            gl.glVertex2f((float)(3 - (i * 0.05)), (float)(i * 0.1));
            gl.glVertex2f((float)(3 - (i * 0.05)), 4);
            //right
            gl.glVertex2f((float)(3 - (i * 0.05)), 4 - (float)(i * 0.05));
            gl.glVertex2f((float)9.8, 4 - (float)(i * 0.05));
            //all the way up
            gl.glVertex2f((float)(9.8 - (i * 0.05)), 4 - (float)(i * 0.05));
            gl.glVertex2f((float)(9.8 - (i * 0.05)), 10);
            //cross lines
            gl.glVertex2f((float)(5 + (i * 0.05)), 0);
            gl.glVertex2f((float)(5 + (i * 0.05)), 10);
            //up again
            gl.glVertex2f((float)(7.5 + (i * 0.05)), 0);
            gl.glVertex2f((float)(7.5 + (i * 0.05)), 8);
            //left
            gl.glVertex2f((float)(7.5 + (i * 0.05)), (float)(8 - (i * 0.05)));
            gl.glVertex2f(1, (float)(8 - (i * 0.05)));
            //down
            gl.glVertex2f((float)(1 + (i * 0.05)), (float)(8 - (i * 0.05)));
            gl.glVertex2f((float)(1 + (i * 0.05)), 3);
            //left final
            gl.glVertex2f((float)(1 + (i * 0.05)), (float)(3 + (i * 0.05)));
            gl.glVertex2f(0, (float)(3 + (i * 0.05)));
        }
        
        for(int i = 0; i < 16; i++)
        {
            gl.glVertex2f((float)(1 + (i * 0.05)), (float)(3 + (i * 0.05)));
            gl.glVertex2f(0, (float)(3 + (i * 0.05)));
        }
        
        gl.glEnd();



        iteration++;
        iteration++;
        if(iteration < 100)
        {
        avatar(gl, 0.0f + (float)(iteration * 3.0/100.0) - 0.4f, 0.8f);
        avatar(gl, 0.0f + (float)(iteration * 3.0/100.0) - 0.6f, 1.2f);
        avatar(gl, 0.0f + (float)(iteration * 3.0/100.0) - 0.25f, 0.5f);
        }else if((iteration > 100) && (iteration < 200)){
            if((float)(0.8f + (iteration - 100) * 4.0/100.0) < 4.0)avatar(gl, 2.6f, (float)(0.8f + (iteration - 100) * 4.0/100.0));
            if((float)(1.2f + (iteration - 100) * 4.0/100.0) < 4.0)avatar(gl, 2.4f, (float)(1.2f + (iteration - 100) * 4.0/100.0));
            if((float)(0.5f + (iteration - 100) * 4.0/100.0) < 4.0)avatar(gl, 2.75f, (float)(0.5f + (iteration - 100) * 4.0/100.0));
        }else if((iteration > 200) && (iteration < 300)){
            if(2.6f + (iteration - 200) * 9.8f/100.0f < 7.7)avatar(gl, 2.6f + (iteration - 200) * 9.8f/100.0f, 3.6f);
            if(2.4 + (iteration - 200) * 9.8f/100.0f < 7.9)avatar(gl, 2.4f + (iteration - 200) * 9.8f/100.0f, 3.4f);
            if(2.75f + (iteration - 200) * 9.8f/100.0f < 7.75)avatar(gl, 2.75f + (iteration - 200) * 9.8f/100.0f, 3.75f);
            avatar(gl, 9.6f, (float)(10.0 - (iteration - 200) * 0.1) + 4);
            avatar(gl, 9.5f, (float)(10.0 - (iteration - 200) * 0.1) + 4);
            avatar(gl, 9.1f, (float)(10.0 - (iteration - 200) * 0.1) + 4);
        }else if((iteration > 300) && (iteration < 400)){
            if( 3.4f + (iteration - 300) * 8.0f/100.0f < 7.7)avatar(gl, 7.7f, 3.4f + (iteration - 300) * 8.0f/100.0f);
            if( 3.6f + (iteration - 300) * 8.0f/100.0f < 7.9)avatar(gl, 7.9f, 3.6f + (iteration - 300) * 8.0f/100.0f);
            if( 3.75f + (iteration - 300) * 8.0f/100.0f < 7.75)avatar(gl, 7.75f, 3.75f + (iteration - 300) * 8.0f/100.0f);
            avatar(gl, 5.0f, (float)10.0/(iteration - 300));
            avatar(gl, 5.2f, (float)10.0/(iteration - 300));
            avatar(gl, 5.4f, (float)10.0/(iteration - 300));
            if(9.6f - (iteration - 300) * 10.0f/100.0f > 3)avatar(gl, 9.6f - (iteration - 300) * 10.0f/100.0f, 3.6f);
            if(9.4 - (iteration - 300) * 10.0f/100.0f > 3)avatar(gl, 9.4f - (iteration - 300) * 10.0f/100.0f, 3.4f);
            if(9.75f - (iteration - 300) * 10.0f/100.0f > 3)avatar(gl, 9.75f - (iteration - 300) * 10.0f/100.0f, 3.75f);
        }else if((iteration > 400) && (iteration < 500)){
            if( 7.4f - (iteration - 400) * 8.0f/100.0f > 1)avatar(gl, 7.4f - (iteration - 400) * 8.0f/100.0f, 7.7f);
            if( 7.2f - (iteration - 400) * 8.0f/100.0f > 1)avatar(gl, 7.2f - (iteration - 400) * 8.0f/100.0f, 7.9f);
            if( 7.75f - (iteration - 400) * 8.0f/100.0f > 1)avatar(gl, 7.75f - (iteration - 400) * 8.0f/100.0f, 7.75f);
            if(2.6f + (iteration - 400) * 9.8f/100.0f > 1)avatar(gl, 2.6f, 4.0f - (iteration - 400) * 9.8f/100.0f);
            if(2.4 + (iteration - 400) * 9.8f/100.0f > 1)avatar(gl, 2.4f, 4.0f - (iteration - 400) * 9.8f/100.0f);
            if(2.75f + (iteration - 400) * 9.8f/100.0f > 1)avatar(gl, 2.75f, 4.0f - (iteration - 400) * 9.8f/100.0f);

        }else if((iteration > 500) && (iteration < 600)){
            if(7.7f - (iteration - 500) * 8.0f/100.0f > 3)avatar(gl, 1.2f, 7.7f - (iteration - 500) * 8.0f/100.0f);
            if( 7.9f - (iteration - 500) * 8.0f/100.0f > 3)avatar(gl, 1.5f, 7.9f - (iteration - 500) * 8.0f/100.0f);
            if( 7.75f - (iteration - 500) * 8.0f/100.0f > 3)avatar(gl, 1.6f, 7.75f - (iteration - 500) * 8.0f/100.0f);
            avatar(gl, 5.0f, (float)0.1 * (iteration - 500));
            avatar(gl, 5.2f, (float)0.1 * (iteration - 500));
            avatar(gl, 5.4f, (float)0.1 * (iteration - 500));
            avatar(gl, 3.0f - (float)((iteration - 500) * 3.0/100.0), 0.8f);
            avatar(gl, 3.0f - (float)((iteration - 500) * 3.0/100.0), 1.2f);
            avatar(gl, 3.0f - (float)((iteration - 500) * 3.0/100.0), 0.5f);
        }else if((iteration > 600) && (iteration < 700)){
            if( 1.2f - (iteration - 600) * 8.0f/100.0f > -1)avatar(gl, 1.2f - (iteration - 600) * 8.0f/100.0f, 3.2f);
            if( 1.5f - (iteration - 600) * 8.0f/100.0f > -1)avatar(gl, 1.5f - (iteration - 600) * 8.0f/100.0f, 3.4f);
            if( 1.6f - (iteration - 600) * 8.0f/100.0f > -1)avatar(gl, 1.6f - (iteration - 600) * 8.0f/100.0f, 3.75f);
        }else if(iteration > 900){
            done = true;
        }

        gl.glFlush();
    }

    //required method for OpenGL, not used in this implementation
    public void displayChanged(GLAutoDrawable drawable, boolean modeChanged, boolean deviceChanged) {}

    /**
     * Inner class to handle generated events
     */
    class InnerHandler implements ActionListener
    {

        public InnerHandler()
        {

        }

        public void actionPerformed(ActionEvent e)
        {

        }

    }//end class InnerHandler

}

