//
//    File: vrml1_mesh.cc
//
//    (C) 2000-2008 Helmut Cantzler
//
//    Licensed under the terms of the Lesser General Public License.
//

#include <string.h>

#include "vrml1_mesh.h"

int Vrml1Mesh::read(FILE *f, int (*updateProgress)(int pos),
		     void (*setTotal)(int size))
{
  char s1[101], s2[21];

  fseek(f, 0, SEEK_END);
  (*setTotal)(ftell(f));
  fseek(f, 0, SEEK_SET);

  if (fscanf(f,"%100s %20s", s1, s2) != 2) // Read header
    {
      FILE_ERROR(f, "VRML header format error");
      return 2;
    }

  while (fgetc(f) != '\n') // Reads till end of the line
    ;

  // check header
  if (strcasecmp(s1,"#VRML") != 0 || strcasecmp(s2,"V1.0") != 0)
    {
      FILE_ERROR(f, "VRML1 header format error");
      return 3;
    }

  list<Triangle*> *shapeTriangles;
  list<Vertex*> *shapeVertices;
  vector<Vertex*> *vertexIndex;
  Triangle *tri;
  Vertex *v;
  int res, shapeNr, textNo, p1, p2, p3, end;
  float x, y, z;

  shapeTriangles = new list<Triangle*>;
  shapeVertices = new list<Vertex*>;

  shapeNr=0;
  do
    {
      textNo=0;
      vertexIndex = new vector<Vertex*>;
      
      // look for vertices (points)
      do
	{
	  res=fscanf(f,"%100s",s1);
	}
      while (res != EOF && strcasecmp(s1,"Coordinate3") != 0);

      if ((*updateProgress)(ftell(f)))
	return 90;

      if (strcasecmp(s1,"Coordinate3") == 0)
	{
	  shapeNr++;

	  fscanf(f,"%100s",s1);
	  while (strcasecmp(s1,"point") != 0 && strcasecmp(s1,"}") != 0)
	    fscanf(f,"%100s",s1);
	  
	  if (strcasecmp(s1,"point") == 0)
	    {
	      while (fgetc(f) != '[') // Reads till begin of points
		 ;
	  
	      while (fscanf(f,"%f",&x) == 1)
	        {
		  if (fscanf(f,"%f %f%*c",&y,&z) != 2)
		    {
		      FILE_ERROR(f, "VRML file format error: v");
		      return 4;
		    }

		  v = new Vertex(x,y,z);
		  addVertex(v);

		  // save in a vector for the triangles and shape
		  vertexIndex->push_back(v);

		  if ((*updateProgress)(ftell(f)))
		    return 90;
		}
	    }
	}

      // look for triangles (faces)
      while (res != EOF && strcasecmp(s1,"IndexedFaceSet") != 0)
	  res=fscanf(f,"%100s",s1);

      if (strcasecmp(s1,"IndexedFaceSet") == 0)
	{
	  fscanf(f,"%100s",s1);
	  while (strcasecmp(s1,"coordIndex") != 0 && strcasecmp(s1,"}") != 0)
	    fscanf(f,"%100s",s1);

	  if (strcasecmp(s1,"coordIndex") == 0)
	    {
	      while (fgetc(f) != '[') // Reads till begin of triangles
		;
	  
	      while (fscanf(f,"%d%*c",&p1) == 1)
		{
		  if (fscanf(f,"%d%*c %d%*c",&p2,&p3) != 2)
		    {
		      FILE_ERROR(f, "VRML file format error: t");
		      return 5;
		    }

		  fscanf(f,"%d%*c",&end);
		  if (end == -1)
		    {
		      // number of points is 3 => ok
		      tri=new Triangle((*vertexIndex)[p1],
				       (*vertexIndex)[p2],
				       (*vertexIndex)[p3]);
		      addTriangle(tri);
		      shapeTriangles->push_back(tri);
		    }
		  else
		    // no end (-1) => seek to end (-1)
		    while (end != -1 && res == 1)
		      res=fscanf(f,"%d,",&end);

		  if ((*updateProgress)(ftell(f)))
		    return 90;
		}
	    }
	}

      // copy the vertices of this shape over
      shapeVertices->insert(shapeVertices->end(), 
			    vertexIndex->begin(), vertexIndex->end());

      delete vertexIndex;
    }
  while (res != EOF);

  shapes->push_back(new Shape(shapeTriangles, shapeVertices));

  return 0;
}

void Vrml1Mesh::write(FILE *f, const char *comment)
{
  int n;
  list<Triangle*>::iterator it;
  list<Vertex*>::iterator iv;
  Vertex v;

  fprintf(f,"#VRML V1.0 ascii\n");
  fprintf(f,"# %s\n", comment);
  fprintf(f,"Separator {\n");
  fprintf(f,"\tMaterial {\n");
  fprintf(f,"\t\tambientColor 0.2 0.2 0.2\n");
  fprintf(f,"\t\tdiffuseColor 1.0 1.0 1.0\n");
  fprintf(f,"\t}\n");

  fprintf(f,"\tCoordinate3 {\n");
  fprintf(f,"\t\t point [\n");
  n=0;   iv=vertices->begin();   // vertices
  if (iv != vertices->end())
    {
      calcOriginalCoordinates(*iv, &v);
      fprintf(f,"\t\t\t%f %f %f", v.x(), v.y(), v.z());
      (*iv)->number=n;
      for (iv++; iv != vertices->end(); iv++)
	{
	  calcOriginalCoordinates(*iv, &v);
	  fprintf(f,",\n\t\t\t%f %f %f", v.x(), v.y(), v.z());
	  n++;
	  (*iv)->number=n;
	}
    }
  fprintf(f," ]\n\t}\n");

  fprintf(f,"\tIndexedFaceSet {\n");
  fprintf(f,"\t\t coordIndex [\n");
  it=triangles->begin();   // triangles
  if (it != triangles->end())
    {
      fprintf(f,"\t\t\t%d, %d, %d, -1", (*it)->vertices[0]->number,
	      (*it)->vertices[1]->number, (*it)->vertices[2]->number);
      for (it++; it != triangles->end(); it++)
	fprintf(f,",\n\t\t\t%d, %d, %d, -1",
		(*it)->vertices[0]->number, (*it)->vertices[1]->number,
		(*it)->vertices[2]->number);
    }
  fprintf(f," ]\n\t}\n}\n");
}
