OV.ExporterObj = class extends OV.ExporterBase
{
	constructor ()
	{
		super ();
	}

    CanExport (format, extension)
    {
        return format === OV.FileFormat.Text && extension === 'obj';
    }
    
	ExportContent (model, format, files)
	{
		function WriteTexture (mtlWriter, keyword, texture, files)
		{
			if (texture === null || !texture.IsValid ()) {
				return;
			}
			let fileName = OV.GetFileName (texture.name);
			mtlWriter.WriteArrayLine ([keyword, fileName]);

			let fileIndex = files.findIndex (function (file) {
				return file.GetName () === fileName;
			});
			if (fileIndex === -1) {
				let textureFile = new OV.ExportedFile (fileName);
				textureFile.SetUrl (texture.url);
				files.push (textureFile);
			}
		}

		let mtlFile = new OV.ExportedFile ('model.mtl');
		let objFile = new OV.ExportedFile ('model.obj');

		files.push (mtlFile);
		files.push (objFile);

		let mtlWriter = new OV.TextWriter ();
		for (let materialIndex = 0; materialIndex < model.MaterialCount (); materialIndex++) {
			let material = model.GetMaterial (materialIndex);
			mtlWriter.WriteArrayLine (['newmtl', this.GetExportedMaterialName (material.name)]);
			mtlWriter.WriteArrayLine (['Ka', material.ambient.r / 255.0, material.ambient.g / 255.0, material.ambient.b / 255.0]);
			mtlWriter.WriteArrayLine (['Kd', material.diffuse.r / 255.0, material.diffuse.g / 255.0, material.diffuse.b / 255.0]);
			mtlWriter.WriteArrayLine (['Ks', material.specular.r / 255.0, material.specular.g / 255.0, material.specular.b / 255.0]);
			mtlWriter.WriteArrayLine (['Ns', material.shininess * 100.0]);
			mtlWriter.WriteArrayLine (['d', material.opacity]);
			WriteTexture (mtlWriter, 'map_Kd', material.diffuseMap, files);
			WriteTexture (mtlWriter, 'map_Ks', material.specularMap, files);
			WriteTexture (mtlWriter, 'bump', material.bumpMap, files);
		}
		mtlFile.SetContent (mtlWriter.GetText ());

		let objWriter = new OV.TextWriter ();
		objWriter.WriteArrayLine (['mtllib', mtlFile.GetName ()]);
		let vertexOffset = 0;
		let normalOffset = 0;
		let uvOffset = 0;
		let usedMaterialName = null;
		for (let meshIndex = 0; meshIndex < model.MeshCount (); meshIndex++) {
			let mesh = model.GetMesh (meshIndex);
			objWriter.WriteArrayLine (['g', this.GetExportedMeshName (mesh.GetName ())]);
			for (let vertexIndex = 0; vertexIndex < mesh.VertexCount (); vertexIndex++) {
				let vertex = mesh.GetVertex (vertexIndex);
				objWriter.WriteArrayLine (['v', vertex.x, vertex.y, vertex.z]);
			}
			for (let normalIndex = 0; normalIndex < mesh.NormalCount (); normalIndex++) {
				let normal = mesh.GetNormal (normalIndex);
				objWriter.WriteArrayLine (['vn', normal.x, normal.y, normal.z]);
			}
			for (let textureUVIndex = 0; textureUVIndex < mesh.TextureUVCount (); textureUVIndex++) {
				let uv = mesh.GetTextureUV (textureUVIndex);
				objWriter.WriteArrayLine (['vt', uv.x, uv.y]);
			}
			for (let triangleIndex = 0; triangleIndex < mesh.TriangleCount (); triangleIndex++) {
				let triangle = mesh.GetTriangle (triangleIndex);
				let v0 = triangle.v0 + vertexOffset + 1;
				let v1 = triangle.v1 + vertexOffset + 1;
				let v2 = triangle.v2 + vertexOffset + 1;
				let n0 = triangle.n0 + normalOffset + 1;
				let n1 = triangle.n1 + normalOffset + 1;
				let n2 = triangle.n2 + normalOffset + 1;
				if (triangle.mat !== null) {
					let material = model.GetMaterial (triangle.mat);
					let materialName = this.GetExportedMaterialName (material.name);
					if (materialName !== usedMaterialName) {
						objWriter.WriteArrayLine (['usemtl', materialName]);
						usedMaterialName = materialName;
					}
				}
				let u0 = '';
				let u1 = '';
				let u2 = '';
				if (triangle.HasTextureUVs ()) {
					u0 = triangle.u0 + uvOffset + 1;
					u1 = triangle.u1 + uvOffset + 1;
					u2 = triangle.u2 + uvOffset + 1;					
				}
				objWriter.WriteArrayLine (['f', [v0, u0, n0].join ('/'), [v1, u1, n1].join ('/'), [v2, u2, n2].join ('/')]);
			}
			vertexOffset += mesh.VertexCount ();
			normalOffset += mesh.NormalCount ();
			uvOffset += mesh.TextureUVCount ();
		}

		objFile.SetContent (objWriter.GetText ());        
	}
};
