package jomodel;


import java.io.*;
import java.util.*;


/** 
 * Import a 3DS file into a JOModel object.
 */
public class JO3DSImporter {

    // Reads the 3DS files into vertex and face lists 
    private JO3DSReader reader = new JO3DSReader();

    // Mesh object will hold the data in a renderable form
    private JOMesh mesh = new JOMesh();


    public JO3DSImporter() {
    }

    public JOMesh load(String filename) {
        System.out.println("JO3DSImporter.import(): Load object from " + filename);
        reader = new JO3DSReader(filename);
        System.out.println("JO3DSImporter.importFromStream(): model has " + reader.faces.size() + " faces and " + reader.vertices.size() + " vertices. ");
        return makeMeshObject(reader.vertices, reader.textureCoords, reader.normals, reader.faces );
    }

    /**
     * Load the 3DS file and store into a mesh.
     */
    public JOMesh importFromStream(InputStream inStream) {
        System.out.println("importFromStream(): Load object from stream...");
        reader.load3DSFromStream(inStream);
        System.out.println("importFromStream(): model has " + reader.faces.size() + " faces and " + reader.vertices.size() + " vertices and " + reader.textureCoords.size() + " txtrcoords."  );
        return makeMeshObject(reader.vertices, reader.textureCoords, reader.normals, reader.faces );
    }

    /**
     * create a GL_Object (mesh object) from the data read by a 3DS_Reader
     * @param verts   ArrayList of vertices
     * @param txtrs   ArrayList of texture coordinates
     * @param norms   ArrayList of normal 
     * @param faces   ArrayList of Face objects (triangles)
     * @return
     */
    public JOMesh makeMeshObject(ArrayList<float[]> verts, ArrayList<float[]> txtrs, ArrayList<float[]> norms, ArrayList<JOFace> faces ) {
        mesh = new JOMesh(); // mesh object
        mesh.name = "3DS";

        // add verts to JOMesh
        for (int i = 0; i < verts.size(); i++) {
            float[] coords = (float[]) verts.get(i);
            mesh.addVertex(coords[0], coords[1], coords[2]);
        }

        // add triangles to JOMesh.  3DS "face" is always a triangle.
        for (int i = 0; i < faces.size(); i++) {
            JOFace face = (JOFace) faces.get(i);
            // put verts, normals, texture coords into triangle
            addTriangle(mesh, face, txtrs, norms);
        }

        // optimize the JOMesh and generate normals
        mesh.rebuild(); 

        // if no normals were loaded, generate some
        if (norms.size() == 0) {
            mesh.regenerateNormals();
        }

        return mesh;
    }

    /**
     * Add a new triangle to the JOMesh.  This assumes that the 
     * vertices have already been added to the JOMesh, in the same
     * order that they were in the 3DS.
     * @param obj       JOMesh
     * @param face      a face from the OBJ file
     * @param txtrs     ArrayList of texture coords from the OBJ file
     * @param norms     ArrayList of normals from the OBJ file
     * @param v1        vertices to use for the triangle (face may have >3 verts)
     * @param v2
     * @param v3
     * @return
     */
    public JOTriangle addTriangle(JOMesh obj, JOFace face, 
            ArrayList<float[]> txtrs, ArrayList<float[]> norms) {
        // An OBJ face may have many vertices (can be a polygon).  
        // Make a new triangle with the specified three verts.
        JOTriangle t = new JOTriangle(
                obj.vertex(face.vertexIDs[0]), 
                obj.vertex(face.vertexIDs[1]), 
                obj.vertex(face.vertexIDs[2]));

        // put texture coords into triangle
        if (txtrs.size() > 0) {  // if texture coords were loaded
            float[] uvw;
            uvw = txtrs.get(face.textureIDs[0]); // txtr coord for vert 1
            t.uvw1 = new JOVector(uvw[0], uvw[1], uvw[2]);
            uvw = txtrs.get(face.textureIDs[1]); // txtr coord for vert 2
            t.uvw2 = new JOVector(uvw[0], uvw[1], uvw[2]);
            uvw = txtrs.get(face.textureIDs[2]); // txtr coord for vert 3
            t.uvw3 = new JOVector(uvw[0], uvw[1], uvw[2]);
        }

        // put normals into triangle (NOTE: normalID can be -1!!! could barf here!!!)
        if (norms.size() > 0) { // if normals were loaded
            float[] norm;
            norm = norms.get(face.normalIDs[0]); // normal for vert 1
            t.norm1 = new JOVector(norm[0], norm[1], norm[2]);
            norm = norms.get(face.normalIDs[1]); // normal for vert 2
            t.norm2 = new JOVector(norm[0], norm[1], norm[2]);
            norm = norms.get(face.normalIDs[2]); // normal for vert 3
            t.norm3 = new JOVector(norm[0], norm[1], norm[2]);
        }

        // add triangle to GL_object
        mesh.addTriangle(t);

        return t;
    }
}