/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.fidentis.analyst.gui;

import com.jogamp.opengl.GL;
import static com.jogamp.opengl.GL.GL_FRONT_AND_BACK;
import static com.jogamp.opengl.GL.GL_VIEWPORT;
import com.jogamp.opengl.GL2;
import static com.jogamp.opengl.GL2GL3.GL_FILL;
import static com.jogamp.opengl.GL2GL3.GL_LINE;
import com.jogamp.opengl.GLAutoDrawable;
import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_MODELVIEW_MATRIX;
import static com.jogamp.opengl.fixedfunc.GLMatrixFunc.GL_PROJECTION_MATRIX;
import cz.fidentis.analyst.icp.Icp;
//import cz.fidentis.analyst.face.HumanFace;
import cz.fidentis.analyst.mesh.core.MeshFacet;
import cz.fidentis.analyst.mesh.core.MeshModel;
import cz.fidentis.analyst.mesh.core.MeshPoint;
import java.awt.Color;
import javax.vecmath.Vector3d;

/**
 *
 * @author Richard Pajersky
 */
public class RegistrationGLEventListener extends GeneralGLEventListener{
    
    private MeshModel primaryModel = null;
    private MeshModel secondaryModel = null;
    
    private Color primaryColor = Color.BLUE;
    private Color secondaryColor = Color.RED;
    
    private boolean other = false;
    
    private double leftPt = 0.0f;
    private double rightPt = 0.0f;
    private double topPt = 0.0f;
    private double bottomPt = 0.0f;
    private double farPt = 0.0f;
    private double nearPt = 0.0f;
    private Vector3d center;
    
    public RegistrationGLEventListener(Canvas primary, Canvas secondary) {
        super(primary);
    }
    
    private void calculateCenter(MeshModel model) {
        for (MeshFacet mf : model.getFacets()) {
            for (MeshPoint mp : mf.getVertices()) {
                Vector3d vert = mp.getPosition();
                if (vert.x > rightPt) {
                    rightPt = vert.x;
                }
                if (vert.x < leftPt) {
                    leftPt = vert.x;
                }
                if (vert.y > topPt) {
                    topPt = vert.y;
                }
                if (vert.y < bottomPt) {
                    bottomPt = vert.y;
                }
                if (vert.z > nearPt) {
                    nearPt = vert.z;
                }
                if (vert.z < farPt) {
                    farPt = vert.z;
                }
            }
        }
        double xc = (rightPt + leftPt) / 2.0f;
        double yc = (topPt + bottomPt) / 2.0f;
        double zc = (nearPt + farPt) / 2.0f;
        center = new Vector3d(xc, yc, zc);
    }
    
    @Override
    public void setModel(MeshModel model) {
        if (primaryModel == null) { 
            primaryModel = model;
        }
        else {
            Icp icp = new Icp();
            icp.setParameters(10, false, 0.05);
            MeshFacet facet = icp.getTransformedFacet(primaryModel.getFacets().get(0), model.getFacets().get(0));
            MeshModel newModel = new MeshModel();
            newModel.addFacet(facet);
            secondaryModel = newModel;
        }
    }
    
    @Override
    public void display(GLAutoDrawable glad) {
        wireModel = glCanvas.getDrawWired(); // is wire-frame or not
        if (whiteBackround) {
            gl.glClearColor(0.9f,0.9f,0.9f,0); 
        } else {
            gl.glClearColor(0.25f,0.25f,0.25f,0);
        }
        // background for GLCanvas       
        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
        gl.glLoadIdentity();

        // sets model to proper position
        glu.gluLookAt(xCameraPosition, yCameraPosition, zCameraPosition, xCenter, yCenter, zCenter, xUpPosition, yUpPosition, zUpPosition);

        gl.glShadeModel(GL2.GL_SMOOTH);
        gl.glGetIntegerv(GL_VIEWPORT, viewport, 0);
        gl.glGetFloatv(GL_MODELVIEW_MATRIX, modelViewMatrix, 0);
        gl.glGetFloatv(GL_PROJECTION_MATRIX, projectionMatrix, 0);
        
        //if there is any model, draw 
        if (primaryModel != null) {
            if (wireModel) {
                gl.glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); //drawn as wire-frame
                drawWithoutTextures(primaryModel);
                if (secondaryModel != null)
                    drawWithoutTextures(secondaryModel);
            } else {
                gl.glPolygonMode( GL_FRONT_AND_BACK, GL_FILL); // drawn as full traingles
                drawWithoutTextures(primaryModel);
                if (secondaryModel != null)
                    drawWithoutTextures(secondaryModel);
            }
        } 
            
        //gl.glPopMatrix();
        gl.glFlush();
    }
    
    /**
     * Loops through the facets and render each of them 
     * 
     * @param model model of the face
     */
    @Override
    public void drawWithoutTextures(MeshModel model) {
        for (int i = 0; i < model.getFacets().size(); i++) {
            renderFacet(model.getFacets().get(i));
        }
        other = !other;
    }
    
    /**
     * Loops through the facet and render all the vertices as they are stored in corner table
     * 
     * @param facet facet of model
     */
    @Override
    public void renderFacet(MeshFacet facet) {
        gl.glBegin(GL2.GL_TRIANGLES); //vertices are rendered as triangles
        // get the normal and tex coords indicies for face i  
        for (int v = 0; v < facet.getCornerTable().getSize(); v++) { 
            // render the normals
            Vector3d norm; 
            norm = facet.getVertices().get(facet.getCornerTable().getRow(v).getVertexIndex()).getNormal();
            if(norm != null) {
                gl.glNormal3d(norm.x, norm.y, norm.z);
            }
            // render the vertices
            Vector3d vert; 
            vert = facet.getVertices().get(facet.getCornerTable().getRow(v).getVertexIndex()).getPosition();
            //Color c = Color.GREEN;
            if (other && secondaryModel != null)
                gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, secondaryColor.getComponents(null), 0);
            else
                gl.glMaterialfv(GL2.GL_FRONT_AND_BACK, GL2.GL_DIFFUSE, primaryColor.getComponents(null), 0);
            gl.glVertex3d(vert.x, vert.y, vert.z);
        }
        gl.glEnd();
    }
    
    public Color getPrimaryColor() {
        return primaryColor;
    }

    public void setPrimaryColor(Color primaryColor) {
        this.primaryColor = primaryColor;
    }

    public Color getSecondaryColor() {
        return secondaryColor;
    }

    public void setSecondaryColor(Color secondaryColor) {
        this.secondaryColor = secondaryColor;
    }
    
}
