/* Model3DInputFilePolyMesh.java
 * Author: David Wanqian Liu
 * Date: Dec 20, 1995
 */


import java.io.*;
import java.awt.Color;


/** Parse a input file which defines polygon mesh of a 3D model
 */
class Model3DInputFilePolyMesh extends Model3DInputFile {
  Model3DInputFilePolyMesh(InputStream is) throws IOException,
                                                  FileFormatException,
                                                  FileContentException {
    super();

    StreamTokenizer st = new StreamTokenizer(is);

    st.eolIsSignificant(true);
    st.commentChar('#');

    scanHeader(st);
    scanVertices(st);
    scanEdges(st);
    scanFaces(st);
  }

  /** Scan input data file header. The file starts with 'begin', followed by
    two int numbers specifying number of vertices and number of edges */
  private void scanHeader(StreamTokenizer st) throws IOException,
                                                     FileFormatException,
                                                     FileContentException {
    while (true) {
      switch (st.nextToken()) {
      default:
	break;
	
      case StreamTokenizer.TT_EOL:
	break;
	
      case StreamTokenizer.TT_WORD:
	if ("begin".equals(st.sval)) {
	  
	  /* Skip till next number */
	  while (st.nextToken() != StreamTokenizer.TT_NUMBER) {};
	    
	  /* Read number of vertices */
	  nvertices = (int) st.nval;
	    
	  /* Read number of edges */
	  if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
	    nedges = (int) st.nval;
	  }
	  else
	    throw new FileFormatException();

	  /* Read number of faces */
	  if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
	    nfaces = (int) st.nval;
	  }
	  else
	    throw new FileFormatException();
 
	  return;
	}
	break;
      }
    }
  }
  
  
  /** Scan vertices from data file */
  private void scanVertices(StreamTokenizer st) throws IOException,
                                                       FileFormatException,
                                                       FileContentException {
    if (nvertices < 1)
      return;
    
    vertices = new Vertex[nvertices];
    // tvertices = new Vertex[nvertices];

    for (int i=0; i<nvertices; i++) {
      vertices[i] = new Vertex();
      // tvertices[i] = new Vertex();

      boolean finished = false;
      while (!finished) {
	switch (st.nextToken()) {
	default:
	  break;
	  
	case StreamTokenizer.TT_EOL:
	  break;
	  
	case StreamTokenizer.TT_NUMBER:
	  vertices[i].x = (float) st.nval;
	  
	  if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
	    vertices[i].y = (float) st.nval;
	  }
	  else
	    throw new FileFormatException();
	  
	  if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
	    vertices[i].z = (float) st.nval;
	  }
	  else
	    throw new FileFormatException();
	  
	  finished = true;
	  break;
	}
      }
    }
    
    return;
  }
  

  
  /** Scan edges from data file */
  private void scanEdges(StreamTokenizer st) throws IOException,
                                                    FileFormatException,
                                                    FileContentException {
    if (nedges < 1)
      return;
    
    edges = new Edge[nedges];
    for (int i=0; i<nedges; i++) {
      int v1=-1, v2=-1;
      
      boolean finished = false;
      while (!finished) {
	switch (st.nextToken()) {
	default:
	  break;
	  
	case StreamTokenizer.TT_EOL:
	  break;
	  
	case StreamTokenizer.TT_NUMBER:
	  v1 = (int) st.nval;
	  
	  if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
	    v2 = (int) st.nval;
	  }
	  else
	    throw new FileFormatException();
	  
	  /* Check vertex index range */
	  if ((v1<0) || (v2<0) || (v1>=nvertices) || (v2>=nvertices))
	    throw new FileContentException();
	  
	  edges[i] = new Edge(vertices[v1], vertices[v2]);

	  /* Read in the color definition for the face */
	  float r, g, b;

	  switch (st.nextToken()) {
	  default:
	    throw new FileFormatException();

	  case StreamTokenizer.TT_EOL:
	    r = 0.0f;
	    g = 0.0f;
	    b = 0.0f;
	    break;
	    
	  case StreamTokenizer.TT_NUMBER:
	    r = (float) st.nval;
	  
	    if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
	      g = (float) st.nval;
	    }
	    else
	      throw new FileFormatException();
	    
	    if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
	      b = (float) st.nval;
	    }
	    else
	      throw new FileFormatException();
	    
	    break;
	  }

	  edges[i].color = new Color(r, g, b);

	  finished = true;
	  break;
	}
      }
      
    }
    
    return;
  }


  /** Scan faces from data file */
  private void scanFaces(StreamTokenizer st) throws IOException,
                                                    FileFormatException,
                                                    FileContentException {
    if (nfaces < 1)
      return;
    
    faces = new Face[nfaces];
    for (int i=0; i<nfaces; i++) {
      boolean finished = false;
      while (!finished) {
	switch (st.nextToken()) {
	default:
	  break;
	  
	case StreamTokenizer.TT_EOL:
	  break;
	  
	case StreamTokenizer.TT_NUMBER:
	  /* Create ith face with st.nval number of vertices */
	  faces[i] = new Face((int) st.nval);
	  
	  /* Read in all the vertices */
	  for (int j=0; j<faces[i].nvertices; j++) {
	    if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
	      int v = (int) st.nval;
	      if (v < 0 || v >= this.nvertices)
		throw new FileContentException();

	      faces[i].vertices[j] = this.vertices[v];
	    }
	    else
	      throw new FileFormatException();
	  }

	  /* Read in the color definition for the face */
	  float r, g, b;

	  switch (st.nextToken()) {
	  default:
	    throw new FileFormatException();

	  case StreamTokenizer.TT_EOL:
	    r = 0.9f;
	    g = 0.7f;
	    b = 0.3f;
	    break;
	    
	  case StreamTokenizer.TT_NUMBER:
	    r = (float) st.nval;
	  
	    if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
	      g = (float) st.nval;
	    }
	    else
	      throw new FileFormatException();
	    
	    if (st.nextToken() == StreamTokenizer.TT_NUMBER) {
	      b = (float) st.nval;
	    }
	    else
	      throw new FileFormatException();
	    
	    break;
	  }

	  faces[i].color = new Color(r, g, b);
	  
	  finished = true;
	  break;
	}
      }
    }
    
    return;
  }


}
