// a parser that would read monster.txt file

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

public class Parser
{
public static BufferedReader  BR;
public static String          LINE;
public static String          TOKEN;
public static StringTokenizer TKNZR;
public static int             STATE;
public static int             LN;    
//--------- optimization ---------
public static void init_static()
    {
	STATE = 0;
    }
//--------------------------------
    
public static void parse(BufferedReader is)
    {
	LN = 0;
	BR = is;
	polyDEF     polydef  = null;
	bodypartDEF bpdef    = null;
	modelDEF    modeldef = null;
	double       A        = 0;
	double       B        = 0;
	double       C        = 0;

	String      name_0   = "undefined 2";
	String      name_1   = "undefined 1";
	int         index_0  = 0;
	int         index_1  = 0;
	vector      Rxyz     = null;
	vector      Dxyz     = null;
	vector      Crgb     = null;	
	boolean     comment  = false;
	int         trantype = -1; // 0 = rotate, 1 = translate
	int         animtype = -1; // 0 = bounce, 1 = cycle
	int         axis     = -1; // 0 = X, 1 = Y, 2 = Z
	double       start    = 0;
	double       stop     = 0;
	int         steps    = 0;
	
	while(true)
	    {
		LINE = nextline(BR);
		LN++;
		if(LINE==null)
		    break;
		TKNZR = new StringTokenizer(LINE);
		while(TKNZR.hasMoreTokens())
		    {
			TOKEN = TKNZR.nextToken();
			if(TOKEN.equals("/*"))
			    comment = true;
			if(TOKEN.equals("*/"))
			    {
				comment = false;
				continue;
			    }
			if(comment)
			    continue;
			
//			System.out.println("    -> "+STATE);			
//			System.out.print("state "+STATE+"  token "+TOKEN);
			if(STATE == 0)
			    {
				if(TOKEN.equals("polygon"))
				    STATE = 10;
				else if(TOKEN.equals("bodypart"))
				    STATE = 100;
				else if(TOKEN.equals("model"))
				    STATE = 1000;
				else
				    {
					System.err.println("line: "+LN+" expecting \'polygon\', \'bodypart\' or \'model\',  recieved"+TOKEN);
					STATE = 0;
				    }
			    }
			else if(STATE == 10)
			    {
				polydef = new polyDEF(TOKEN);
				STATE = 11;
			    }
			else if(STATE == 11)
			    {
				if(TOKEN.equals("{"))
				    STATE = 12;
				else
				    {
					System.err.println("line: "+LN+" parsing polygon "+polydef.name+", expecting \'{\', recieved"+TOKEN);
					STATE = 0;
				    }
			    }
			else if(STATE == 12)
			    {
				if(TOKEN.equals("vertices:"))
				    STATE = 13;
				else if(TOKEN.equals("normal:"))
				    STATE = 20;
				else
				    {
					System.err.println("line: "+LN+" parsing polygon "+polydef.name+", expecting \'vertices:\' or \'normal:\', recieved"+TOKEN);
					STATE = 0;
				    }
			    }
			else if(STATE == 13)
			    {
				A = stof(TOKEN);
				STATE = 14;
			    }
			else if(STATE == 14)
			    {
				B = stof(TOKEN);
				STATE = 15;
			    }
			else if(STATE == 15)
			    {
				C = stof(TOKEN);
				polydef.insert(new vector(A, B, C));
				STATE = 16;
			    }
			else if(STATE == 16)
			    {
				if(TOKEN.equals("normal:"))
				    STATE = 20;
				else
				    {
					A = stof(TOKEN);
					STATE = 14;
				    }
			    }
			else if(STATE == 20)
			    {
				if(TOKEN.equals("solve"))
				    {
					polydef.solve_normal();
					STATE = 30;
				    }
				else
				    {
					A = stof(TOKEN);
					STATE = 21;
				    }
			    }
			else if(STATE == 21)
			    {
				B = stof(TOKEN);
				STATE = 22;
			    }
			else if(STATE == 22)
			    {
				C = stof(TOKEN);
				polydef.set_normal(new vector(A, B, C));
				STATE = 30;
			    }
			else if(STATE == 30)
			    {
				if(TOKEN.equals("}"))
				    {
					STATE = 0;
					polygonDB.insert(polydef);
				    }
				else
				    {
					System.err.println("line: "+LN+" parsing polygon "+polydef.name+", expecting \'}\', recieved"+TOKEN);
					STATE = 0;
				    }
			    }
			else if(STATE == 100)
			    {
				bpdef = new bodypartDEF(TOKEN);
				STATE = 101;
			    }
			else if(STATE == 101)
			    {
				if(TOKEN.equals("{"))
				    STATE = 102;
				else
				    {
					System.err.println("line: "+LN+" parsing bodypart "+bpdef.name+", expecting \'{\', recieved"+TOKEN);
					STATE = 0;
				    }
			    }
			else if(STATE == 102)
			    {
				if(TOKEN.equals("polygons:"))
				    STATE = 103;
				else
				    {
					System.err.println("line: "+LN+" parsing bodypart "+bpdef.name+", expecting \'polygons:\', recieved"+TOKEN);
					STATE = 0;
				    }
			    }
			else if(STATE == 103)
			    {
				if(TOKEN.equals("}"))
				    {
					STATE = 0;
					bodypartDB.insert(bpdef);
				    }
				else
				    bpdef.insert(TOKEN);
			    }
			else if(STATE == 1000)
			    {
				modeldef = new modelDEF(TOKEN);
				STATE = 1001;
			    }
			else if(STATE == 1001)
			    {
				if(TOKEN.equals("{"))
				    STATE = 1002;
				else
				    {
					System.err.println("line: "+LN+" parsing model "+modeldef.name+", expecting \'{\', recieved"+TOKEN);
					STATE = 0;
				    }				
			    }
			else if(STATE == 1002)
			    {
				if(TOKEN.equals("origin:"))
				    STATE = 1003;
				else if(TOKEN.equals("connect:"))
				    STATE = 1100;
				else if(TOKEN.equals("animate:"))
				    STATE = 1200;
				else if(TOKEN.equals("}"))
				    {
					STATE = 0;
					modelDB.insert(modeldef);
				    }
				else
				    {
					System.err.println("line: "+LN+" parsing model "+modeldef.name+", expecting \'origin:\', \'connect:\' or \'}\', recieved"+TOKEN);
					STATE = 0;
				    }
			    }
			else if(STATE == 1003)
			    {
				modeldef.set_origin(TOKEN);
				STATE = 1004;
			    }
			else if(STATE == 1004)
			    {
				if(TOKEN.equals("Color:"))
				    STATE = 1005;
				else
				    {
					System.err.println("line: "+LN+" parsing model "+modeldef.name+", expecting \'Color:\', recieved"+TOKEN);
					STATE = 0;
				    }
			    }
			else if(STATE == 1005)
			    {
				A = stof(TOKEN);
				STATE = 1006;
			    }
			else if(STATE == 1006)
			    {
				B = stof(TOKEN);
				STATE = 1007;
			    }
			else if(STATE == 1007)
			    {
				C = stof(TOKEN);
				Crgb = new vector(A, B, C);
				modeldef.set_origin_bp_color(Crgb);
				STATE = 1002;
			    }
			else if(STATE == 1100)
			    {
				name_0 = TOKEN;
				STATE = 1101;
			    }
			else if(STATE == 1101)
			    {
				index_0 = stoi(TOKEN);
				STATE = 1102;
			    }
			else if(STATE == 1102)
			    {
				name_1 = TOKEN;
				STATE = 1103;
			    }
			else if(STATE == 1103)
			    {
				index_1 = stoi(TOKEN);
				STATE = 1104;
			    }
			else if(STATE == 1104)
			    {
				if(TOKEN.equals("Rxyz:"))
				    STATE = 1105;
				else
				    {
					System.err.println("line: "+LN+" parsing model "+modeldef.name+", expecting \'Rxyz:\', recieved"+TOKEN);
					STATE = 0;
				    }
			    }
			else if(STATE == 1105)
			    {
				A = stof(TOKEN);
				STATE = 1106;
			    }
			else if(STATE == 1106)
			    {
				B = stof(TOKEN);
				STATE = 1107;
			    }
			else if(STATE == 1107)
			    {
				C = stof(TOKEN);
				Rxyz = new vector(A*((double)Math.PI), B*((double)Math.PI), C*((double)Math.PI));
				STATE = 1108;
			    }
			else if(STATE == 1108)
			    {
				if(TOKEN.equals("Dxyz:"))
				    STATE = 1109;
				else
				    {
					System.err.println("line: "+LN+" parsing model "+modeldef.name+", expecting \'Dxyz:\', recieved"+TOKEN);
					STATE = 0;
				    }
			    }
			else if(STATE == 1109)
			    {
				A = stof(TOKEN);
				STATE = 1110;
			    }
			else if(STATE == 1110)
			    {
				B = stof(TOKEN);
				STATE = 1111;
			    }
			else if(STATE == 1111)
			    {
				C = stof(TOKEN);
				Dxyz = new vector(A, B, C);
				STATE = 1112;
			    }
			else if(STATE == 1112)
			    {
				if(TOKEN.equals("Color:"))
				    STATE = 1113;
				else
				    {
					System.err.println("line: "+LN+" parsing model "+modeldef.name+", expecting \'Color:\', recieved"+TOKEN);
					STATE = 0;
				    }
			    }
			else if(STATE == 1113)
			    {
				A = stof(TOKEN);
				STATE = 1114;
			    }
			else if(STATE == 1114)
			    {
				B = stof(TOKEN);
				STATE = 1115;
			    }
			else if(STATE == 1115)
			    {
				C = stof(TOKEN);
				Crgb = new vector(A, B, C);
				modeldef.insert(name_0, index_0, name_1, index_1, Rxyz, Dxyz, Crgb);
				STATE = 1002;
			    }
			else if(STATE == 1200)
			    {
				name_0 = TOKEN;
				STATE = 1201;
			    }
			else if(STATE == 1201)
			    {
				index_0 = stoi(TOKEN);
				STATE = 1202;
			    }
			else if(STATE == 1202)
			    {
				if(TOKEN.equals("rotate"))
				    trantype = 0;
				else if(TOKEN.equals("translate"))
				    trantype = 1;
				else if(TOKEN.equals("axis"))
				    STATE = 1210;
				else if(TOKEN.equals("start"))
				    STATE = 1220;
				else if(TOKEN.equals("stop"))
				    STATE = 1230;
				else if(TOKEN.equals("steps"))
				    STATE = 1240;
				else if(TOKEN.equals("bounce"))
				    {
					animtype = 0;
					STATE = 1002;
					if(trantype == 0)
					    {
						start = start*(double)(Math.PI);
						stop  = stop*(double)(Math.PI);
					    }
					modeldef.set_animation(name_0, index_0, trantype, animtype, axis, start, stop, steps);
				    }
				else if(TOKEN.equals("cycle"))
				    {
					animtype = 1;
					STATE = 1002;
					if(trantype == 0)
					    {
						start = start*(double)(Math.PI);
						stop  = stop*(double)(Math.PI);
					    }
					modeldef.set_animation(name_0, index_0, trantype, animtype, axis, start, stop, steps);
				    }
				else
				    {
					System.err.println("line: "+LN+" parsing model "+modeldef.name+
							   ", expecting \'rotate\', \'translate\', \'axis\', \'start\', \'stop\',"+
							   " \'steps\', \'bounce\', \'cycle\', recieved"+TOKEN);
					STATE = 0;
				    }
			    }
			else if(STATE == 1210)
			    {
				STATE = 1202;
				if(TOKEN.equals("x") || TOKEN.equals("X"))
				    axis = 0;
				else if(TOKEN.equals("y") || TOKEN.equals("Y"))
				    axis = 1;
				else if(TOKEN.equals("z") || TOKEN.equals("Z"))
				    axis = 2;
				else
				    {
					System.err.println("line: "+LN+" parsing model "+modeldef.name+", expecting \'x\', \'y\', \'z\', recieved"+TOKEN);
					STATE = 0;
				    }
			    }
			else if(STATE == 1220)
			    {
				start = stof(TOKEN);
				STATE = 1202;
			    }
			else if(STATE == 1230)
			    {
				stop  = stof(TOKEN);
				STATE = 1202;
			    }
			else if(STATE == 1240)
			    {
				steps = stoi(TOKEN);
				STATE = 1202;
			    }
		    }
	    }
    }

public static String nextline(BufferedReader is)
    {
        String s = null;	
        try
	    {
		s = is.readLine();
	    }
	catch(IOException e)
	    {
		System.out.println("Bad input file");
	    }
        return s;
    }
    
public static int stoi(String text)
    {
        int i = 0;
        try
	    {
		i = Integer.valueOf(text).intValue();
	    }
	catch(java.lang.NumberFormatException e)
	    {
		System.err.println("NumberFormatException on integer value: " + text);
		System.err.println(e.getMessage());
		System.exit(1);
	    }
        return i;
    } 
    
    
public static double stof(String text)
    {
        double f = 0.0f;
        try
	    {
		f = (double)(Float.valueOf(text).doubleValue());
	    }
	catch(java.lang.NumberFormatException e)
	    {
		System.err.println("NumberFormatException on double value: " + text);
		System.err.println(e.getMessage());
		System.exit(1);
	    }
        return f;
    } 
}

