import java.io.*;
import java.nio.FloatBuffer;
import java.util.*;

/** CS400 3DMotionCapture
 * OBJ
 * 
 * Reads the obj format files to construct a 3D model
 * @author Kohei Shinkawa*/


public class OBJ {
	
	ArrayList<double[]> vList = new ArrayList<double[]>(); //List of vertices
	ArrayList<FloatBuffer> vtList = new ArrayList<FloatBuffer>(); //List of texture coordinates
	ArrayList<float[]> vnList = new ArrayList<float[]>(); //List of normal vectors
	ArrayList<OBJPart> partsList = new ArrayList<OBJPart>(); //List of sub-divisional information
	String filename, mtlfile;
	
	public OBJ(){	
	}
	
	public OBJ(String filename){
		this.filename = filename;
		this.mtlfile = filename.split("\\.")[0]+".mtl";
		readFile(filename);
		joinParts();
	}
	
	public OBJ(String filename, String mtlfile){
		this.filename = filename;
		this.mtlfile = mtlfile;
		readFile(filename);
		joinParts();
	}
	
	/*If the obj file contains multiple sections for the same usemtl, join the two parts
	 * (This helps to reduce the time for constructing the object)*/
	private void joinParts(){
		ArrayList<OBJPart> newpartsList = new ArrayList<OBJPart>();
		while(partsList.size() != 0){
			OBJPart part = partsList.get(0);
			partsList.remove(0);
			for(int i =0; i< partsList.size(); i++){
				OBJPart temp = partsList.get(i);
				if(temp.usemtl.compareTo(part.usemtl) ==0){
					partsList.remove(i);
					part.join(temp);
				}
			}
		newpartsList.add(part);
		}
		partsList = newpartsList;
	}
	
	
	public ArrayList<double[]> getVList() {
		return vList;
	}

	public ArrayList<OBJPart> getParts() {
		return partsList;
	}
	
	public ArrayList<FloatBuffer> getvtList(){
		return vtList;
	}
	
	public ArrayList<float[]> getVnList() {
		return vnList;
	}

	/*Append a new vertex to the current list (*Order of vertices matters)*/
	private void addV(String str){
		StringTokenizer st = new StringTokenizer(str);
		st.nextToken();
		double[] coord = new double[3];
		for(int i =0; i < 3; i++){
			coord[i] = Double.valueOf(st.nextToken());
		}
		vList.add(coord);
	}
	/*Add a new texture coordinate to the current list*/
	private void addVt(String str){
		StringTokenizer st = new StringTokenizer(str);
		st.nextToken();
		float[] coord = new float[2];
		for(int i =0; i < 2; i++){
			if(i == 0)coord[i] = Float.valueOf(st.nextToken());
			else coord[i] = 1-Float.valueOf(st.nextToken());
		}
		vtList.add(FloatBuffer.wrap(coord));
	}
	
	/*Add a new normal vector to the current list*/
	private void addVn(String str){
		StringTokenizer st = new StringTokenizer(str);
		st.nextToken();
		float[] coord = new float[3];
		for(int i =0; i < 3; i++){
			if(i == 0)coord[i] = Float.valueOf(st.nextToken());
			else coord[i] = 1-Float.valueOf(st.nextToken());
		}
		vnList.add(coord);
	}
	
	/*Read the obj file to extract all the information*/
	public void readFile(String filename){
		BufferedReader reader = null;
		OBJPart part = null;
		try{
			FileInputStream fstream = new FileInputStream(filename);
			// Get the object of DataInputStream
			DataInputStream in = new DataInputStream(fstream);
			reader = new BufferedReader(new InputStreamReader(in));
			String strLine;
			while ((strLine = reader.readLine()) != null)   {
					if(strLine.startsWith("usemtl")){
						if(part != null){
							partsList.add(part);
						}
						part = new OBJPart(mtlfile, strLine.split(" ")[1]);
					}
					else if(strLine.startsWith("f ")){
						part.addF(strLine);
						part.addVt(strLine);
						part.addVn(strLine);
					}
					else if (strLine.startsWith("v ")){
						addV(strLine);
					}
					else if(strLine.startsWith("vt ")){
						addVt(strLine);
					}
					else if(strLine.startsWith("vn ")){
						addVn(strLine);
					}
			}
			partsList.add(part);
		}catch(IOException ioe){
			ioe.printStackTrace();
		}
	}


}
