package JautOGL;


import java.io.*;
import java.util.ArrayList;
import java.util.StringTokenizer;
//import java.applet.*;
//import java.awt.*;
//import java.awt.event.*;
import javax.media.opengl.*;
import javax.media.opengl.glu.*;
//import com.sun.opengl.util.*; // GLUT, FPSAnimator


// import net.java.games.jogl.*;
// import net.java.games.jogl.util.*;

public class GLModel{

    private ArrayList vertexsets;
    private ArrayList vertexcolorsets;
    private boolean hasVertexColor;
    private ArrayList vertexsetsnorms;
    private ArrayList vertexsetstexs;
    private ArrayList faces;
    private ArrayList facestexs;
    private ArrayList facesnorms;
    private ArrayList mattimings;
    private MtlLoader materials;
    private int objectlist;
    private int numpolys;
    public float toppoint;
    public float bottompoint;
    public float leftpoint;
    public float rightpoint;
    public float farpoint;
    public float nearpoint;
    private String mtl_path;

	//THIS CLASS LOADS THE MODELS	
    public GLModel(BufferedReader ref, boolean centerit, String path, GL gl){
        
        mtl_path=path;
        vertexsets = new ArrayList();
        vertexcolorsets = new ArrayList();
        hasVertexColor = false;
        vertexsetsnorms = new ArrayList();
        vertexsetstexs = new ArrayList();
        faces = new ArrayList();
        facestexs = new ArrayList();
        facesnorms = new ArrayList();
        mattimings = new ArrayList();
        numpolys = 0;
        toppoint = 0.0F;
        bottompoint = 0.0F;
        leftpoint = 0.0F;
        rightpoint = 0.0F;
        farpoint = 0.0F;
        nearpoint = 0.0F;
        loadobject(ref,gl);
        if(centerit)
            centerit();
        opengldrawtolist(gl);
        numpolys = faces.size();
       // cleanup();
    }

    private void cleanup(){
        vertexsets.clear();
        vertexsetsnorms.clear();
        vertexsetstexs.clear();
        faces.clear();
        facestexs.clear();
        facesnorms.clear();
    }
    private float [] HexToRgb(String hex){
    	int num = Integer.parseInt(hex, 16);
    	float rgb[] = new float[4];
    	rgb[0] = (num & 0xFF0000) >> 16;
    	rgb[1] = (num & 0xFF00) >> 8;
    	rgb[2] = num & 0xFF;
    	rgb[0]/=255;
    	  rgb[1]/=255;
    	  rgb[2]/=255;
    	  rgb[3]=1f;
    	  return rgb;
    	 //_stprintf(output, _T("%d, %d, %d"), b1, b2, b3);
    	}
    private void loadobject(BufferedReader br, GL gl){
    	int linecounter = 0;
    	int facecounter = 0;
        try{
            boolean firstpass = true;
            String newline;
            while((newline = br.readLine()) != null){
              	linecounter++;
                if(newline.length() > 0){
                    newline = newline.trim();
                    
                    //LOADS VERTEX COORDINATES
                    if(newline.startsWith("v ")){
                        float coords[] = new float[4];
                        float colors[] = new float[4];
                        String coordstext[] = new String[4];
                        newline = newline.substring(2, newline.length());
                        StringTokenizer st = new StringTokenizer(newline, " ");
                        
                        for(int i = 0; st.hasMoreTokens(); i++){
                        	String str = st.nextToken();
                        	if(str.charAt(0) == '#'){
                        		hasVertexColor = true;
                        		colors = HexToRgb(str.substring(1));
                        	}else
                            coords[i] = Float.parseFloat(str);
                        }
                        if(firstpass){
                            rightpoint = coords[0];
                            leftpoint = coords[0];
                            toppoint = coords[1];
                            bottompoint = coords[1];
                            nearpoint = coords[2];
                            farpoint = coords[2];
                            firstpass = false;
                        }
                        if(coords[0] > rightpoint)
                            rightpoint = coords[0];
                        if(coords[0] < leftpoint)
                            leftpoint = coords[0];
                        if(coords[1] > toppoint)
                            toppoint = coords[1];
                        if(coords[1] < bottompoint)
                            bottompoint = coords[1];
                        if(coords[2] > nearpoint)
                            nearpoint = coords[2];
                        if(coords[2] < farpoint)
                            farpoint = coords[2];
                        vertexsets.add(coords);
                        vertexcolorsets.add(colors);
                    }
                    else
                    
                    //LOADS VERTEX TEXTURE COORDINATES
                    if(newline.startsWith("vt")){
                        float coords[] = new float[4];
                        String coordstext[] = new String[4];
                        newline = newline.substring(3, newline.length());
                        StringTokenizer st = new StringTokenizer(newline, " ");
                        for(int i = 0; st.hasMoreTokens(); i++)
                            coords[i] = Float.parseFloat(st.nextToken());

                        vertexsetstexs.add(coords);
                    }
                    else
                    
                    //LOADS VERTEX NORMALS COORDINATES
                    if(newline.startsWith("vn")){
                        float coords[] = new float[4];
                        String coordstext[] = new String[4];
                        newline = newline.substring(3, newline.length());
                        StringTokenizer st = new StringTokenizer(newline, " ");
                        for(int i = 0; st.hasMoreTokens(); i++)
                            coords[i] = Float.parseFloat(st.nextToken());

                        vertexsetsnorms.add(coords);
                    }
                    else
                    
                    //LOADS FACES COORDINATES
                    if(newline.startsWith("f ")){
                    	facecounter++;
                        newline = newline.substring(2, newline.length());
                        StringTokenizer st = new StringTokenizer(newline, " ");
                        int count = st.countTokens();
                        int v[] = new int[count];
                        int vt[] = new int[count];
                        int vn[] = new int[count];
                        for(int i = 0; i < count; i++){
                            char chars[] = st.nextToken().toCharArray();
                            StringBuffer sb = new StringBuffer();
                            char lc = 'x';
                            for(int k = 0; k < chars.length; k++){
                                if(chars[k] == '/' && lc == '/')
                                    sb.append('0');
                                lc = chars[k];
                                sb.append(lc);
                            }

                            StringTokenizer st2 = new StringTokenizer
                            (sb.toString(), "/");
                            int num = st2.countTokens();
                            v[i] = Integer.parseInt(st2.nextToken());
                            if(num > 1)
                                vt[i] = Integer.parseInt(st2.nextToken());
                            else
                                vt[i] = 0;
                            if(num > 2)
                                vn[i] = Integer.parseInt(st2.nextToken());
                            else
                                vn[i] = 0;
                        }

                        faces.add(v);
                        facestexs.add(vt);
                        facesnorms.add(vn);
                    }
                    else
                    
                    //LOADS MATERIALS
                    if (newline.charAt(0) == 'm' && newline.charAt(1) == 't' && newline.charAt(2) == 'l' && newline.charAt(3) == 'l' && newline.charAt(4) == 'i' && newline.charAt(5) == 'b') {
						String[] coordstext = new String[3];
						coordstext = newline.split("\\s+");
						if(mtl_path!=null)
							loadmaterials( gl);
					}
					else
					
					//USES MATELIALS
					if (newline.charAt(0) == 'u' && newline.charAt(1) == 's' && newline.charAt(2) == 'e' && newline.charAt(3) == 'm' && newline.charAt(4) == 't' && newline.charAt(5) == 'l') {
						String[] coords = new String[2];
						String[] coordstext = new String[3];
						coordstext = newline.split("\\s+");
						coords[0] = coordstext[1];
						coords[1] = facecounter + "";
						mattimings.add(coords);
						//System.out.println(coords[0] + ", " + coords[1]);
					}
                }
             }
        }
        catch(IOException e){
            System.out.println("Failed to read file: " + br.toString());
        }
        catch(NumberFormatException e){
            System.out.println("Malformed OBJ file: " + br.toString() + "\r \r"+ e.getMessage());
        }
    }
    
    private void loadmaterials(GL gl) {
		FileReader frm;
		String refm = mtl_path;

		try {
			frm = new FileReader(refm);
			BufferedReader brm = new BufferedReader(frm);
			int ind = mtl_path.lastIndexOf('/');
			String path = "";
			if (ind != -1)
			{
				path = mtl_path.substring(0, ind+1);		
			}
			materials = new MtlLoader(brm,path,gl);
			frm.close();
		} catch (IOException e) {
			System.out.println("Could not open file: " + refm);
			materials = null;
		}
	}

    private void centerit(){
        float xshift = (rightpoint - leftpoint) / 2.0F;
        float yshift = (toppoint - bottompoint) / 2.0F;
        float zshift = (nearpoint - farpoint) / 2.0F;
        for(int i = 0; i < vertexsets.size(); i++){
            float coords[] = new float[4];
            coords[0] = ((float[])vertexsets.get(i))[0] - leftpoint - xshift;
            coords[1] = ((float[])vertexsets.get(i))[1] - bottompoint - yshift;
            coords[2] = ((float[])vertexsets.get(i))[2] - farpoint - zshift;
            vertexsets.set(i, coords);
        }

    }

    public float getXWidth(){
        float returnval = 0.0F;
        returnval = rightpoint - leftpoint;
        return returnval;
    }

    public float getYHeight(){
        float returnval = 0.0F;
        returnval = toppoint - bottompoint;
        return returnval;
    }

    public float getZDepth(){
        float returnval = 0.0F;
        returnval = nearpoint - farpoint;
        return returnval;
    }

    public int numpolygons(){
        return numpolys;
    }

    public void opengldrawtolist(GL gl){
        ////////////////////////////////////////
		/// With Materials if available ////////
		////////////////////////////////////////
    	
		this.objectlist = gl.glGenLists(1);
		
		int nextmat = -1;
		int matcount = 0;
		int totalmats = mattimings.size();
		String[] nextmatnamearray = null;
		String nextmatname = null;
		
		if (totalmats > 0 && materials != null) {
			nextmatnamearray = (String[])(mattimings.get(matcount));
			nextmatname = nextmatnamearray[0];
			nextmat = Integer.parseInt(nextmatnamearray[1]);
		}

		gl.glNewList(objectlist,4864);
		gl.glPushAttrib(GL.GL_CURRENT_BIT|GL.GL_LIGHTING_BIT);
		if(hasVertexColor){
			gl.glColorMaterial(GL.GL_FRONT_AND_BACK,GL.GL_DIFFUSE);
			gl.glEnable(GL.GL_COLOR_MATERIAL);
		}
		for (int i=0;i<faces.size();i++) {
			if (i == nextmat) {
					//gl.glEnable(GL.GL_COLOR_MATERIAL);
					//gl.glColor4f((materials.getKd(nextmatname))[0],(materials.getKd(nextmatname))[1],(materials.getKd(nextmatname))[2],(materials.getd(nextmatname)));
				float ambient[] = new float[4];
				float diffuse[] = new float[4];
				float specular[] = new float[4];
				ambient[0]=materials.getKa(nextmatname)[0];
				ambient[1]=materials.getKa(nextmatname)[1];
				ambient[2]=materials.getKa(nextmatname)[2];
				ambient[3]=materials.getd(nextmatname);
				diffuse[0]=materials.getKd(nextmatname)[0];
				diffuse[1]=materials.getKd(nextmatname)[1];
				diffuse[2]=materials.getKd(nextmatname)[2];
				diffuse[3]=materials.getd(nextmatname);
				specular[0]=materials.getKs(nextmatname)[0];
				specular[1]=materials.getKs(nextmatname)[1];
				specular[2]=materials.getKs(nextmatname)[2];
				specular[3]=materials.getd(nextmatname);
				gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_AMBIENT, ambient,0);
				 gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_DIFFUSE, diffuse,0);
				 gl.glMaterialfv(GL.GL_FRONT_AND_BACK, GL.GL_SPECULAR, specular,0);
				 //gl.glMaterialf(GL.GL_FRONT_AND_BACK, GL.GL_SHININESS, shininess);
				
				
					gl.glEnable(GL.GL_TEXTURE_2D);
					gl.glTexEnvf(GL.GL_TEXTURE_ENV,GL.GL_TEXTURE_ENV_MODE,GL.GL_MODULATE);
					if(materials.getTexture(nextmatname)== null)
					{
						gl.glDisable(GL.GL_TEXTURE_2D);
					}
					else
							materials.getTexture(nextmatname).bind(gl);
					
				matcount++;
				if (matcount < totalmats) {
					nextmatnamearray = (String[])(mattimings.get(matcount));
					nextmatname = nextmatnamearray[0];
					nextmat = Integer.parseInt(nextmatnamearray[1]);
				}
			}
			
			int[] tempfaces = (int[])(faces.get(i));
			int[] tempfacesnorms = (int[])(facesnorms.get(i));
			int[] tempfacestexs = (int[])(facestexs.get(i));
			
			//// Quad Begin Header ////
			int polytype;
			if (tempfaces.length == 3) {
				polytype = gl.GL_TRIANGLES;
			} else if (tempfaces.length == 4) {
				polytype = gl.GL_QUADS;
			} else {
				polytype = gl.GL_POLYGON;
			}
			gl.glBegin(polytype);
			////////////////////////////
			
			for (int w=0;w<tempfaces.length;w++) {
				if (tempfacesnorms[w] != 0) {
					float normtempx = ((float[])vertexsetsnorms.get(tempfacesnorms[w] - 1))[0];
					float normtempy = ((float[])vertexsetsnorms.get(tempfacesnorms[w] - 1))[1];
					float normtempz = ((float[])vertexsetsnorms.get(tempfacesnorms[w] - 1))[2];
					gl.glNormal3f(normtempx, normtempy, normtempz);
				}
				
				if (tempfacestexs[w] != 0) {
					float textempx = ((float[])vertexsetstexs.get(tempfacestexs[w] - 1))[0];
					float textempy = ((float[])vertexsetstexs.get(tempfacestexs[w] - 1))[1];
					float textempz = ((float[])vertexsetstexs.get(tempfacestexs[w] - 1))[2];
					gl.glTexCoord3f(textempx,1f-textempy,textempz);
				}
				if(hasVertexColor){
					float rgb [] = ((float[])vertexcolorsets.get(tempfaces[w] - 1));
					
					gl.glColor4f(rgb[0],rgb[1],rgb[2],rgb[3]);
				}
				float tempx = ((float[])vertexsets.get(tempfaces[w] - 1))[0];
				float tempy = ((float[])vertexsets.get(tempfaces[w] - 1))[1];
				float tempz = ((float[])vertexsets.get(tempfaces[w] - 1))[2];
				gl.glVertex3f(tempx,tempy,tempz);
			}
			
			
			//// Quad End Footer /////
			gl.glEnd();
			///////////////////////////
			
			
		}
		gl.glDisable(GL.GL_COLOR_MATERIAL);
		gl.glPopAttrib();
		gl.glEndList();
	
	}    
    public void opengldraw(GL gl){
    	//gl.glEnable(GL.GL_COLOR_MATERIAL);
        gl.glCallList(objectlist);
        //gl.glDisable(GL.GL_COLOR_MATERIAL);
    }
}
