#ifndef __TOKEN__
#define __TOKEN__
/****************************************************************************************


		MCToken.h

		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Author:	Ray Dream 
		Date:		3/2/98

		Revision History

		when		who			what & why
		==========	==========	======================================================
		11/12/99	Thierry		added translate boolean to GetDynamicStringToken
		10/5/99		Ian			GetNextToken() now returns an MCErr.
		8/17/99		Emil		MCToken now uses TMCiostream::SetInfo/GetInfo to store
								what used to be contained in it's globals
		5/17/99		Ian			Added high-ascii translation routines moved some constants
								into the header.
		12/23/98	Arnaud		Added real32 array R/W 
		09/15/98	Mathieu		Added unsigned int reading
		7/6/98		Ian			Pulled out RDPack, and RDUnpack, they are now in MCCompression.
		5/18/98		Greg		Moved time-related calls to AnimToken.h (to reduce
								dependencies for use by MCSketch)
		3/4/98		Greg		Initial conversion

*****************************************************************************************/

#if CP_PRAGMA_ONCE
#pragma once
#endif

#include "MCString.h"
#include "MCPoint.h"
#include "MCRect.h"
#include "MCStream.h"
//class TMCstrstream;
//class TMCiostream;

#define tBINARY '$'
#define	tSPACE ' '
#define	tCOMMA ','
#define tBEGIN '{'
#define tEND '}'
#define tTAB '\t'

#define tCR 0x0D
#define tLF 0x0A
#define tCOMMENT '#'
#define tQUOTE '"'
#define tESCAPE '\\'

enum
{
	kMaxTokenSize		= 256,
	kEndTokenSignature  = '}   '
};

class 	TMCiostreamContext; 
template<class T> class TMCArray;

namespace MCToken
{
	//
	// Failure support
	//
	void FailEOFFile();


	//******************************************************************
	// InitTokenMgr() should be call every time before reading or
	// writing a new file. The parameter sets gTokenAsciiFormat (this
	// controls ASCII translation). Other globals like the indentation level
	// are reset to their default values too.

	void		InitTokenMgr(TMCiostream& stream);
	void		SetTokenAsciiFormat(TMCiostream& stream, int32 tokenAsciiFormat);
	int32		GetTokenAsciiFormat(TMCiostream& stream);

	boolean 	IsBeginToken(int8* token);
	boolean 	IsEndToken(int8* token);

	//******************************************************************
	//
	// Reading
	//
	//******************************************************************

	MCErr 		GetNextToken		(TMCiostream& stream, int8* tokenp, boolean raw = false);
	void 		SkipTokenData		(TMCiostream& stream);
	void		SkipTokenData		(TMCiostream& stream,boolean beginTokenWasRead);

	int32 		CompactAttribute	(const int8*	attrName);
	void 		FailReadFile		(void);

	void		ExtractTokenData(TMCiostream& stream,void*& data,uint32& datLen);

	void 		GetBeginToken		(TMCiostream& stream);
	void 		GetEndToken			(TMCiostream& stream);

	TMCString255 GetLocalizedStringToken		(TMCiostream& stream);
	TMCString255 GetNonLocalizedStringToken		(TMCiostream& stream);
	
	TMCDynamicString& GetLocalizedDynamicStringToken(TMCiostream& stream, TMCDynamicString& result);
	TMCDynamicString& GetNonLocalizedDynamicStringToken(TMCiostream& stream, TMCDynamicString& result, boolean translate = true);

	TMCString& 	GetLongStringToken	(TMCiostream& stream, TMCString& result);
	int8 		GetInt8Token		(TMCiostream& stream);
	int16 		GetInt16Token		(TMCiostream& stream);
	int32 		GetInt32Token		(TMCiostream& stream);
	uint8 		GetUInt8Token		(TMCiostream& stream);
	uint16 		GetUInt16Token		(TMCiostream& stream);
	uint32 		GetUInt32Token		(TMCiostream& stream);
	real32 		GetReal32Token		(TMCiostream& stream);
	real64 		GetReal64Token		(TMCiostream& stream);

	//tCOMMA is FORBIDDEN in a FourChar (used as separator in arrays)
	int32 		GetFourCharConstToken	(TMCiostream& stream);	

	uint32 		GetEnumToken	(TMCiostream& stream);
	boolean 	GetBooleanToken		(TMCiostream& stream);
	TMCPoint 	GetPointToken		(TMCiostream& stream);
	TMCRect 	GetRectToken		(TMCiostream& stream);
	void 		GetInt16ArrayToken	(TMCiostream& stream, int32 nb, int16* valArray);
	void 		GetInt32ArrayToken	(TMCiostream& stream, int32 nb, int32* valArray);
	void		GetReal32ArrayToken (TMCiostream& stream, int32 nb, real32* valArray);

	void 		GetBinaryStartToken	(TMCiostream& stream, uint32& byteCount); // byteCount = number of bytes to be read
	void 		GetBinaryEndToken	(TMCiostream& stream);

	TMCString255 GetPathRefToken	(TMCiostream& stream);
	void	 	GetStreamToken		(TMCiostream& stream, TMCstrstream& out, int32 &size);

	void 		GetBufferAsHexa		(TMCiostream& stream,int8* data,int32 count,boolean binary);
	void 		GetHexaBinaryToken	(TMCiostream& stream,int32 size,void *data);
	void 		GetBufferAsBinHex   (TMCiostream& stream,int8* data,int32 count, uint32 &lastInfo); // call BeginBufferAsBinHex first.


	// -Description:
	//		Reads an array from a (token) stream, the data must have been written by PutTMCArrayAttribute
	//
	// -Parameters:
	//		stream: the stream to read from	
	//		array: the array to fill from the stream
	//		multiLine: must be the same value than used with PutTMCArrayAttribute
	//
	// -Remarks:
	//		Any previous element in the array will be ERASED
	//
	template <class T> void GetTMCArrayToken(TMCiostream& stream, T& array, const boolean multiLine= false)
	{
		if (multiLine)
			GetBeginToken(stream);

		int32 elemCount= 0;
		stream >> elemCount;
		array.SetElemCount(elemCount);
		
		for (int32 elemNdx= 0; elemNdx < elemCount; elemNdx++)
		{
			if (!multiLine)
			{
				int8 c;
				stream.read(&c, 1);
				if (c != tCOMMA)
				{
					stream.putback(c);	//Because some files (Carrara 2 bones) were written without comas :-(
				}
			}
			stream >> array[elemNdx];			
		}

		if (multiLine)
			GetEndToken(stream);
	}

	//******************************************************************
	//
	// Writing
	//
	//******************************************************************
	TMCiostreamContext*	PutBeginToken	(TMCiostream& stream, int32 keyword, boolean getContext=false);
	void				PutBeginToken	(TMCiostream& stream);
//	void				PutBeginToken	(TMCiostream& stream, int32 keyword);
	void 	PutEndToken					(TMCiostream& stream);
	 
	//tCOMMA is FORBIDDEN in a FourChar (used as separator in arrays)
	void 	PutFourCharConstAttribute	(TMCiostream& stream, int32 keyword, int32 token);
	void	PutInt8Attribute		(TMCiostream& stream, int32 keyword, int8 value);
	void	PutInt16Attribute		(TMCiostream& stream, int32 keyword, int16 value);
	void	PutInt32Attribute		(TMCiostream& stream, int32 keyword, int32 value);
	void	PutUInt8Attribute		(TMCiostream& stream, int32 keyword, uint8 value);
	void	PutUInt16Attribute		(TMCiostream& stream, int32 keyword, uint16 value);
	void	PutUInt32Attribute		(TMCiostream& stream, int32 keyword, uint32 value);
	void 	PutReal32Attribute		(TMCiostream& stream, int32 keyword, real32 value);
	void 	PutReal64Attribute		(TMCiostream& stream, int32 keyword, real64 value);
	void 	PutEnumAttribute		(TMCiostream& stream, int32 keyword, uint32 value);
	void 	PutBooleanAttribute		(TMCiostream& stream, int32 keyword, boolean value);
	void 	PutPointAttribute		(TMCiostream& stream, int32 keyword, const TMCPoint& inPoint);
	void 	PutRectAttribute		(TMCiostream& stream, int32 keyword, const TMCRect& inRect);
	void 	PutInt32ArrayAttribute	(TMCiostream& stream, int32 keyword, int32 nb, int32* valArray);
	void 	PutInt16ArrayAttribute	(TMCiostream& stream, int32 keyword, int32 nb, int16* valArray);
	void	PutReal32ArrayAttribute (TMCiostream& stream, int32 keyword, int32 nb, const real32* valArray); //if keyword is 0, its not written

//	void 	PutStringAttribute		(TMCiostream& stream, int32 keyword, const TMCString& str);
	void 	PutLocalizedStringAttribute		(TMCiostream& stream, int32 keyword, const TMCString& str, boolean translate= true);
	void 	PutNonLocalizedStringAttribute	(TMCiostream& stream, int32 keyword, const TMCString& str, boolean translate= true);

	void 	PutLocalizedLongStringAttribute		(TMCiostream& stream, int32 keyword, const TMCString& str, boolean translate= true);
	void 	PutNonLocalizedLongStringAttribute	(TMCiostream& stream, int32 keyword, const TMCString& str, boolean translate= true);

	void 	PutInt32Token			(TMCiostream& stream, int32 value);

	// PutBinaryStartAttribute: start a block of binary data (byteCount is the number of bytes to write)
	void 	PutBinaryStartAttribute	(TMCiostream& stream, int32 keyword, uint32 byteCount);
	void 	PutBinaryEndAttribute	(TMCiostream& stream);

	// write a reference to a file relative to the file being written (the one from the stream)
	void 	PutPathRefAttribute		(TMCiostream& stream, int32 keyword, const TMCString& str);
	void 	PutStreamAttribute		(TMCiostream& stream, int32 keyword, TMCstrstream& in);

	void 	PutToken				(TMCiostream& stream, uint32 keyword, boolean skipWriteSpace= true);
	void 	IndentToken				(TMCiostream& stream);
	//void 	PutString				(TMCiostream& stream, const TMCString& str);

	void	PutNonLocalizedString	(TMCiostream& stream, const TMCString& str, boolean translate= true);
	void	PutLocalizedString		(TMCiostream& stream, const TMCString& str, boolean translate= true);


	void 	PutHexaBinaryAttribute	(TMCiostream& stream,int32 keyword,int32 size,const void *data);
	void 	PutBufferAsHexa			(TMCiostream& stream,int8* data,int32 count,boolean binary);

	void	BeginBufferAsBinHex		(uint32 &lastInfo);
	void	PutBufferAsBinHex		(TMCiostream& stream,int8* data,int32 count,uint32 &lastInfo);
	void	EndPutBufferAsBinHex	(TMCiostream& stream,uint32 &lastInfo);


	// -Description:
	//		Writes an array in a (token) stream, the written line is of the form:
	//		token valuesCount value0 value1 ... 
	//
	// -Parameters:
	//		stream: the stream to write into
	//		keyword: the four char ID to write in the stream before the array
	//		array: the array to write in the stream
	//		multiLine:	if true, puts everything between {} and separates elements by a carriage return
	//					if false, write everything on the same line with comas as separators.
	// -Remarks:
	//		The operators << and >> MUST be defined for the template parameter
	//
	template <class T> void PutTMCArrayAttribute(TMCiostream& stream, int32 keyword, const T& array, const boolean multiLine= false)
	{
		if (multiLine)
		{
			PutBeginToken(stream, keyword);
		}
		else
		{
			IndentToken(stream);
			PutToken(stream, keyword);
			stream << tSPACE;
		}
		
		const int32 elemCount= array.GetElemCount();
		stream << elemCount;
		
		if (elemCount > 0)
		{
			if (multiLine) 	stream << endl;
			else			stream << tCOMMA;
			
			int32 elemNdx= 0;
			for (; elemNdx < (elemCount-1); elemNdx++)
			{
				stream << array[elemNdx];

				if (multiLine) 	stream << endl;
				else			stream << tCOMMA;
			}
			stream << array[elemNdx];
		}
		//no else

		if (multiLine) PutEndToken(stream);
		else stream << endl;
	}
}

#endif
