package cz.fidentis.analyst.newgui.swing;

import com.jogamp.opengl.GLCapabilities;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.awt.GLCanvas;
import cz.fidentis.analyst.face.HumanFace;
import cz.fidentis.analyst.mesh.io.ModelFileFilter;
import com.jogamp.opengl.util.FPSAnimator;
import cz.fidentis.analyst.newgui.Drawable;
import cz.fidentis.analyst.newgui.Scene;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;

/**
 * OpenGL canvas.
 * 
 * @author Natalia Bebjakova 
 * @author Radek Oslejsek
 */
public class Canvas extends javax.swing.JPanel {
    
    private final GLCanvas glCanvas;
    
    /**
     * Frequency of the rotation or zoom animations
     */
    private static final int FPS = 60; 
    
    /**
     * Animator used when the rotation or scale buttons are pressed and held
     */
    private final FPSAnimator animator;
    
    /*
     * Animatio timer
     */
    private long startClickTime = 0;
    private TimerTask task;
    private Timer timer;
    
    private final Scene scene = new Scene();
    
    private final CanvasListener listener;
    private final MouseRotationListener manipulator;
    
    /**
     * Constructor.
     */
    public Canvas() {
        initComponents();
        
        // gl version 2 is used
        GLCapabilities capabilities = new GLCapabilities(GLProfile.get(GLProfile.GL2));
        capabilities.setDoubleBuffered(true);
       
        // creates new glCanvas panel for displaying model
        glCanvas = new GLCanvas(capabilities);
        jPanel1.add(glCanvas);
        glCanvas.setVisible(true);     
        glCanvas.setBackground(Color.black);
        
        // enables glCanvas to react to events
        glCanvas.requestFocusInWindow();        
        glCanvas.setSize(getWidth() - getInsets().left - getInsets().right, getHeight() - getInsets().top - getInsets().bottom);
       
        // enables animated transition 
        animator = new FPSAnimator(glCanvas, FPS, true);

        listener = new CanvasListener(this);
        glCanvas.addGLEventListener(listener);
        
        manipulator = new MouseRotationListener(this);
        glCanvas.addMouseListener(manipulator);
        glCanvas.addMouseMotionListener(manipulator);
        glCanvas.addMouseWheelListener(manipulator);
        
        this.validate();   
    }
   
    /**
     * Returns the scene
     * @return the scene
     */
    public Scene getScene() {
        return scene;
    }
    
    /**
     * Returns the underlying OpenGL canvas.
     * 
     * @return the underlying OpenGL canvas.
     */
    public GLCanvas getGLCanvas() {
        return this.glCanvas;
    }
    
    /**
     * Changing the size of glCanvas
     * 
     * @param d New size of glCanvas
     */
    public void resizeCanvas(Dimension d) {
        jPanel1.setSize(d);
        glCanvas.setSize(d);
        this.validate();
        this.repaint();
    }
    
    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     * 
     * Generated code from NetBeans
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jLayeredPane1 = new javax.swing.JLayeredPane();
        resetButton = new javax.swing.JLabel();
        upNavigationButton = new javax.swing.JButton();
        leftNavigationButton = new javax.swing.JButton();
        minusNavigationButton = new javax.swing.JButton();
        downNavigationButton = new javax.swing.JButton();
        plusNavigationButton = new javax.swing.JButton();
        jLabel1 = new javax.swing.JLabel();
        rightNavigationButton1 = new javax.swing.JButton();
        whiteBackroundButton = new javax.swing.JLabel();
        blackBackroundButton = new javax.swing.JLabel();
        jPanel1 = new javax.swing.JPanel();

        setBackground(new java.awt.Color(0, 0, 0));
        setLayout(new java.awt.BorderLayout());

        jLayeredPane1.setBackground(new java.awt.Color(40, 40, 40));
        jLayeredPane1.setToolTipText("");
        jLayeredPane1.setOpaque(true);
        jLayeredPane1.addComponentListener(new java.awt.event.ComponentAdapter() {
            public void componentResized(java.awt.event.ComponentEvent evt) {
                jLayeredPane1ComponentResized(evt);
            }
            public void componentShown(java.awt.event.ComponentEvent evt) {
                jLayeredPane1ComponentShown(evt);
            }
        });

        resetButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resetButton.png"))); // NOI18N
        resetButton.setToolTipText("Reset position of model");
        resetButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        resetButton.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
            public void mouseMoved(java.awt.event.MouseEvent evt) {
                resetButtonMouseMoved(evt);
            }
        });
        resetButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                resetButtonMouseClicked(evt);
            }
            public void mouseExited(java.awt.event.MouseEvent evt) {
                resetButtonMouseExited(evt);
            }
        });
        jLayeredPane1.add(resetButton);
        resetButton.setBounds(60, 40, 30, 30);

        upNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/upButton.png"))); // NOI18N
        upNavigationButton.setToolTipText("Rotate up");
        upNavigationButton.setBorderPainted(false);
        upNavigationButton.setContentAreaFilled(false);
        upNavigationButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        upNavigationButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                upNavigationButtonMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                upNavigationButtonMouseReleased(evt);
            }
        });
        jLayeredPane1.setLayer(upNavigationButton, javax.swing.JLayeredPane.MODAL_LAYER);
        jLayeredPane1.add(upNavigationButton);
        upNavigationButton.setBounds(60, 10, 30, 30);

        leftNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/leftButton.png"))); // NOI18N
        leftNavigationButton.setToolTipText("Rotate left");
        leftNavigationButton.setBorderPainted(false);
        leftNavigationButton.setContentAreaFilled(false);
        leftNavigationButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        leftNavigationButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                leftNavigationButtonMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                leftNavigationButtonMouseReleased(evt);
            }
        });
        jLayeredPane1.setLayer(leftNavigationButton, javax.swing.JLayeredPane.MODAL_LAYER);
        jLayeredPane1.add(leftNavigationButton);
        leftNavigationButton.setBounds(30, 40, 30, 30);

        minusNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/minus.png"))); // NOI18N
        minusNavigationButton.setToolTipText("Zoom out");
        minusNavigationButton.setBorderPainted(false);
        minusNavigationButton.setContentAreaFilled(false);
        minusNavigationButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        minusNavigationButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                minusNavigationButtonMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                minusNavigationButtonMouseReleased(evt);
            }
        });
        jLayeredPane1.setLayer(minusNavigationButton, javax.swing.JLayeredPane.MODAL_LAYER);
        jLayeredPane1.add(minusNavigationButton);
        minusNavigationButton.setBounds(90, 90, 30, 30);

        downNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/downButton.png"))); // NOI18N
        downNavigationButton.setToolTipText("Rotate down");
        downNavigationButton.setBorderPainted(false);
        downNavigationButton.setContentAreaFilled(false);
        downNavigationButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        downNavigationButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                downNavigationButtonMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                downNavigationButtonMouseReleased(evt);
            }
        });
        jLayeredPane1.setLayer(downNavigationButton, javax.swing.JLayeredPane.MODAL_LAYER);
        jLayeredPane1.add(downNavigationButton);
        downNavigationButton.setBounds(60, 70, 30, 30);

        plusNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/plus.png"))); // NOI18N
        plusNavigationButton.setToolTipText("Zoom in");
        plusNavigationButton.setBorderPainted(false);
        plusNavigationButton.setContentAreaFilled(false);
        plusNavigationButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        plusNavigationButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                plusNavigationButtonMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                plusNavigationButtonMouseReleased(evt);
            }
        });
        jLayeredPane1.setLayer(plusNavigationButton, javax.swing.JLayeredPane.MODAL_LAYER);
        jLayeredPane1.add(plusNavigationButton);
        plusNavigationButton.setBounds(30, 90, 30, 30);

        jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/navigBackground.png"))); // NOI18N
        jLayeredPane1.add(jLabel1);
        jLabel1.setBounds(30, 10, 90, 90);

        rightNavigationButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/rightButton.png"))); // NOI18N
        rightNavigationButton1.setToolTipText("Rotate right");
        rightNavigationButton1.setBorderPainted(false);
        rightNavigationButton1.setContentAreaFilled(false);
        rightNavigationButton1.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        rightNavigationButton1.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                rightNavigationButton1MousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                rightNavigationButton1MouseReleased(evt);
            }
        });
        jLayeredPane1.setLayer(rightNavigationButton1, javax.swing.JLayeredPane.MODAL_LAYER);
        jLayeredPane1.add(rightNavigationButton1);
        rightNavigationButton1.setBounds(90, 40, 30, 30);

        whiteBackroundButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/whiteBackroundCanvas.png"))); // NOI18N
        whiteBackroundButton.setToolTipText("White backround");
        whiteBackroundButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        whiteBackroundButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                whiteBackroundButtonMouseClicked(evt);
            }
        });
        jLayeredPane1.add(whiteBackroundButton);
        whiteBackroundButton.setBounds(50, 130, 56, 56);

        blackBackroundButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/blackBackroundCanvas.png"))); // NOI18N
        blackBackroundButton.setToolTipText("Dark background");
        blackBackroundButton.setCursor(new java.awt.Cursor(java.awt.Cursor.HAND_CURSOR));
        blackBackroundButton.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                blackBackroundButtonMouseClicked(evt);
            }
        });
        jLayeredPane1.add(blackBackroundButton);
        blackBackroundButton.setBounds(50, 190, 56, 56);

        jPanel1.setBackground(new java.awt.Color(0, 0, 0));
        jPanel1.setLayout(new java.awt.BorderLayout());
        jLayeredPane1.add(jPanel1);
        jPanel1.setBounds(0, 0, 0, 0);

        add(jLayeredPane1, java.awt.BorderLayout.CENTER);
    }// </editor-fold>//GEN-END:initComponents

    private void jLayeredPane1ComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_jLayeredPane1ComponentResized
        jPanel1.setBounds(0, 0, jLayeredPane1.getWidth(), jLayeredPane1.getHeight());
        glCanvas.setBounds(jLayeredPane1.getX(), jLayeredPane1.getY(), jLayeredPane1.getWidth(), jLayeredPane1.getHeight());
    }//GEN-LAST:event_jLayeredPane1ComponentResized

    private void jLayeredPane1ComponentShown(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_jLayeredPane1ComponentShown
        jPanel1.setBounds(0, 0, jLayeredPane1.getWidth(), jLayeredPane1.getHeight());
        glCanvas.setBounds(jLayeredPane1.getX(), jLayeredPane1.getY(), jLayeredPane1.getWidth(), jLayeredPane1.getHeight());
    }//GEN-LAST:event_jLayeredPane1ComponentShown

    private void leftNavigationButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftNavigationButtonMousePressed
        animator.start();
        timer = new Timer();
        startClickTime = System.currentTimeMillis();
        task = new TimerTask() {
            @Override
            public void run() {
                scene.getCamera().rotateLeft(2);
            }
        };
        timer.schedule(task, 500, 100);
        leftNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/leftButtonPressed.png")));
    }//GEN-LAST:event_leftNavigationButtonMousePressed

    private void upNavigationButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_upNavigationButtonMousePressed
        animator.start();
        timer = new Timer();
        startClickTime = System.currentTimeMillis();
        task = new TimerTask() {
            @Override
            public void run() {
                scene.getCamera().rotateUp(2);
            }
        };
        timer.schedule(task, 500, 100);
        upNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/upButtonPressed.png")));
    }//GEN-LAST:event_upNavigationButtonMousePressed

    private void downNavigationButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_downNavigationButtonMousePressed
        animator.start();
        timer = new Timer();
        startClickTime = System.currentTimeMillis();
        task = new TimerTask() {
            @Override
            public void run() {
                scene.getCamera().rotateDown(2);
            }
        };
        timer.schedule(task, 500, 100);
        downNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/downButtonPressed.png")));
    }//GEN-LAST:event_downNavigationButtonMousePressed

    private void plusNavigationButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_plusNavigationButtonMousePressed
        animator.start();
        timer = new Timer();
        startClickTime = System.currentTimeMillis();
        task = new TimerTask() {
            @Override
            public void run() {
                scene.getCamera().zoomIn(3);
            }
        };
        timer.schedule(task, 500, 100);
        plusNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/plusPressed.png")));
    }//GEN-LAST:event_plusNavigationButtonMousePressed
 
    private void minusNavigationButtonMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_minusNavigationButtonMousePressed
        animator.start();
        timer = new Timer();
        startClickTime = System.currentTimeMillis();
        task = new TimerTask() {
            @Override
            public void run() {
                scene.getCamera().zoomOut(3);
            }
        };
        timer.schedule(task, 500, 100);
        minusNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/minusPressed.png")));
    }//GEN-LAST:event_minusNavigationButtonMousePressed

    private void leftNavigationButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_leftNavigationButtonMouseReleased
        timer.cancel();
        if ((System.currentTimeMillis() - startClickTime) < 500) {
            scene.getCamera().rotateLeft(22.5);
        }
        startClickTime = 0;
        animator.stop();
        leftNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/leftButton.png")));
    }//GEN-LAST:event_leftNavigationButtonMouseReleased

    private void upNavigationButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_upNavigationButtonMouseReleased
        timer.cancel();
        if ((System.currentTimeMillis() - startClickTime) < 500) {
            scene.getCamera().rotateUp(22.5);
        }
        startClickTime = 0;
        animator.stop();
        upNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/upButton.png")));
    }//GEN-LAST:event_upNavigationButtonMouseReleased

    private void downNavigationButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_downNavigationButtonMouseReleased
        timer.cancel();
        if ((System.currentTimeMillis() - startClickTime) < 500) {
            scene.getCamera().rotateDown(22.5);
        }
        startClickTime = 0;
        animator.stop();
        downNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/downButton.png")));
    }//GEN-LAST:event_downNavigationButtonMouseReleased

    private void plusNavigationButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_plusNavigationButtonMouseReleased
        timer.cancel();
        if ((System.currentTimeMillis() - startClickTime) < 500) {
            scene.getCamera().zoomIn(30);
        }
        startClickTime = 0;
        animator.stop();
        plusNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/plus.png")));
    }//GEN-LAST:event_plusNavigationButtonMouseReleased

    private void minusNavigationButtonMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_minusNavigationButtonMouseReleased
        timer.cancel();
        if ((System.currentTimeMillis() - startClickTime) < 500) {
            scene.getCamera().zoomOut(30);
        }
        startClickTime = 0;
        animator.stop();
        minusNavigationButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/minus.png")));
    }//GEN-LAST:event_minusNavigationButtonMouseReleased

    private void rightNavigationButton1MousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightNavigationButton1MousePressed
        animator.start();
        timer = new Timer();
        startClickTime = System.currentTimeMillis();
        task = new TimerTask() {
            @Override
            public void run() {
                scene.getCamera().rotateRight(2);
            }
        };
        timer.schedule(task, 500, 100);
        rightNavigationButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/rightButtonPressed.png")));
    }//GEN-LAST:event_rightNavigationButton1MousePressed

    private void rightNavigationButton1MouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_rightNavigationButton1MouseReleased
        timer.cancel();
        if ((System.currentTimeMillis() - startClickTime) < 500) {
            scene.getCamera().rotateRight(22.5);
        }
        startClickTime = 0;
        animator.stop();
        rightNavigationButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/rightButton.png")));
    }//GEN-LAST:event_rightNavigationButton1MouseReleased

    private void resetButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_resetButtonMouseClicked
        scene.getCamera().initLocation();
        glCanvas.display();
    }//GEN-LAST:event_resetButtonMouseClicked

    private void resetButtonMouseMoved(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_resetButtonMouseMoved
        resetButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resetButtonPressed.png")));
        resetButton.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
    }//GEN-LAST:event_resetButtonMouseMoved

    private void resetButtonMouseExited(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_resetButtonMouseExited
        resetButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/resetButton.png")));
    }//GEN-LAST:event_resetButtonMouseExited

    private void whiteBackroundButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_whiteBackroundButtonMouseClicked
        scene.setBrightBackground();
        whiteBackroundButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/whiteBackroundCanvasPressed.png")));
        blackBackroundButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/blackBackroundCanvas.png")));
    }//GEN-LAST:event_whiteBackroundButtonMouseClicked

    private void blackBackroundButtonMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_blackBackroundButtonMouseClicked
        scene.setDarkBackground();
        whiteBackroundButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/whiteBackroundCanvas.png")));
        blackBackroundButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/blackBackroundCanvasPressed.png")));
    }//GEN-LAST:event_blackBackroundButtonMouseClicked

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel blackBackroundButton;
    private javax.swing.JButton downNavigationButton;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLayeredPane jLayeredPane1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JButton leftNavigationButton;
    private javax.swing.JButton minusNavigationButton;
    private javax.swing.JButton plusNavigationButton;
    private javax.swing.JLabel resetButton;
    private javax.swing.JButton rightNavigationButton1;
    private javax.swing.JButton upNavigationButton;
    private javax.swing.JLabel whiteBackroundButton;
    // End of variables declaration//GEN-END:variables
}
