/*
 * $Id: textparser.h 4815 2018-01-08 10:19:58Z antonin.misek-skoda-auto.cz $
 *
 * Description  : One line description of file.
 * Author       : Antonin Misek <antonin.misek@skoda-auto.cz>
 *
 * Purpose      :
 *     Long description of what the file is for.
 */
#ifndef TEXTPARSER_H
#define TEXTPARSER_H

#include <wx/sstream.h>
//#include <string.h>
#include "common.h"
#include <limits>
#include "flexilog.h"
#include "wx/filename.h"

#ifdef __WINDOWS__
#pragma warning (disable: 4748)
#endif

namespace VRUT
{
	///Class for support of parsing text files
	class TextParser
	{
	private:
		///Input text stream with data
		wxInputStream *	inputStream;
		///Read buffer
		char *buff;
		///Current position
		char *aPos;
		///End of buffer
		char *bEnd;
		///Position in read buffer
		size_t buffSize;
		///Minimal buffer size
		size_t minSize;
		///File offset, it allows together with aPos compute current position in file
		size_t offset;

	public:
		///Class constructor
		///minSize must be at least max(maxKeywordLen+1, maxNumberLen+1) in buffered mode, i.e. buffSize>0
		///minSize must be 0 in "load whole scene" mode, i.e. buffSize=0
		TextParser(wxInputStream * _inputStream, size_t _buffSize, size_t _minSize) : inputStream(_inputStream), buffSize(_buffSize), minSize(_minSize), offset(0)
		{
			if (buffSize==0)
			{
				//load whole scene
				buffSize = inputStream->GetSize();
				if (buffSize==0)
				{
					//it is not possible to read size of stream
					//really wrong hack, please use real buffered mode instead of "read all at once"
					char *buf = (char*)malloc(10000000);
					std::string temp;
					while (!inputStream->Eof())
					{
						inputStream->Read(buf, 9999999);
						buf[inputStream->LastRead()]=0;
						temp += buf;
					}
					buffSize = temp.size()+1;
					buff = (char*)malloc(buffSize);
					strcpy(buff, temp.c_str());
					free(buf);
				}
				else
				{
					buff = (char*)malloc(++buffSize);
					inputStream->Read(buff, buffSize-1);
					if (inputStream->LastRead()<buffSize-1)
						buffSize=inputStream->LastRead();
					buff[buffSize-1]=0;
				}
				minSize = 0;
			}
			else
			{
				if (minSize<10)
					minSize = 10;
				if (buffSize<10*minSize)
					buffSize=10*minSize;
				buff = (char*)malloc(buffSize);
				inputStream->Read(buff, buffSize-1);
				if (inputStream->LastRead()<buffSize-1)
					buffSize=inputStream->LastRead()+1;
				buff[buffSize-1]=0;
			}
			aPos = buff;
			bEnd = buff + buffSize-1;
		}

		///Class constructor
		TextParser(const char * _input) : inputStream(NULL), minSize(0), offset(0)
		{
			buffSize = strlen(_input) + 1;
			buff = (char*)malloc(buffSize);
			memcpy(buff, _input,buffSize);
			buff[buffSize-1]=0;
			aPos = buff;
			bEnd = buff + buffSize - 1;
		}

		///Class constructor
		TextParser(const char * _input, unsigned long size) : inputStream(NULL), buffSize(size+1), minSize(0), offset(0)
		{
			buff = (char*)malloc(buffSize);
			memcpy(buff, _input, size);
			buff[buffSize-1]=0;
			aPos = buff;
			bEnd = buff + buffSize - 1;
		}

		///Class destructor
		~TextParser()
		{
			free(buff);
		}

		///Read chars to buffer
		///\param[in] force If \c true Try to read chars even if not "needed"
		///\return \c false if no chars are read
		bool ReadToBuffer(bool force=false)
		{
			if (minSize)
			{
				if (aPos==buff)
					return false;//buffer is full
				size_t restLen = (size_t)(bEnd-aPos);
				if (((restLen<minSize)||(force))&&(!inputStream->Eof()))
				{
					//strncpy(buff, aPos, restLen);//not works when inside string is 0
					memcpy(buff, aPos, restLen);
					inputStream->Read(buff+restLen, buffSize-restLen-1);
					if (inputStream->LastRead()<buffSize-restLen-1)
					{
						buffSize=inputStream->LastRead()+restLen;
						bEnd = buff + buffSize;
					}
					offset+=aPos-buff;
					aPos=buff;
					return true;
				}
			}
			return false;
		}

		///Skip any of given characters
		inline void SkipChars(const char *chars)
		{
			while (true)
			{
				while (true)
				{
					if (aPos>=bEnd)
						break;
					const char *ch=chars;
					while (*ch && (*aPos!=*ch))
						++ch;
					if (!*ch)
						break;
					++aPos;
				}
				/*while ((aPos<bEnd)&&(strchr(chars, *aPos)!=NULL))
					++aPos;*/
				if (aPos==bEnd)
				{
					if (!ReadToBuffer())
						return;
				}
				else
					return;
			}
		}

		///Skip given character
		inline void SkipChar(const char ch)
		{
			while (true)
			{
				while ((aPos<bEnd) && (*aPos==ch))
					++aPos;
				if (aPos==bEnd)
				{
					if (!ReadToBuffer())
						return;
				}
				else
					return;
			}
		}

		///Skip given number of bytes
		size_t GetPosition() const
		{
			return offset+(aPos-buff);
		}

		char* GetBuffer(size_t size)
		{
			if (size_t(bEnd-aPos)<size)
			{
				if (buffSize<size)
				{
					//realokovat
					LOG(wxT("<TextParser>GetBuffer: size bigger than buffSize"));
					return NULL;
				}
				else
				{
					ReadToBuffer(true);
					if (size_t(bEnd-aPos)<size)
						return NULL;
				}
			}
			return aPos;
		}

		///Skip given number of bytes
		void SkipBytes(size_t bytesCount)
		{
			while (bytesCount>0)
			{
				if (size_t(bEnd-aPos)<bytesCount)
				{
					bytesCount-=bEnd-aPos;
					aPos=bEnd;
				}
				else
				{
					aPos+=bytesCount;
					bytesCount=0;
				}
				/*if (!ReadToBuffer())
					return;*/
				ReadToBuffer();
			}
		}

		///Find first occurrence of any character from \c chars
		///or return \c bEnd and the caller must fill buffer and call again
		inline char* FindFirstOf(const char *chars)
		{
			char* res=aPos;
			for (; res<bEnd; ++res)
			{
				const char *pos=chars;
				while ((*pos) && (*pos!=*res))
					++pos;
				if (*pos)
					break;
			}
			return res;
		}

		/// Find char and return his count of occurrence.
		/// Search only buffer !
		inline int FindAndGetCount(const char character)
		{
			int count = 0;
			char* res=aPos;
			for (; res<bEnd; ++res)
			{
				const char *pos=&character;
				if (*pos == *res)
				{
					++count;
				}
			}
			return count ;
		}

		///Skip any of given characters and comments
		void SkipCharsAndComments(const char *chars)
		{
			while (true)
			{
				//skip useless chars and comments
				SkipChars(chars);
				ReadToBuffer();
				if (*aPos=='#')
				{
					while (true)
					{
						aPos=FindFirstOf("\n\r");
						if (aPos==bEnd)
						{
							if (!ReadToBuffer())
								return;//comment up to end of file
						}
						else
						{
							ReadToBuffer();
							break;
						}
					}
				}
				else if ((*aPos=='/') && (*(aPos+1)=='*') && (aPos<bEnd-1))
				{
					aPos+=2;
					while (true)
					{
						while (!((*aPos=='*') && (*(aPos+1)=='/')) && (aPos<bEnd-1))
							++aPos;
						if (aPos==bEnd-1)
						{
							if (!ReadToBuffer())
								return;//comment up to end of file
						}
						else
						{
							aPos+=2;
							ReadToBuffer();
							break;
						}
					}
				}
				else
					return;
			}
		}

		///Is there anything left to read?
		inline bool IsEmpty(const char *separators = NULL, bool skip = true)
		{
			if (skip)
			{
				if (separators==NULL)
				{
					separators = " \t\n\r";
				}
				SkipCharsAndComments(separators);
			}
			if (aPos>=bEnd)
				ReadToBuffer();
			return (aPos>=bEnd);
		}

		///Check keyword and read it, useful only when only one keyword can occur
		bool NextKeywordIs(const char *keyword, const char *whitechars = NULL, const char *separators = NULL)
		{
			if (whitechars==NULL)
			{
				whitechars = " \t\n\r";
			}
			if (separators==NULL)
			{
				separators = whitechars;
			}
			SkipCharsAndComments(whitechars);
			size_t keyLen = strlen(keyword);
			if (!_strnicmp(aPos, keyword, keyLen))
			{
				if (strchr(separators, *(aPos+keyLen))!=NULL)
				{
					aPos+=keyLen;
					return true;
				}
			}
			return false;
		}

		///Check keyword and read it, useful only when only one keyword can occur
		///This version not try to skip whitechars and it not check separator after keyword
		bool NextBinKeywordIs(const char *keyword, size_t keyLen=0)
		{
			ReadToBuffer();
			if (keyLen==0)
				keyLen=strlen(keyword);

			if (!_strnicmp(aPos, keyword, keyLen))
			{
				aPos+=keyLen;
				return true;
			}
			return false;
		}

		///Check for more keywords at once, it can be used for example in switches (the last keyword must be empty)
		///\param[in] keywords Array with keywords to look for
		///\param[in] whitechars Characters to be skipped
		///\param[in] separators Characters used for check of keyword end
		///\return Index of keyword in array that matches input
		int KeywordsSwitch(const char *keywords[], const char *whitechars = NULL, const char *separators = NULL)
		{
			if (whitechars==NULL)
			{
				whitechars = " \t\n\r";
			}
			if (separators==NULL)
			{
				separators = whitechars;
			}
			SkipCharsAndComments(whitechars);
			int i=0;
			while (**keywords)
			{
				size_t keyLen = strlen(*keywords);
				if (!_strnicmp(aPos, *keywords, keyLen))
				{
					if (strchr(separators, *(aPos+keyLen))!=NULL)
					{
						aPos+=keyLen;
						return i;
					}
				}
				++i;
				++keywords;
			}
			return -1;
		}

		///Check for more keywords at once, it can be used for example in switches (the last keyword must be empty)
		///\param[in] keywords Array with keywords to look for
		///\param[in] keyLens Lengths of the keywords
		///\return Index of keyword in array that matches input
		int KeywordsBinSwitch(const char *keywords[], const size_t keyLens[] = NULL)
		{
			int i=0;
			while (**keywords)
			{
				size_t keyLen;
				if (keyLens != NULL)
				{
					keyLen = *keyLens;
					++keyLens;
				}
				else
					keyLen=strlen(*keywords);
				if (!_strnicmp(aPos, *keywords, keyLen))
				{
					aPos+=keyLen;
					return i;
				}
				++i;
				++keywords;
			}
			return -1;
		}

		///Check for more keywords at once, it can be used for example in switches
		///\param[in] chars Array with characters to look for
		///\param[in] separators Characters to be skipped
		///\param[in] skip \c If true skip characters in \c separators and comments
		///\return Index of character in array that matches input
		int CharsSwitch(const char *chars, const char *separators = NULL, bool skip = true)
		{
			if (skip)
			{
				if (separators==NULL)
					separators = " \t\n\r";
				SkipCharsAndComments(separators);
			}
			int charsNum = (int)strlen(chars);
			for (int i=0; i<charsNum; ++i)
			{
				if (*aPos==*chars)
				{
					++aPos;
					return i;
				}
				++chars;
			}
			return -1;
		}

		///Test next character, but do not read it
		inline bool NextCharIs(const char chr, const char *separators = NULL, bool skip = true)
		{
			if (skip)
			{
				if (separators==NULL)
					separators = " \t\n\r";
				SkipCharsAndComments(separators);
			}
			return (*aPos==chr);
		}

		///Read next character
		inline char GetChar(const char *separators = NULL, bool skip = true)
		{
			if (skip)
			{
				if (separators==NULL)
					separators = " \t\n\r";
				SkipCharsAndComments(separators);
			}
			if (aPos==bEnd)
				if (!ReadToBuffer())
					return -1;
			return *(aPos++);
		}

		///Read quoted of not quoted string up to next separator
		std::string GetString(const char *separators = NULL, bool skip = true)
		{
			std::string res;
			if (skip)
			{
				if (separators==NULL)
					separators = " \t\n\r";
				SkipCharsAndComments(separators);
			}
			if (*aPos=='\"')
			{
				//read quoted string
				++aPos;
				while (true)
				{
					char *pos=FindFirstOf("\"");
					if (pos==bEnd)
					{
						res.append(aPos, bEnd-aPos);
						aPos=bEnd;
						if (!ReadToBuffer())
							return res;//string up to end of file
					}
					else
					{
						res.append(aPos, pos-aPos);
						aPos=pos + 1;
						ReadToBuffer();
						return res;
					}
				}
			}
			else
			{
				//read not quoted string
				while (true)
				{
					char *pos=FindFirstOf(separators);
					if (pos==bEnd)
					{
						res.append(aPos, bEnd-aPos);
						aPos=bEnd;
						if (!ReadToBuffer())
							return res;//string up to end of file
					}
					else
					{
						res.append(aPos, pos-aPos);
						aPos=pos;
						ReadToBuffer();
						return res;
					}
				}
			}
			return res;
		}

		///Read string up to first of separators going back from position aPos+maxlen
		//It is workaround for IGES parsing for broken files
		std::string GetNStringRev(int maxlen, const char *chars)
		{
			if (bEnd-aPos<maxlen)
			{
				ReadToBuffer(true);
				if (bEnd-aPos<maxlen)
				{
					LOGERROR(wxString::Format(wxT("TextParser::GetNStringRev maxlen=%lu is greater then available content (%i)"), (unsigned long)maxlen, bEnd-aPos));
					return GetBinString(bEnd-aPos);
				}
			}

			char* res=aPos+maxlen;
			for (; res>aPos; res--)
			{
				const char *pos=chars;
				while ((*pos) && (*pos!=*res))
					++pos;
				if (*pos)
					break;
			}
			std::string ret(aPos, res-aPos);
			aPos=res+1;//skip the first character from chars
			ReadToBuffer();
			return ret;
		}

		///Read string with given size
		std::string GetBinString(size_t bytesCount)
		{
			std::string res(bytesCount, 0);
			for (size_t i=0; i<bytesCount; )
			{
				if (size_t(bEnd-aPos)<bytesCount-i)
				{
					memcpy((void*)(res.c_str()+i), aPos, bEnd-aPos);
					i+=bEnd-aPos;
					aPos=bEnd;
				}
				else
				{
					memcpy((void*)(res.c_str()+i), aPos, bytesCount-i);
					aPos+=bytesCount-i;
					i=bytesCount;
				}
				ReadToBuffer();
			}
			return res;
		}

		///Read quoted of not quoted string up to next separator, wxString version
		wxString GetWxString(const char *separators = NULL, bool skip = true)
		{
			return wxString::From8BitData(GetString(separators, skip).c_str());
		}

		///Read quoted of not quoted string up to next separator, wxString version
		wxString GetWxStringUtf8(const char *separators = NULL, bool skip = true)
		{
			return wxString::FromUTF8(GetString(separators, skip).c_str());
		}

		///Read string with given size, wxString version
		wxString GetBinWxString(size_t bytesCount)
		{
			wxString res;
			for (size_t i=0; i<bytesCount; )
			{
				if (size_t(bEnd-aPos)<bytesCount-i)
				{
					res+=wxString::From8BitData(aPos, bEnd-aPos);
					i+=bEnd-aPos;
					aPos=bEnd;
				}
				else
				{
					res+=wxString::From8BitData(aPos, bytesCount-i);
					aPos+=bytesCount-i;
					i=bytesCount;
				}
				ReadToBuffer();
			}
			return res;
		}

		///Read quoted of not quoted string up to next separator
		wxString GetBinWxStringUtf8()
		{
			std::string res;
			//read not quoted string
			while (true)
			{
				size_t len=strnlen(aPos, bEnd-aPos);
				res.append(aPos, len);
				aPos+=len;
				if (aPos==bEnd)
				{
					if (!ReadToBuffer())
						break;//string up to end of file
				}
				else
					break;
			}
			++aPos;
			return wxString::FromUTF8(res.c_str());
		}

		///Read string with given size, each character has two bytes, wxString version
		wxString GetBin2BWxString(size_t bytesCount)
		{
			wxString res;
			for (size_t i=0; i<bytesCount*2; )
			{
				if (size_t(bEnd-aPos)<bytesCount*2-i)
				{
					res+=wxString((wxChar*)aPos, (bEnd-aPos)/2);
					i+=(bEnd-aPos)/2;
					aPos=bEnd;
					if ((bEnd-aPos)%2==1)
						aPos--;
				}
				else
				{
					res+=wxString((wxChar*)aPos, bytesCount-i);
					aPos+=bytesCount*2-i;
					i=bytesCount*2;
				}
				ReadToBuffer();
			}
			return res;
		}

		///Read up to end of line, it should be used only for error messages
		wxString GetWxLine()
		{
			wxString res;
			while (true)
			{
				char *pos=FindFirstOf("\n\r");
				if (pos==bEnd)
				{
					res+=wxString::From8BitData(aPos);
					aPos=bEnd;
					if (!ReadToBuffer())
						return res;//line up to end of file
				}
				else
				{
#if wxCHECK_VERSION(2, 9, 0)
					res+=wxString::From8BitData(aPos, pos-aPos);
#else
					res+=wxString::From8BitData(std::string(aPos, pos-aPos).c_str());
#endif
					aPos=pos + 1;
					ReadToBuffer();
					return res;
				}
			}
			return res;
		}

		///Read binary data with given size
		bool GetBinData(void *outbuf, size_t bytesCount)
		{
			for (size_t i=0; i<bytesCount; )
			{
				if (size_t(bEnd-aPos)<bytesCount-i)
				{
					memcpy((char*)outbuf+i, aPos, bEnd-aPos);
					i+=bEnd-aPos;
					aPos=bEnd;
				}
				else
				{
					memcpy((char*)outbuf+i, aPos, bytesCount-i);
					aPos+=bytesCount-i;
					i=bytesCount;
				}
				if (!ReadToBuffer() && (i<bytesCount))
					return false;
			}
			return true;
		}

		///Parse integer
		///\param[out] target Will be set to parsed value
		///\param[in] separators Characters to be skipped
		///\param[in] skip If \c true skip characters in \c separators and comments
		///\return \c true if successful
		bool ParseInt(int * target, const char *separators = NULL, bool skip = true)
		{
			if (skip)
			{
				if (separators==NULL)
					separators = " \t\n\r";
				SkipCharsAndComments(separators);
			}
			/* *target = atoi(aPos);
			aPos = FindFirstOf(separators);*/
			*target = 0;
			bool isOK=false;
			char *origPos = aPos;
			bool sign = false;//false = positive number
			if (*aPos=='-')
			{
				sign = true;
				++aPos;
			}
			else if (*aPos=='+')
				++aPos;
			//read integral part of number
			unsigned char n;
			while (*aPos && ((n=*aPos-'0')<10))
			{
				*target = *target*10 + n;
				++aPos;
				isOK = true;
			}
			//apply sign
			if (sign)
				*target=-*target;
			if (!isOK)
				aPos = origPos;
			return isOK;
		}

		///Parse long integer
		///\param[out] target Will be set to parsed value
		///\param[in] separators Characters to be skipped
		///\param[in] skip If \c true skip characters in \c separators and comments
		///\return \c true if successful
		bool ParseLong(long * target, const char *separators = NULL, bool skip = true)
		{
			if (skip)
			{
				if (separators==NULL)
					separators = " \t\n\r";
				SkipCharsAndComments(separators);
			}
			*target = 0;
			bool isOK=false;
			char *origPos = aPos;
			bool sign = false;//false = positive number
			if (*aPos=='-')
			{
				sign = true;
				++aPos;
			}
			else if (*aPos=='+')
				++aPos;
			//read integral part of number
			unsigned char n;
			while (*aPos && ((n=*aPos-'0')<10))
			{
				*target = *target*10 + n;
				++aPos;
				isOK = true;
			}
			//apply sign
			if (sign)
				*target=-*target;
			if (!isOK)
				aPos = origPos;
			return isOK;
		}
		
		///Parse unsigned long integer
		///\param[out] target Will be set to parsed value
		///\param[in] separators Characters to be skipped
		///\param[in] skip If \c true skip characters in \c separators and comments
		///\return \c true if successful
		bool ParseULong(unsigned long * target, const char *separators = NULL, bool skip = true)
		{
			if (skip)
			{
				if (separators == NULL)
					separators = " \t\n\r";
				SkipCharsAndComments(separators);
			}
			*target = 0;
			bool isOK = false;
			char *origPos = aPos;
			if (*aPos == '+')
				++aPos;
			//read integral part of number
			unsigned char n;
			while (*aPos && ((n = *aPos - '0') < 10))
			{
				*target = *target * 10 + n;
				++aPos;
				isOK = true;
			}
			if (!isOK)
				aPos = origPos;
			return isOK;
		}

		///Parse long integer stored in hex format (for example 0x1d)
		///\param[out] target Will be set to parsed value
		///\param[in] separators Characters to be skipped
		///\param[in] skip If \c true skip characters in \c separators and comments
		///\return \c true if successful
		bool ParseHexLong(long * target, const char *separators = NULL, bool skip = true)
		{
			if (skip)
			{
				if (separators==NULL)
					separators = " \t\n\r";
				SkipCharsAndComments(separators);
			}
			*target = 0;
			bool isOK=false;
			char *origPos = aPos;
			bool sign = false;//false = positive number
			if (*aPos=='-')
			{
				sign = true;
				++aPos;
			}
			else if (*aPos=='+')
				++aPos;
			//check the "0x"
			if (!NextCharIs('0', NULL, false))
			{
				aPos = origPos;
				return false;
			}
			++aPos;
			if (!NextCharIs('x', NULL, false))
			{
				aPos = origPos;
				return false;
			}
			++aPos;
			//read integral part of number
			while (*aPos)
			{
				unsigned char n = *aPos - '0';
				if (n>9)
				{
					if ((n=*aPos-'a')>6)
						if ((n=*aPos-'A')>6)
							break;
					*target = *target*16 + n+10;
				}
				else
					*target = *target*16 + n;
				++aPos;
				isOK = true;
			}
			//apply sign
			if (sign)
				*target=-*target;
			if (!isOK)
				aPos = origPos;
			return isOK;
		}

		///Parse unsigned long integer in binary form
		///\param[out] target Will be set to parsed value
		///\param[in] bytes Number of bytes to read
		///\return \c true if successful
		bool ParseBinULong(unsigned long *target, const size_t bytes)
		{
			ReadToBuffer();

			*target = 0;
			for (size_t i=0; i<bytes; ++i)
			{
				*target=*target+((unsigned char)*aPos<<(i*8));
				++aPos;
			}
			return true;
		}

		///Parse long integer in binary form
		///\param[out] target Will be set to parsed value
		///\param[in] bytes Number of bytes to read
		///\return \c true if successful
		bool ParseBinLong(long *target, const size_t bytes)
		{
			return ParseBinULong((unsigned long *)target, bytes);
		}

		///Parse unsigned long long integer in binary form
		///\param[out] target Will be set to parsed value
		///\param[in] bytes Number of bytes to read
		///\return \c true if successful
		bool ParseBinULongLong(unsigned long long *target, const size_t bytes)
		{
			ReadToBuffer();

			*target = 0;
			for (size_t i = 0; i<bytes; ++i)
			{
				*target = *target + ((unsigned char)*aPos << (i * 8));
				++aPos;
			}
			return true;
		}

		///Convert string to float, it is workaround for extremely slow windows implementation of atof (that uses locales)
		bool myatof(float &target)
		{
			if (!*aPos)
				return false;
			unsigned long long cpart=0;
			bool isOK=false;
			char *origPos = aPos;
			//test the sign
			bool sign = false;//false = positive number
			if (*aPos=='-')
			{
				sign = true;
				++aPos;
			} else if (*aPos=='+')
			{
				++aPos;
			}
			//read integral part of number
			unsigned char n;
			while (*aPos && ((n=*aPos-'0')<10))
			{
				cpart = cpart*10 + n;
				++aPos;
				isOK = true;
			}
			target = cpart;
			//read decimals
			if (*aPos=='.')
			{
				bool isBeffor = isOK;	// testing if beffor at is numer or no. True = yes,it's ,False = no,it isn't  
				isOK = false;
				++aPos;
				if (*aPos=='#') //NaN or INF
				{
					++aPos;
					if (!_strnicmp(aPos, "IND", 3))
						aPos+=3;
					else if (!_strnicmp(aPos, "INF", 3))
						aPos+=3;
					else if (!_strnicmp(aPos, "QO", 2))
						aPos+=2;
					else if (!_strnicmp(aPos, "QNAN", 4))
						aPos+=4;
					while (*aPos && (*aPos>='0') && (*aPos<='9'))
						++aPos;
					target=std::numeric_limits<float>::infinity();
					return true;
				}
				cpart = 0;
				unsigned long long count = 1;
				while (*aPos && ((n=*aPos-'0')<10))
				{
					cpart = cpart*10 + n;
					++aPos;
					count*=10;
					isOK = true;
				}
				// neni ze teckou zadne cislo =  chyba a konec
				if (!isOK && !isBeffor)
					return false;
				else if (isBeffor && !isOK)		// cislo je pred teckou ale neni za ni => ok
					isOK = true;
				target+=(float)cpart/count;
			}
			//read exponent
			if ((*aPos=='e')||(*aPos=='E'))
			{
				++aPos;
				//test exponent sign
				bool esign = false;//false = positive number
				if (*aPos=='-')
				{
					esign = true;
					++aPos;
				} else if (*aPos=='+')
				{
					++aPos;
				}
				int exponent = 0;
				while (*aPos && ((n=*aPos-'0')<10))
				{
					exponent = exponent*10 + n;
					++aPos;
					isOK = true;
				}
				if (esign)
					target/=pow((float)10,exponent);
				else
					target*=pow((float)10,exponent);
			}
			//apply sign
			if (sign)
				target=-target;
			if (!isOK)
				aPos = origPos;
			return isOK;
		}

		///Parse float
		///\param[out] target Will be set to parsed value
		///\param[in] separators Characters to be skipped
		///\return \c true if successful
		bool ParseFloat(float * target, const char *separators = NULL)
		{
			if (separators==NULL)
			{
				separators = " \t\n\r";
			}
			SkipCharsAndComments(separators);
			return myatof(*target);
		}

		///Parse float number in binary form
		///\param[out] target Will be set to parsed value
		///\return \c true if successful
		bool ParseBinFloat(float *target)
		{
			ReadToBuffer();

			*target = *((float*)aPos);
			aPos+=4;
			return true;
		}


		///Parse vector optionally separated by brackets
		///\param[out] target Array to be filled with values
		///\param[in] dim Number of values to be read, if 0 read till delimiter
		///\param[in] parenthesis Parse also parenthesis if \c not NULL, incoming is parenthesis[0], outcoming is parenthesis[1]
		///\param[in] separators Set of separators used on begin of vector
		///\param[in] skip Early skip - do not repeat SkipChars redundantly \c true
		///\return Number of vector values read
		size_t ParseVector(float * target, size_t dim, const char* parenthesis = NULL, const char* separators = NULL, bool skip = true)
		{
			if (parenthesis)
			{
				if (GetChar(separators, skip)!=parenthesis[0])
				{
					LOGERROR(wxT("EXPECTED parenthesis\t") + GetWxLine());
					return 0;
				}
			}
			size_t i=0;
			bool checkDim = dim > 0;
			for ( ; (i < dim) || !checkDim; ++i)
			{
				if (NextCharIs(')', " ,\t\n\r"))
					break;
				if (!myatof(*target))
					break;
				++target;
			}
			if (parenthesis)
			{
				if (GetChar()!=parenthesis[1])
				{
					LOGERROR(wxT("EXPECTED parenthesis\t")/* + GetWxLine()*/);
					//return 0;
				}
			}
#ifndef NDEBUG
			if (checkDim && (i != dim) && (FlexiLog::GetLogLevel()>=wxLOG_Debug))
			{
				LOGDEBUG(wxString::Format(wxT("TextParser: VECTOR size not expected i=%lu dim=%lu"), (unsigned long)i, (unsigned long)dim));
			}
#endif
			return i;
		}

		
		///Parse float number in binary form
		///\param[out] target Will be set to parsed value
		///\param[in] dim Number of values to be read
		///\return \c true if successful
		bool ParseBinVector(float *target, size_t dim)
		{
			while (dim-->0)
			{
				ReadToBuffer();

				*target = *((float*)aPos);
				aPos+=4;
				++target;
			}
			return true;
		}

		///Rewrite values in buffer
		///\param[in] _input ,which rewrite buffer 
		///\param[in] size of new buffer 
		///\return \c true if successful
		bool RewriteBuffer(const char * _input, unsigned long size = 0)
		{
			if (size == 0)
				size = strlen(_input);
			
			if (buffSize != size + 1)
			{
				//free(buff);
				buffSize = size + 1;
				buff = (char*)realloc(buff, buffSize);
				//buff = (char*)malloc(buffSize);
				memcpy(buff, _input, buffSize);
				buff[buffSize-1]=0;
				aPos = buff;
				bEnd = buff + buffSize - 1;
			}
			else
			{
				memcpy(buff, _input, size + 1);
				buff[buffSize-1]=0;
				aPos = buff;
				bEnd = buff + buffSize - 1;
			}
			return true;
		}

		///Swap bytes Little-Big endian
		static void SwapBytes(void *value, size_t packetBytes, size_t packetsCount)
		{
			char *valueC = (char*)value;
			for (size_t i=0; i<packetsCount; ++i)
			{
				for (size_t j=0; j<packetBytes/2; ++j)
				{
					char tmpVal=valueC[j];
					valueC[j]=valueC[packetBytes-j-1];
					valueC[packetBytes-j-1]=tmpVal;
				}
				valueC+=packetBytes;
			}
		}

		///Swap bytes Little-Big endian
		static void SwapBytes(unsigned long &value)
		{
			value = (((value & 0x000000ff) << 24) | ((value & 0x0000ff00) <<  8) |((value & 0x00ff0000) >>  8) |((value & 0xff000000) >> 24));
		}

		///Swap bytes Little-Big endian
		static void SwapBytes(unsigned long long &value)
		{
			value = (((value & 0x00000000000000ff) << 56) | ((value & 0x000000000000ff00) << 40) | ((value & 0x0000000000ff0000) << 24) |
					((value & 0x00000000ff000000) <<  8) | ((value & 0x000000ff00000000) >>  8) | ((value & 0x0000ff0000000000) >> 24) |
					((value & 0x00ff000000000000) >> 40) | ((value & 0xff00000000000000) >> 56));
		}

		static bool ComparePaths(const wxString &path1, const wxString &path2, int fieldsMask)
		{
			wxFileName fn1(path1);
			wxFileName fn2(path2);
			if (fieldsMask & 1) //name
				if (fn1.GetName() != fn2.GetName())
					return false;
			if (fieldsMask & 2) //extension
				if (fn1.GetExt() != fn2.GetExt())
					return false;
			if (fieldsMask & 4) //path
				if (fn1.GetPath() != fn2.GetPath())
					return false;
			return true;
		}
	};
}

#endif

