/*
================
DeclParser::Parse
================
*/
void DeclParser::Parse( Lexer &lexer ) {
	Dict *resultDict = OG_NULL;

	bool getKeyValue = false;

	int index;
	const Token *token;
	String key, value;

	const char *p;
	while ( (token = lexer.ReadToken()) != OG_NULL ) {
		p = token->GetString();
		if ( p ) {
			if ( *p == '\0' )
				lexer.Error("Unexpected Empty Token");
			if ( !getKeyValue ) {
				index = declTypes.Find(p);
				if ( index != -1 ) {
					value = lexer.ReadString();

					if ( value.IsEmpty() )
						lexer.Error("Empty name!");

					DictEx<Dict> &result = declTypes[index]->declList;
					index = result.Find(p);
					if ( index == -1 ) 
						resultDict = &result[p];
					else {
						resultDict = &result[index];
						resultDict->Clear();
					}
				} else {
					resultDict = OG_NULL;
					lexer.Warning( Format("Unknown decl Type '$*'") << p );
				}
				lexer.ExpectToken("{");
				getKeyValue = true;
			} else {
				if ( *p == '}' )
					getKeyValue = false;
				else if ( resultDict ) {
					key = p;
					(*resultDict).Set( key.c_str(), lexer.ReadString() );
				}
			}
		}
	}
	if ( getKeyValue )
		throw LexerError( LexerError::END_OF_FILE );
}
/*
================
ReadGeoMObject
================
*/
static void ReadGeoMObject( Lexer &lexer, ListEx<aseMesh> &myMeshList ) {
	lexer.ExpectToken("{");
	const char *p;
	const Token *token;
	String name;
	while ( (token = lexer.ReadToken()) != OG_NULL ) {
		p = token->GetString();
		if ( !p || !*p )
			continue;
		if ( String::Icmp( p, "}" ) == 0 ) 
			return;
		if ( String::Icmp( p, "*" ) != 0 ) 
			lexer.Error( Format("expected *, got '$*'") << p );

		if ( lexer.CheckToken( "NODE_NAME" ) )
			name = lexer.ReadString();
		else if ( lexer.CheckToken( "MESH" ) ) {
			aseMesh *inMesh = &myMeshList.Alloc();
			inMesh->name = name;
			ReadMesh( lexer, inMesh );
		}
		else if ( !SkipUnknown(lexer) )
			break;
	}
}
/*
================
ReadMaterial
================
*/
static void ReadMaterial( Lexer &lexer ) {
	lexer.ReadInt();
	lexer.ExpectToken("{");
	const char *p;
	const Token *token;
	while ( (token = lexer.ReadToken()) != OG_NULL ) {
		p = token->GetString();
		if ( !p || !*p )
			continue;
		if ( String::Icmp( p, "}" ) == 0 ) 
			return;
		if ( String::Icmp( p, "*" ) != 0 ) 
			lexer.Error( Format("expected *, got '$*'") << p );

		//! @todo	Finish this

		if ( !SkipUnknown(lexer) )
			break;
	}
}
/*
================
ReadMaterialList
================
*/
static void ReadMaterialList( Lexer &lexer ) {
	lexer.ExpectToken("{");
	const char *p;
	const Token *token;
	int numMaterials;
	while ( (token = lexer.ReadToken()) != OG_NULL ) {
		p = token->GetString();
		if ( !p || !*p )
			continue;
		if ( String::Icmp( p, "}" ) == 0 ) 
			return;
		if ( String::Icmp( p, "*" ) != 0 ) 
			lexer.Error( Format("expected *, got '$*'") << p );

		if ( lexer.CheckToken( "MATERIAL_COUNT" ) )
			numMaterials = lexer.ReadInt();
		else if ( lexer.CheckToken( "MATERIAL" ) )
			ReadMaterial( lexer );
		else if ( !SkipUnknown(lexer) )
			break;
	}
}
/*
================
DeclParser::MakeBinary
================
*/
bool DeclParser::MakeBinary( const char *filename ) {
	if ( commonFS == OG_NULL )
		return false;

	Lexer lexer;
	if ( !lexer.LoadFile( filename ) )
		return false;

	File *f = commonFS->OpenWrite( Format( "$*.bin" ) << filename );
	if ( !f )
		return false;

	try {
		f->Write( DECL_DESCRIPTOR_STR, DECL_DESCRIPTOR_LENGTH );

		Dict dict;
		bool getKeyValue = false;

		const Token *token;
		String key, value;

		String str;
		const char *p;
		while ( (token = lexer.ReadToken()) != OG_NULL ) {
			//! @todo	maybe token should be stored as String, so we don't have to recalc len/bytelen
			p = token->GetString();
			if ( p ) {
				if ( *p == '\0' ) {
					lexer.Error("Unexpected Empty Token");
					return false;
				}
				if ( !getKeyValue ) {
					str = p;
					str.WriteToFile( f );
					value = lexer.ReadString();

					if ( value.IsEmpty() ) {
						lexer.Error("Empty name!");
						return false;
					}
					value.WriteToFile( f );

					lexer.ExpectToken("{");
					getKeyValue = true;
				} else {
					if ( *p == '}' ) {
						getKeyValue = false;
						dict.WriteToFile( f );
						dict.Clear();
					}
					else {
						key = p;
						dict.Set( key.c_str(), lexer.ReadString() );
					}
				}
			}
		}
		if ( getKeyValue ) {
			lexer.Error("Unexpected End Of File");
			return false;
		}
		return true;
	}
	catch( FileReadWriteError &err ) {
		f->Close();
		User::Error( ERR_FILE_WRITEFAIL, Format("Binary Decl: $*.bin" ) << err.ToString(), filename );
		return false;
	}
	catch( LexerError &err ) {
		f->Close();
		String errStr;
		err.ToString( errStr );
		User::Error( ERR_LEXER_FAILURE, errStr.c_str(), filename );
		return false;
	}
}
/*
================
ReadMesh
================
*/
static void ReadMesh( Lexer &lexer, aseMesh *inMesh ) {
	int idx;
	Vec3 temp;
	lexer.ExpectToken("{");
	const char *p;
	const Token *token;
	while ( (token = lexer.ReadToken()) != OG_NULL ) {
		p = token->GetString();
		if ( !p || !*p )
			continue;
		if ( String::Icmp( p, "}" ) == 0 ) 
			return;
		if ( String::Icmp( p, "*" ) != 0 ) 
			lexer.Error( Format("expected *, got '$*'") << p );

		if ( lexer.CheckToken( "MESH_NUMVERTEX" ) ) {
			inMesh->numVerts = lexer.ReadInt();
			inMesh->vertices = new aseVertex[inMesh->numVerts];
		}
		else if ( lexer.CheckToken( "MESH_NUMFACES" ) ) {
			inMesh->numTris = lexer.ReadInt();
			inMesh->triangles = new aseTriangle[inMesh->numTris];
		}
		else if ( lexer.CheckToken( "MESH_VERTEX_LIST" ) ) {
			lexer.ExpectToken("{");
			for( int i=0; i<inMesh->numVerts; i++ ) {
				lexer.ExpectToken("*");
				lexer.ExpectToken("MESH_VERTEX");
				idx = lexer.ReadInt();
				inMesh->vertices[idx].origin.x = lexer.ReadFloat() * ASE_MODEL_SCALE;
				inMesh->vertices[idx].origin.y = lexer.ReadFloat() * ASE_MODEL_SCALE;
				inMesh->vertices[idx].origin.z = lexer.ReadFloat() * ASE_MODEL_SCALE;
			}
			lexer.ExpectToken("}");
		}
		else if ( lexer.CheckToken( "MESH_NORMALS" ) ) {
			lexer.ExpectToken("{");
			for( ;; ) {
				if ( lexer.CheckToken("}") )
					break;
				lexer.ExpectToken("*");
				// don't need the face normal
				if ( lexer.CheckToken("MESH_FACENORMAL") ) {
					lexer.GotoNextLine();
					continue;
				}
				lexer.ExpectToken("MESH_VERTEXNORMAL");
				idx = lexer.ReadInt();
				inMesh->vertices[idx].normal.x = lexer.ReadFloat();
				inMesh->vertices[idx].normal.y = lexer.ReadFloat();
				inMesh->vertices[idx].normal.z = lexer.ReadFloat();
			}
		}
		else if ( lexer.CheckToken( "MESH_FACE_LIST" ) ) {
			lexer.ExpectToken("{");
			for( int i=0; i<inMesh->numTris; i++ ) {
				lexer.ExpectToken("*");
				lexer.ExpectToken("MESH_FACE");
				idx = lexer.ReadInt();
				lexer.CheckToken(":"); // might or might not be there
				lexer.ExpectToken("A");
				lexer.ExpectToken(":");
				inMesh->triangles[idx].v[0] = lexer.ReadInt();
				lexer.ExpectToken("B");
				lexer.ExpectToken(":");
				inMesh->triangles[idx].v[1] = lexer.ReadInt();
				lexer.ExpectToken("C");
				lexer.ExpectToken(":");
				inMesh->triangles[idx].v[2] = lexer.ReadInt();
				lexer.GotoNextLine();
			}
			lexer.ExpectToken("}");
		}
		else if ( lexer.CheckToken( "MESH_NUMTVERTEX" ) ) {
			inMesh->numTVerts = lexer.ReadInt();
			inMesh->texCoords = new Vec2[inMesh->numTVerts];
		}
		else if ( lexer.CheckToken( "MESH_TVERTLIST" ) ) {
			lexer.ExpectToken("{");
			for( int i=0; i<inMesh->numTVerts; i++ ) {
				lexer.ExpectToken("*");
				lexer.ExpectToken("MESH_TVERT");
				idx = lexer.ReadInt();
				inMesh->texCoords[idx].x = lexer.ReadFloat();
				inMesh->texCoords[idx].y = 1.0f-lexer.ReadFloat();
				lexer.ReadFloat();// don't need 3rd component
			}
			lexer.ExpectToken("}");
		}
		else if ( lexer.CheckToken( "MESH_NUMTVFACES" ) )
			lexer.ExpectToken( Format() << inMesh->numTris );
		else if ( lexer.CheckToken( "MESH_TFACELIST" ) ) {
			lexer.ExpectToken("{");
			for( int i=0; i<inMesh->numTris; i++ ) {
				lexer.ExpectToken("*");
				lexer.ExpectToken("MESH_TFACE");
				idx = lexer.ReadInt();

				inMesh->triangles[idx].t[0] = lexer.ReadInt();
				inMesh->triangles[idx].t[1] = lexer.ReadInt();
				inMesh->triangles[idx].t[2] = lexer.ReadInt();
			}
			lexer.ExpectToken("}");
		}
		else if ( lexer.CheckToken( "MATERIAL_REF" ) )
			inMesh->materialId = lexer.ReadInt();
		else if ( !SkipUnknown(lexer) )
			break;
	}
}
/*
================
XDeclParser::Parse
================
*/
void XDeclParser::Parse( Lexer &lexer ) {
	const Token *token;
	String name, value;
	XDeclNode *currentNode = &rootNode;
	XDeclNode *newNode;
	bool getKeyValue = false;
	bool addNode;
	Stack<XDeclNode *> nodeStack;

	const char *p;
	while ( (token = lexer.ReadToken()) != NULL ) {
		p = token->GetString();
		if ( p ) {
			if ( *p == '\0' )
				lexer.Error("Unexpected Empty Token");

			if ( !getKeyValue ) {
				if ( String::Cmp( p, "}" ) == 0 ) {
					currentNode = nodeStack.Top();
					nodeStack.Pop();
				} else {
					name = p;
					addNode = false;
					if ( lexer.CheckToken("=") ) {
						currentNode->dict.Set( name.c_str(), lexer.ReadString() );
						lexer.ExpectToken(";");
					} else if ( lexer.CheckToken("(") ) {
						addNode = true;
						getKeyValue = true;
					} else if ( lexer.CheckToken("{") ) {
						addNode = true;
					} else {
						lexer.Error("Syntax Error, was expecting '(', '=' or '{'");
					}
					if ( addNode ) {
						newNode = allocator.Alloc();
						newNode->name = name;
						currentNode->numChildren++;
						if ( currentNode->firstChild == NULL )
							currentNode->firstChild = newNode;
						else
							currentNode->lastChild->next = newNode;
						currentNode->lastChild= newNode;
						nodeStack.Push( currentNode );
						currentNode = newNode;
					}
				}
			} else  {
				name = p;
				lexer.ExpectToken("=");
				currentNode->dict.Set( name.c_str(), lexer.ReadString() );
				if ( !lexer.CheckToken(",") ) {
					lexer.ExpectToken(")");
					if ( lexer.CheckToken(";") ) {
						currentNode = nodeStack.Top();
						nodeStack.Pop();
						getKeyValue = false;
					} else if ( lexer.CheckToken("{") ) {
						getKeyValue = false;
					} else {
						lexer.Error("Syntax Error, was expecting ';' or '{'");
					}
				}
			}
		}
	}
	if ( getKeyValue || nodeStack.Num() )
		throw LexerError( LexerError::END_OF_FILE );
}