/*********************************************************************//**
*	\brief Lexical analyzator.
*	Lexikalni analyzator se pouziva k syntakticke analyze textu.
*
*	\author Michal Jirous
*	\date 09.04.2009
*	\file lexan.h
**********************************************************************/

#ifndef __LEXAN_H__
#define __LEXAN_H__

#include <iostream>
#include <string>
using namespace std;

const int LEXAN_FIELD_SIZE = 255;

#define WRONG_CHAR -1
#define END_OF_FILE -2
#define LEXAN_SPACE -3
#define LEXAN_INT	-4
#define LEXAN_DOUBLE	-5
#define LEXAN_COMMENT	-6
#define LEXAN_NO_SYMBOL -7

void incBytes(int value);
int getBytes();

struct nodeL
{
	nodeL **next;
	int m_iSize;
	int m_iReturnValue;
	int num_pointer_to_this;
	
	nodeL(const unsigned int size)
	{
		m_iSize = size;
		next = new nodeL*[m_iSize];		incBytes(sizeof(nodeL*)*m_iSize);
		for(int i = 0; i < m_iSize; i++)
			next[i] = NULL;
		m_iReturnValue = 0;
		num_pointer_to_this = 0;
	}

	nodeL(nodeL *n)
	{
		m_iSize = n->m_iSize;
		next = new nodeL*[m_iSize];		incBytes(sizeof(nodeL*)*m_iSize);
		for(int i = 0; i < m_iSize; i++)
		{
			next[i] = n->next[i];
			if(n->next[i]!=NULL)
				n->next[i]->num_pointer_to_this++;
		}
		m_iReturnValue = n->m_iReturnValue;
		num_pointer_to_this = 0;
	}

	nodeL(nodeL *nDefault, int iReturnValue, bool bEndOne)
	{
		m_iSize = nDefault->m_iSize;
		next = new nodeL*[m_iSize];			incBytes(sizeof(nodeL*)*m_iSize);
		for(int i = 0; i < m_iSize; i++)
		{
			if(bEndOne)
				next[i] = NULL;
			else
			{
				next[i] = nDefault->next[i];
				if(nDefault->next[i] != NULL)
					nDefault->next[i]->num_pointer_to_this++;
			}
		}
		m_iReturnValue = iReturnValue;
		num_pointer_to_this = 0;
	}
	
	void deleteNext( nodeL *def, nodeL *wr)
	{
		if(next != NULL)
		for(int i=0;i <m_iSize;i++)
		{
			if(next[i] != NULL)
			{
				next[i]->deleteNext(def,wr);
				if(next[i]->num_pointer_to_this == 1)
					delete next[i];
				else
					next[i]->num_pointer_to_this--;
				next[i] = NULL;
			}
		}
	}
};

class CLexan
{
	unsigned int m_uiCharacterTableSize;
	unsigned char cCharacterTable[255];
	bool bAllowedCharacters[255];
	nodeL *m_nRoot, *m_nDefault, *m_nWrongChar, *m_nCommentSlash;
	nodeL *intNode;
	nodeL *doubleNode;
	string m_sData, m_sSymbolName;
	size_t m_iDataIndex;
	bool m_bSkipEmptyChars, bAllowingCharacters, bCaseSensitivity, bEmptyCharsSettings;
	int m_iLexSymbol;
public:
	CLexan();
	~CLexan();
	void setNumberDetection();
	void setCommentDetection();
	void setAllowedCharacter( char c );
	void createDefaultNode();
	void setDefaultReturnValue( int iSymbol );
	void setCycleForChar( char cCharacter );
	void setCaseSensitivity( bool sensitivity )	{	bCaseSensitivity = sensitivity;		}
	void setWrongCharacter( char cCharacter );
	void setDefaultEmptyCharactersSettings(bool value)	{ bEmptyCharsSettings = value;	};
	void setAllowedCharacters( string sCharacters);
	void init();
	void setSkippingEmptyCharacters( bool value )	{ m_bSkipEmptyChars = value;	}
	void addSubject( string sName, int iValue, bool bEndOne = false );
	void setEndCharacters( string sChars );	//jako ; + - apod.
	void setEndCharacter( char cChar );	//jako ; + - apod.
	void skipEmptyCharacters(void);
	string readTillCharacter( char cCharacter );
	int analyze();
	void loadString( string sData ) {	m_iDataIndex = 0; m_sData = sData; m_iLexSymbol = LEXAN_NO_SYMBOL;	}
	int operator()() {	return analyze();	}
	string getSymbolName(){	return m_sSymbolName;	}
	string getText(){	return m_sData;	}
	string getRemainingString();
	
	int show()
	{
		if(m_iLexSymbol == LEXAN_NO_SYMBOL)
			return m_iLexSymbol = analyze();
		else
			return m_iLexSymbol;
	}

	bool compare( int symbol )
	{
		if( symbol == show() )
		{
			m_iLexSymbol = LEXAN_NO_SYMBOL;
			return true;
		}
		else
			return false;
	}
};



#endif
