// a simple unigrafix parser 
// eric brittain, ericb@mit.edu, mar 2005

import java.io.*;
import java.util.regex.*;
import java.util.*;

public class Unigrafix {    
    /*
adapted from http://www.cs.berkeley.edu/~sequin/CS285/SOL97/proj2/cube_simple.ug
v V0  0 0 0;
v V1  0 0 1;
v V2  0 1 0;
v V3  0 1 1;
v V4  1 0 0;
v V5  1 0 1;
v V6  1 1 0;
v V7  1 1 1;
f F0  (V0 V4 V5 V1);
f F1  (V2 V3 V7 V6);
f F2  (V1 V5 V7 V3);
f F3  (V2 V6 V4 V0);
f F4  (V5 V4 V6 V7);
f F5  (V0 V1 V3 V2);
     */    
    
    private static Hashtable parseVertices(String filename) throws IOException {
        BufferedReader br=null;
        Hashtable vertexHT = new Hashtable();
        br = new BufferedReader(new FileReader(filename));
        
        // parse vertices
        //String VERTEX_PATTERN = "v\\s+V(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\d+)\\s*;";
        String VERTEX_PATTERN = "v\\s+V(\\d+)\\s+(\\d+|\\d+.\\d+)\\s+(\\d+|\\d+.\\d+)\\s+(\\d+|\\d+.\\d+)\\s*;";
        Pattern vertexPattern = Pattern.compile(VERTEX_PATTERN);
        String line = null;
        while((line = br.readLine())!=null){
            //System.out.println("line = "+line);
            Matcher matcher = vertexPattern.matcher(line);
            while(matcher.find()){
                double x = Double.parseDouble(matcher.group(2));
                double y = Double.parseDouble(matcher.group(3));
                double z = Double.parseDouble(matcher.group(4));
                
                String vertexName = "V"+matcher.group(1);
                Vertex v = new Vertex(vertexName, x, y, z);
                vertexHT.put(vertexName, v);
                //System.out.println("v = "+v);
            }
        }
        
        br.close();
        return vertexHT;
    }
    
    private static Face[] parseFaces(String filename, Hashtable vertexHT)  throws IOException  {
        BufferedReader br=null;
        br = new BufferedReader(new FileReader(filename));
        
        ArrayList faceArray = new ArrayList();
        
        // parse faces
        String FACE_PATTERN = "f\\s+F(\\d+)\\s*\\(((\\s*\\w+)+)\\)";
        Pattern facePattern = Pattern.compile(FACE_PATTERN);
        String line = null;
        while((line = br.readLine())!=null){
            //System.out.println("line = "+line);
            Matcher matcher = facePattern.matcher(line);
            while(matcher.find()){
                // create face
                Face face = new Face("F"+matcher.group(1));
                faceArray.add(face);
                
                String vertexList = matcher.group(2);
                String[] vertexNameArray = vertexList.split(" ");
                
                // add vertices to face
                for(int i=0; i<vertexNameArray.length; i++){
                    String vertexName = vertexNameArray[i].trim();
                    Vertex vertex = (Vertex)vertexHT.get(vertexName);
                    if(vertex == null){
                        throw new RuntimeException("Vertex: "+vertexName+" is not in file.");
                    }
                    face.addVertex(vertex);
                }
            }
        }
        
        br.close();
        
        Object[] objArray = faceArray.toArray();
        Face[] faceArr = new Face[objArray.length];
        for(int i=0; i<objArray.length; i++){
            faceArr[i] = (Face)objArray[i];
        }
        
        return faceArr;
    }
    
    
    private Vertex[] vertexArray;
    public Vertex[] getVertexArray(){
        return this.vertexArray;
    }
    
    private Face[] faceArray;
    public Face[] getFaceArray(){
        return this.faceArray;
    }
    
    public Unigrafix(String filename) throws IOException {
        System.out.print("Parsing vertices....");
        Hashtable vertexHT = parseVertices(filename);
        System.out.println("done.");
        
        System.out.print("Parsing faces...");
        this.faceArray = parseFaces(filename, vertexHT);
        this.vertexArray = new Vertex[vertexHT.size()];
        int index = 0;
        for(Enumeration e = vertexHT.elements(); e.hasMoreElements();){
            this.vertexArray[index] = (Vertex)e.nextElement();
            index++;
        }
        System.out.println("done.");
    }
    
    public static void main(String[] args){
        try {
            Unigrafix ug = new Unigrafix(args[0]);

            Vertex[] vertices = ug.getVertexArray();
            for(int i=0; i < vertices.length; i++){
                System.out.println(vertices[i]);
            }
            
            Face[] faces = ug.getFaceArray();
            for(int i=0; i < faces.length; i++){
                System.out.println(faces[i]);
            }
            
        } catch(Exception e){
            e.printStackTrace();
        }
    }
    
    static class Vertex {
        private String name;
        private double x, y, z;
        public Vertex(String name, double x, double y, double z){
            this.name = name;
            this.x = x;
            this.y = y;
            this.z = z;
        }
        public String toString(){
            return name+" "+x+" "+y+" "+z;
        }
    }
    
    static class Face {
        private String name;
        private ArrayList vertexList = new ArrayList();
        public Face(String name){
            this.name = name;
        }
        public void addVertex(Vertex vertex){
            this.vertexList.add(vertex);
        }
        public String toString(){
            StringBuffer sb = new StringBuffer(name+" ");
            for(int i=0; i<vertexList.size(); i++){
                Vertex vertex = (Vertex)vertexList.get(i);
                sb.append("["+vertex.toString()+"] ");
            }
            return sb.toString();
        }
    }
}
