/**
* WebGL Model Viewer - ObjParser.js
* Copyright © Cyril Diagne 2010.
*
* @author kikko.fr
*/

ObjParser = function() {
	
	this.path = null;
	this.texturesURL = null;
	this.model = null;
	this.initTime = 0;
}

ObjParser.prototype = {
	
	events: new EventDispatcher(),
	
	load : function(url, texturesURL) {
		this.model = new Model();
		this.path = url.substring(0, url.lastIndexOf("/")+1);
		this.texturesURL = texturesURL || this.path;
		this.initTime = new Date().getTime();
		this.loadFile(url, this.parse);
	},
	
	loadFile : function(url, callback) {
		
		log("ObjParser: Loading:", url);
		
		var req = new XMLHttpRequest();
		var scope = this;
	  	req.onreadystatechange = function() {
			if(req.readyState == 4 && (req.status == 0 || req.status == 200)) {
				//scope.parse(req.responseText);
				callback.apply(scope, [req.responseText])
			}
		}
	    req.open("GET", url, true);
	    req.setRequestHeader("Content-Type", "text/plain");
		req.overrideMimeType("text/plain; charset=x-user-defined");
	  	req.send(null);
	},
	
	parse : function(data) {
		
		var i, w;
		this.model.meshes=[];
		var verts=[], uvs=[];
		var mesh = null;
		var pf = parseFloat;
		var lines = data.split("\n");
		var isMeshNew = false;
		var mtlibName=null;
		var currMtl;
		for (var i=0; i<lines.length; i++) {
			
			w = lines[i].split(" ");
			switch(w[0]) {
				
				case "mtllib":
					mtlibName = w[1];
					break;
				
				case "usemtl":
					currMtl = w[1];
					break;
				
				case "v":
					if(!isMeshNew) {
						log("ObjParser: found untitled mesh");
						mesh = new Mesh();
						mesh.name = "Untitled"
						this.model.meshes.push(mesh);
						isMeshNew = true;
					}
					var newVert = new Vertex([ pf(w[1]), pf(w[2]), pf(w[3]) ]);
					mesh.vertices.push( newVert );
					verts.push(newVert);
					break;
					
				case "vt":
					uvs.push( [pf(w[1]), pf(w[2])] );
					break;
				
				case "f":
					isMeshNew = false;
					var ids = [];
					var facesInfos = [];
					facesInfos.push([ w[1], w[2], w[3] ]);
					if(w.length > 4) facesInfos.push([ w[1], w[3], w[4] ]);
					
					for (var j=0; j<facesInfos.length; j++) {
						var faceDataArr = [];
						for(var k=0; k<facesInfos[j].length; k++) {
							var f = facesInfos[j][k];
							var a = f.split("/");
							var vId = parseInt(a[0]) - 1;
							var uvId = parseInt(a[1]) - 1;
							var v = verts[vId];
							// duplicate the vertex if it's uvId is different from obj's one
							if(v.uvId && v.uvId != uvId) {
								v = new Vertex(v.p);
								mesh.vertices.push(v);
								vId = mesh.vertices.length-1;
							}
							v.uvId = uvId;
							v.uv = uvs[uvId];
							vId = mesh.vertices.indexOf(v);
							faceDataArr.push(vId);
						}
						var face = new Face(faceDataArr);
						face.mat = currMtl;
						mesh.faces.push(face);
					}
					break;
				
				case "o":					
					mesh = new Mesh();
					mesh.name = w[1];
					this.model.meshes.push(mesh);
					isMeshNew = true;
					log("ObjParser: found mesh:", mesh.name);
					break;
			}
		}	
		
		var numMeshes = this.model.meshes.length;
		log("ObjParser:", numMeshes, "successfully loaded and parsed :");
		for(i=0; i<numMeshes; i++) {
			var mesh = this.model.meshes[i];
			log("ObjParser:", mesh.name, mesh.vertices.length, "vertices", mesh.faces.length, "faces");
		}
		
		if(mtlibName) {
			
			this.loadFile(this.path+"/"+mtlibName, this.parseMaterials);
		}
		else log("ObjParser: Error : no mtlib found.");
	},
	
	
	parseMaterials : function(data) {
		
		var w;
		var pf = parseFloat;
		var lines = data.split("\n");
		var mat;
		for (var i=0; i<lines.length; i++) {
			
			var w = lines[i].split(" ");
			switch(w[0]) {
				
				case "newmtl":
					mat = new Material(w[1]);
					this.model.materialList.push(mat);
					log("ObjParser: found material:", mat.name);
					break;
				case "Ns":
					mat.shininess = w[1];
					break;
				case "Ka":
					mat.ambient = w.splice(1, 3);
					break;
				case "Kd":
					mat.diffuse = w.splice(1, 3);
					break;
				case "Ks":
					mat.specular = w.splice(1, 3);
					break;
				case "map_Kd":
					mat.addMap("diffuse", w[1]);
					break;
				case "map_bump": case "bump":
					mat.addMap("normal", w[1]);
					break;
				case "map_Ks":
					mat.addMap("specular", w[1]);
					break;
				case "disp":
					mat.addMap("height", w[1]);
					break;
			}
		}
		
		TextureLibrary.events.addListener("texturesLoaded", this.textureLoaded, this);
		TextureLibrary.load(this.texturesURL);
	},
	
	
	textureLoaded : function(eventName) {
		
		TextureLibrary.events.removeListener("texturesLoaded", this.textureLoaded);
		
		this.model.events.addListener("modelReady", this.modelReadyHandler, this);
		this.model.init();
		
		
	},
	
	
	modelReadyHandler : function() {
	
		this.model.events.removeListener("modelReady", this.modelReadyHandler);
		
		log( "ObjParser: Total Time:",((new Date().getTime()-this.initTime)*0.001).toFixed(3)+"s" );
		this.events.dispatchEvent("loadSuccess");
	}
}
