// XTPSyntaxEditLexClass.cpp : implementation file
//
// This file is a part of the XTREME TOOLKIT PRO MFC class library.
// (c)1998-2012 Codejock Software, All Rights Reserved.
//
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
// CONSENT OF CODEJOCK SOFTWARE.
//
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
// IN THE XTREME SYNTAX EDIT LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
// SINGLE COMPUTER.
//
// CONTACT INFORMATION:
// support@codejock.com
// http://www.codejock.com
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"

// common includes
#include "Common/XTPColorManager.h"
#include "Common/XTPSmartPtrInternalT.h"
#include "Common/XTPVC80Helpers.h"


// syntax editor includes
#include "XTPSyntaxEditDefines.h"
#include "XTPSyntaxEditStruct.h"
#include "XTPSyntaxEditLexPtrs.h"
#include "XTPSyntaxEditLexClassSubObjT.h"
#include "XTPSyntaxEditLexCfgFileReader.h"
#include "XTPSyntaxEditLexClassSubObjDef.h"
#include "XTPSyntaxEditLexClass.h"
#include "XTPSyntaxEditLexParser.h"
#include "XTPSyntaxEditTextIterator.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

//#define TRACE_ASSERT ASSERT
#define TRACE_ASSERT(x)

//#define TRACE_MEMORY_LEX_AUTOMAT_MEM_MAN

////////////////////////////////////////////////////////////////////////////
const int c_nPrevClassDepth_default = 1;

using namespace XTPSyntaxEditLexAnalyser;

namespace XTPSyntaxEditLexAnalyser
{
	CXTPSyntaxEditLexAutomatMemMan* XTPGetLexAutomatMemMan()
	{
		static CXTPSyntaxEditLexAutomatMemMan s_LexAutomatMemMan;
		return &s_LexAutomatMemMan;
	}
	////////////////////////////////////////////////////////////////////////////

	static const LPCTSTR cszSpecs = _T("~`!@#$%^&*()_-+=\\|{}[];:'\",.<>/?");
	//---------------------------------------------------------------------------
	const TCHAR* g_arKnownLexClassAttribs[] =
	{
		XTPLEX_ATTR_TXT_COLORFG,
		XTPLEX_ATTR_TXT_COLORBK,
		XTPLEX_ATTR_TXT_COLORSELFG,
		XTPLEX_ATTR_TXT_COLORSELBK,
		XTPLEX_ATTR_TXT_BOLD,
		XTPLEX_ATTR_TXT_ITALIC,
		XTPLEX_ATTR_TXT_UNDERLINE,
		XTPLEX_ATTR_CASESENSITIVE,
		XTPLEX_ATTR_COLLAPSABLE,
		XTPLEX_ATTR_COLLAPSEDTEXT,
		XTPLEX_ATTR_PARSEONSCREEN,
		XTPLEX_ATTR_RESTARTRUNLOOP,
		XTPLEX_ATTR_ENDCLASSPARENT,
		XTPLEX_ATTR_RECURRENCEDEPTH,
		XTPLEX_ATTR_DISPLAYNAME,

		// Global attributes
		XTPLEX_ATTRG_FIRSTPARSEINSEPARATETHREAD,
		XTPLEX_ATTRG_EDITREPARCEINSEPARATETHREAD,
		XTPLEX_ATTRG_CONFIGCHANGEDREPARCEINSEPARATETHREAD,
		XTPLEX_ATTRG_EDITREPARCETIMEOUT_MS,
		XTPLEX_ATTRG_MAXBACKPARSEOFFSET,
		XTPLEX_ATTRG_ONSCREENSCHCACHELIFETIME_SEC,
		XTPLEX_ATTRG_PARSERTHREADIDLELIFETIME_SEC,
	};

	extern int FindStr(const CStringArray& rarData, LPCTSTR pcszStr, BOOL bCase = FALSE);
	extern int Find_noCase(CStringArray& rarData, LPCTSTR strData);
	//===========================================================================
	BOOL SplitStr(LPCTSTR pcszStr, TCHAR chSplitter, CStringArray& rArProps)
	{
		rArProps.RemoveAll();
		CString str0(pcszStr);
		CString strSplitter(chSplitter);

		CString str;
		do {
			str = str0.SpanExcluding(strSplitter);

			int nLen = str.GetLength();
			int nLenMax = str0.GetLength();

			if (nLen)
			{
				str0.Delete(0, min(nLen+1, nLenMax));
				rArProps.Add(str);
			}
		}
		while (!str.IsEmpty());

		return TRUE;
	}

	//---------------------------------------------------------------------------
	BOOL PropPathSplit(LPCTSTR pcszPropPath, CStringArray& rArProps)
	{
		return SplitStr(pcszPropPath, _T(':'), rArProps);
	}

	//---------------------------------------------------------------------------
	CString MakeStr(const CStringArray& rArProps, LPCTSTR strSplitter)
	{
		CString strResult;
		int nCount = (int)rArProps.GetSize();
		for (int i = 0; i < nCount; i++)
		{
			if (i)
			{
				strResult += strSplitter;
			}
			CString strI = rArProps[i];
			strResult += strI;
		}
		return strResult;
	}

	//---------------------------------------------------------------------------
	CString PropPathFirstRemove(CString& rStrPropPath)
	{
		CString strProp;

		strProp = rStrPropPath.SpanExcluding(_T(":"));

		int nLen = strProp.GetLength();
		int nLenMax = rStrPropPath.GetLength();

		if (nLen)
		{
			rStrPropPath.Delete(0, min(nLen+1, nLenMax));
		}

		return strProp;
	}

	//---------------------------------------------------------------------------
	int PropPathCount(LPCTSTR pcszPropPath)
	{
		CString strPP(pcszPropPath);

		int nCount = 1;

		int nLenMax = strPP.GetLength();

		for (int nFIndex = 0; nFIndex >= 0 && nFIndex < nLenMax;)
		{
			nFIndex = strPP.Find(_T(':'), nFIndex);
			if (nFIndex >= 0)
			{
				nFIndex++;
				nCount++;
			}
		}

		return nCount;
	}

	//---------------------------------------------------------------------------
	void AddIfNeed(CXTPSyntaxEditLexVariantPtrArray* pArDest, CXTPSyntaxEditLexVariant* pLVar)
	{
		if (!pArDest || !pLVar)
		{
			ASSERT(FALSE);
			return;
		}

		int nCount = (int)pArDest->GetSize();
		for (int i = 0; i < nCount; i++)
		{
			CXTPSyntaxEditLexVariant* pLV_i = pArDest->GetAt(i, FALSE);
			ASSERT(pLV_i);
			if (pLV_i && *pLV_i == *pLVar)
			{
				return;
			}
		}

		//-----------
		CXTPSyntaxEditLexVariantPtr ptrLV(pLVar, TRUE);
		pArDest->Add(ptrLV);
	}

	//---------------------------------------------------------------------------
	void ConcatenateLVArrays(CXTPSyntaxEditLexVariantPtrArray* pArDest,
							 CXTPSyntaxEditLexVariantPtrArray* pAr2, int nMaxCount = INT_MAX)
	{
		if (!pArDest || !pAr2)
		{
			ASSERT(FALSE);
			return;
		}
		int nCount = min(nMaxCount, (int)pAr2->GetSize());
		for (int i = 0; i < nCount; i++)
		{
			CXTPSyntaxEditLexVariant* pLVar = pAr2->GetAt(i, FALSE);
			AddIfNeed(pArDest, pLVar);
		}
	}

	//---------------------------------------------------------------------------
	int FindStr(CXTPSyntaxEditLexVariantPtrArray* pAr, LPCTSTR pcszStr, BOOL bCase = FALSE, int* pnStrIdx = NULL)
	{
		if (!pAr || !pcszStr)
		{
			ASSERT(FALSE);
			return -1;
		}

		int nCount = (int)pAr->GetSize();
		for (int i = 0; i < nCount; i++)
		{
			CXTPSyntaxEditLexVariant* pLV_i = pAr->GetAt(i, FALSE);
			ASSERT(pLV_i && pLV_i->IsStrType());

			if (pLV_i && pLV_i->IsStrType())
			{
				int nIdx2 = FindStr(pLV_i->m_arStrVals, pcszStr, bCase);
				if (nIdx2 >= 0)
				{
					if (pnStrIdx)
					{
						*pnStrIdx = nIdx2;
					}
					return i;
				}
			}
		}
		return -1;
	}

	AFX_INLINE int StrCmp_sort(const CString& rStr1, const CString& rStr2,
		BOOL bAscending, BOOL bNoCase)
	{
		int nCmpRes = 0;

		if (bNoCase)
		{
			nCmpRes = rStr1.CompareNoCase(rStr2);
		}
		else
		{
			nCmpRes = rStr1.Compare(rStr2);
		}

		if (!bAscending)
		{
			nCmpRes *= -1;
		}
		return nCmpRes;
	}

	void SortArray(CStringArray& rarData, BOOL bAscending, BOOL bNoCase)
	{
		CString strTmp;

		int nCount = (int)rarData.GetSize();
		for (int i = 0; i < nCount; i++)
		{
			for (int j = i + 1; j < nCount; j++)
			{
				int nCmpRes = StrCmp_sort(rarData[i], rarData[j], bAscending, bNoCase);
				if (nCmpRes > 0)
				{
					strTmp = rarData[i];
					rarData[i] = rarData[j];
					rarData[j] = strTmp;
				}
			}
		}
	}

	int _cdecl StrCmp_qsort_AnC(const void* p1, const void* p2)
	{
		return StrCmp_sort(*((CString*)p1), *((CString*)p2), TRUE, TRUE);
	}
	int _cdecl StrCmp_qsort_AC(const void* p1, const void* p2)
	{
		return StrCmp_sort(*((CString*)p1), *((CString*)p2), TRUE, FALSE);
	}
	int _cdecl StrCmp_qsort_DnC(const void* p1, const void* p2)
	{
		return StrCmp_sort(*((CString*)p1), *((CString*)p2), FALSE, TRUE);
	}
	int _cdecl StrCmp_qsort_DC(const void* p1, const void* p2)
	{
		return StrCmp_sort(*((CString*)p1), *((CString*)p2), FALSE, FALSE);
	}

	void QSortArray(CStringArray& rarData, BOOL bAscending, BOOL bNoCase)
	{
		int nCount = (int)rarData.GetSize();
		if (nCount <= 0)
		{
			return;
		}

		//--------------------------------------------------------------------
		typedef int (_cdecl* TPFNStrCmp)(const void* p1, const void* p2);

		TPFNStrCmp pfnStrCmp = NULL;
		if (bAscending && bNoCase)
		{
			pfnStrCmp = StrCmp_qsort_AnC;
		}
		else if (bAscending && !bNoCase)
		{
			pfnStrCmp = StrCmp_qsort_AC;
		}
		else if (!bAscending && bNoCase)
		{
			pfnStrCmp = StrCmp_qsort_DnC;
		}
		else if (!bAscending && !bNoCase)
		{
			pfnStrCmp = StrCmp_qsort_DC;
		}

		//--------------------------------------------------------------------
		void* pArray = (void*)&rarData[0];
		int nDataSize = sizeof(CString*);

		qsort(pArray, nCount, nDataSize, pfnStrCmp);
	}

	BOOL SortTagsInLexVarArray(CXTPSyntaxEditLexVariantPtrArray& rarTags,
								BOOL bAscending, BOOL bNoCase)
	{
		CXTPSyntaxEditLexVariantPtrArray arData;
		CXTPSyntaxEditLexVariant lvStrs;

		int nCount0 = (int)rarTags.GetSize();
		for (int i = 0; i < nCount0; i++)
		{
			CXTPSyntaxEditLexVariant* pLV = rarTags.GetAt(i, FALSE);
			ASSERT(pLV);
			if (pLV)
			{
				if (!(pLV->m_nObjType == xtpEditLVT_valStr || pLV->m_nObjType == xtpEditLVT_valVar))
				{
					TRACE(_T("ERROR! Tag should be string or variable. \n"));
				}

				if (pLV->m_nObjType == xtpEditLVT_valStr)
				{
					lvStrs.m_nObjType = xtpEditLVT_valStr;
					lvStrs.m_arStrVals.Append(pLV->m_arStrVals);
				}
				else
				{
					CXTPSyntaxEditLexVariant* pClone = pLV->Clone();
					if (pClone)
					{
						arData.AddPtr(pClone, FALSE);
					}
					else
					{
						return FALSE;
					}
				}
			}
		}

		//------------------------------------------------------------------------
		if (lvStrs.m_nObjType == xtpEditLVT_valStr)
		{
			QSortArray(lvStrs.m_arStrVals, bAscending, bNoCase);

			CXTPSyntaxEditLexVariantPtr ptrClone = lvStrs.Clone();
			if (ptrClone)
			{
				arData.InsertAt(0, ptrClone);
			}
			else
			{
				return FALSE;
			}
		}

		//====================================================================
		rarTags.RemoveAll();
		rarTags.Append(arData);

		return TRUE;
	}
}

////////////////////////////////////////////////////////////////////////////
//struct LA_CHAR_NODE

LA_CHAR_NODE::LA_CHAR_NODE()
{
	wChar = 0;
	wFlags = 0;
	pNextMap = NULL;

	pNextNode = NULL;
}

LA_CHAR_NODE::~LA_CHAR_NODE()
{
//  if (pNextMap

//      pNextMap->InternalRelease();
//  }
}

void LA_CHAR_NODE::Clear()
{
	wChar = 0;
	wFlags = 0;
	pNextNode = NULL;

	if (pNextMap)
	{
		pNextMap->InternalRelease();
		pNextMap = NULL;
	}
}

const LA_CHAR_NODE& LA_CHAR_NODE::operator=(const LA_CHAR_NODE& rSrc)
{
	if (rSrc.pNextMap)
	{
		rSrc.pNextMap->InternalAddRef();
	}
	if (pNextMap)
	{
		pNextMap->InternalRelease();
	}

	wChar = rSrc.wChar;
	wFlags = rSrc.wFlags;
	pNextMap = rSrc.pNextMap;

	pNextNode = rSrc.pNextNode;

	return *this;
}

////////////////////////////////////////////////////////////////////////////

CXTPSyntaxEditLexAutomatMemMan::CXTPSyntaxEditLexAutomatMemMan()
{
	m_lLockCount = 0;

	m_pFreeMaps = NULL;
	m_pFreeNodes = NULL;
	m_pFreeTables = NULL;

	m_uAllocatedMaps = 0;
	m_uUsedMaps = 0;

	m_uAllocatedNodes = 0;
	m_uUsedNodes = 0;

	m_uAllocatedTables = 0;
	m_uUsedTables = 0;
	m_uAllocatedTablesBytes = 0;
	m_uUsedTablesBytes = 0;
}

CXTPSyntaxEditLexAutomatMemMan::~CXTPSyntaxEditLexAutomatMemMan()
{
	FreeAll();
}

DWORD CXTPSyntaxEditLexAutomatMemMan::Lock()
{
	return ::InterlockedIncrement(&m_lLockCount);
}

DWORD CXTPSyntaxEditLexAutomatMemMan::Unlok()
{
	if (m_lLockCount <=0)
	{
		ASSERT(FALSE);
		return 0;
	}

	LONG lResult = ::InterlockedDecrement(&m_lLockCount);
	if (0 == lResult)
	{
		FreeAll();
		return 0;
	}
	return (DWORD)lResult;
}

void CXTPSyntaxEditLexAutomatMemMan::FreeAll()
{
	ASSERT(m_lLockCount == 0);

	POSITION pos;

	//- 1 -----------------------------------------------
	pos = m_allocatedNodes.GetHeadPosition();
	while (pos)
	{
		delete[] m_allocatedNodes.GetNext(pos);
	}
	m_allocatedNodes.RemoveAll();
	//- 2 -----------------------------------------------
	pos = m_allocatedMaps.GetHeadPosition();
	while (pos)
	{
		delete[] m_allocatedMaps.GetNext(pos);
	}
	m_allocatedMaps.RemoveAll();
	//- 3 -----------------------------------------------
	pos = m_allocatedTables.GetHeadPosition();
	while (pos)
	{
		delete m_allocatedTables.GetNext(pos);
	}
	m_allocatedTables.RemoveAll();

	m_pFreeMaps = NULL;
	m_pFreeNodes = NULL;
	m_pFreeTables = NULL;

	m_uAllocatedMaps = 0;
	m_uUsedMaps = 0;

	m_uAllocatedNodes = 0;
	m_uUsedNodes = 0;

	m_uAllocatedTables = 0;
	m_uUsedTables = 0;
	m_uAllocatedTablesBytes = 0;
	m_uUsedTablesBytes = 0;
}

CXTPSyntaxEditLexAutomatWordsMap* CXTPSyntaxEditLexAutomatMemMan::NewMap(UINT uHashTableSize)
{
	if (m_pFreeMaps)
	{
		m_uUsedMaps += 1;

		CXTPSyntaxEditLexAutomatWordsMap* pMap = m_pFreeMaps;
		m_pFreeMaps = m_pFreeMaps->pNextFreeObj;
		pMap->pNextFreeObj = NULL;

		pMap->InitMap(uHashTableSize);
		return pMap;
	}

	int nObjCount = 1024/sizeof(CXTPSyntaxEditLexAutomatWordsMap);
	m_pFreeMaps = new CXTPSyntaxEditLexAutomatWordsMap[nObjCount];

	if (!m_pFreeMaps)
	{
		return NULL;
	}
	m_allocatedMaps.AddTail(m_pFreeMaps);

	m_uAllocatedMaps += nObjCount;

	for (int i = 1; i < nObjCount; i++)
	{
		m_pFreeMaps[i-1].pNextFreeObj = &m_pFreeMaps[i];
	}

	return NewMap(uHashTableSize);
}

LA_CHAR_NODE* CXTPSyntaxEditLexAutomatMemMan::NewNode()
{
	if (m_pFreeNodes)
	{
		m_uUsedNodes += 1;

		LA_CHAR_NODE* pObj = m_pFreeNodes;
		m_pFreeNodes = m_pFreeNodes->pNextNode;
		pObj->pNextNode = NULL;

		return pObj;
	}

	int nObjCount = 1024/sizeof(LA_CHAR_NODE);
	m_pFreeNodes = new LA_CHAR_NODE[nObjCount];

	if (!m_pFreeNodes)
	{
		return NULL;
	}
	m_allocatedNodes.AddTail(m_pFreeNodes);
	m_uAllocatedNodes += nObjCount;

	for (int i = 1; i < nObjCount; i++)
	{
		m_pFreeNodes[i-1].pNextNode = &m_pFreeNodes[i];
	}

	return NewNode();
}

PLA_CHAR_NODE* CXTPSyntaxEditLexAutomatMemMan::NewHashTable(UINT uSize)
{
	ASSERT(uSize >= 1);
	if (m_pFreeTables)
	{
		// try find object with the same size
		LA_HASH_TABLE** ppHTabPrev = &m_pFreeTables;
		LA_HASH_TABLE* pHTab = m_pFreeTables;
		while (pHTab)
		{
			if (pHTab->uSize == uSize)
			{
				*ppHTabPrev = pHTab->pNextFreeObj;
				pHTab->pNextFreeObj = NULL;

				m_uUsedTables += 1;
				m_uUsedTablesBytes += uSize * sizeof(PLA_CHAR_NODE) + LA_HASH_TABLE::GetHeaderSizeB();

				return pHTab->GetData();
			}
			ppHTabPrev = &(pHTab->pNextFreeObj);
			ASSERT(pHTab != pHTab->pNextFreeObj);
			pHTab = pHTab->pNextFreeObj;
		}

		// try find bigger object and cut it
		ppHTabPrev = &m_pFreeTables;
		pHTab = m_pFreeTables;
		UINT uHeaderSize = LA_HASH_TABLE::GetHeaderSize();
		while (pHTab)
		{
			if (pHTab->uSize >= uSize)
			{
				if (pHTab->uSize - uSize > uHeaderSize)
				{
					LA_HASH_TABLE* pHTabNext = (LA_HASH_TABLE*) (pHTab->GetData()+ uSize);
					pHTabNext->uSize = pHTab->uSize - uSize - uHeaderSize;
					pHTab->uSize = uSize;

					ASSERT(pHTabNext->uSize > 0);
					ASSERT(pHTab != pHTab->pNextFreeObj);
					pHTabNext->pNextFreeObj = pHTab->pNextFreeObj;

					*ppHTabPrev = pHTabNext;
					pHTab->pNextFreeObj = NULL;

					m_uAllocatedTables += 1;
				}
				else
				{
					ASSERT(pHTab != pHTab->pNextFreeObj);
					*ppHTabPrev = pHTab->pNextFreeObj;
					pHTab->pNextFreeObj = NULL;
				}

				m_uUsedTables += 1;
				m_uUsedTablesBytes += uSize * sizeof(PLA_CHAR_NODE) + LA_HASH_TABLE::GetHeaderSizeB();

				return pHTab->GetData();
			}
			ppHTabPrev = &pHTab->pNextFreeObj;
			ASSERT(pHTab != pHTab->pNextFreeObj);
			pHTab = pHTab->pNextFreeObj;
		}
	}

	//=== Allocate new block ===
	UINT uDataSize = 1024 * uSize;
	LA_HASH_TABLE*  pNewTable = (LA_HASH_TABLE*) new PLA_CHAR_NODE[uDataSize];
	if (!pNewTable)
	{
		return NULL;
	}
	memset(pNewTable, 0, uDataSize * sizeof(PLA_CHAR_NODE));

	pNewTable->uSize = uDataSize - LA_HASH_TABLE::GetHeaderSize();
	pNewTable->pNextFreeObj = m_pFreeTables;
	m_pFreeTables = pNewTable;

	ASSERT(m_pFreeTables != m_pFreeTables->pNextFreeObj);

	m_allocatedTables.AddTail((PLA_CHAR_NODE*)pNewTable);

	m_uAllocatedTables += 1;
	m_uAllocatedTablesBytes += uDataSize * sizeof(PLA_CHAR_NODE);

	return NewHashTable(uSize);
}

void CXTPSyntaxEditLexAutomatMemMan::FreeObject(CXTPSyntaxEditLexAutomatWordsMap* pObj)
{
	pObj->Clear();

	pObj->pNextFreeObj = m_pFreeMaps;
	m_pFreeMaps = pObj;

	m_uUsedMaps --;
}

void CXTPSyntaxEditLexAutomatMemMan::FreeObject(LA_CHAR_NODE* pObj)
{
	pObj->Clear();

	pObj->pNextNode = m_pFreeNodes;
	m_pFreeNodes = pObj;

	m_uUsedNodes--;
}

void CXTPSyntaxEditLexAutomatMemMan::FreeObject(PLA_CHAR_NODE* pObj)
{
	LA_HASH_TABLE* pHTab = LA_HASH_TABLE::GetHeader(pObj);
	pHTab->Clear();

	pHTab->pNextFreeObj = m_pFreeTables;
	ASSERT(pHTab != pHTab->pNextFreeObj);
	m_pFreeTables = pHTab;


	m_uUsedTables--;
	m_uUsedTablesBytes -= pHTab->uSize * sizeof(PLA_CHAR_NODE) + LA_HASH_TABLE::GetHeaderSizeB();
}

#ifdef _DEBUG
void CXTPSyntaxEditLexAutomatMemMan::Dump(CDumpContext& dc) const
{
	UNREFERENCED_PARAMETER(dc);

#ifdef TRACE_MEMORY_LEX_AUTOMAT_MEM_MAN

	UINT uAllocatedTotal = (m_uAllocatedMaps*sizeof(CXTPSyntaxEditLexAutomatWordsMap) +
		m_uAllocatedNodes*sizeof(LA_CHAR_NODE) +
		m_uAllocatedTablesBytes) / 1024;
	UINT uUsedTotal = (m_uUsedMaps*sizeof(CXTPSyntaxEditLexAutomatWordsMap) +
		m_uUsedNodes*sizeof(LA_CHAR_NODE) +
		m_uUsedTablesBytes) / 1024;

	dc  << _T("*** Lex-Automat Mem Man ***   \n ")
		<< _T("\n")
		<< _T("AllocatedMaps=") << (int)m_uAllocatedMaps << _T(" (") << (int)(m_uAllocatedMaps * sizeof(CXTPSyntaxEditLexAutomatWordsMap) / 1024) << _T(" KB)  \n")
		<< _T("UsedMaps=") << (int)m_uUsedMaps << _T(" (") << (int)(m_uUsedMaps * sizeof(CXTPSyntaxEditLexAutomatWordsMap) / 1024) << _T(" KB) \n")
		<< _T("\n")
		<< _T("AllocatedNodes=") << (int)m_uAllocatedNodes << _T(" (") << (int)(m_uAllocatedNodes*sizeof(LA_CHAR_NODE) / 1024) << _T(" KB) \n")
		<< _T(" UsedNodes=") << (int)m_uUsedNodes << _T(" (") << (int)(m_uUsedNodes*sizeof(LA_CHAR_NODE) / 1024) << _T(" KB) \n")
		<< _T("\n")
		<< _T("AllocatedTables=") << (int)m_uAllocatedTables << _T(" (") << (int)(m_uAllocatedTablesBytes / 1024) << _T(" KB) \n")
		<< _T("UsedTables=") << (int)m_uUsedTables << _T(" (") << (int)(m_uUsedTablesBytes / 1024) << _T(" KB) \n")
		<< _T("\n ")
		<< _T("= AllocatedTotal= ") << (int)uAllocatedTotal << _T(" KB, UsedTotal= ") << (int)uUsedTotal << _T(" KB, [Free= ") << ((int)uAllocatedTotal - (int)uUsedTotal) << _T(" KB] \n\n ");
#endif
}
#endif

////////////////////////////////////////////////////////////////////////////
//class CXTPSyntaxEditLexAutomatWordsMap : public CCmdTarget

CXTPSyntaxEditLexAutomatWordsMap::CXTPSyntaxEditLexAutomatWordsMap(UINT uHashTableSize)
{
	m_pHashTable = NULL;
	ASSERT(uHashTableSize >= 1);
	m_uHashTableSize = max(1, uHashTableSize);

	pNextFreeObj = NULL;
}

CXTPSyntaxEditLexAutomatWordsMap::~CXTPSyntaxEditLexAutomatWordsMap()
{
	//RemoveAll();
}

void CXTPSyntaxEditLexAutomatWordsMap::InitMap(UINT uHashTableSize)
{
	if (m_pHashTable)
	{
		XTPGetLexAutomatMemMan()->FreeObject(m_pHashTable);
		m_pHashTable = NULL;
	}

	ASSERT(uHashTableSize >= 1);
	m_uHashTableSize = uHashTableSize;
}

UINT CXTPSyntaxEditLexAutomatWordsMap::GetHashTableSize()
{
	return m_uHashTableSize;
}

void CXTPSyntaxEditLexAutomatWordsMap::OnFinalRelease()
{
	RemoveAll() ;

	XTPGetLexAutomatMemMan()->FreeObject(this);
}


void CXTPSyntaxEditLexAutomatWordsMap::RemoveAll()
{
	if (m_pHashTable)
	{
		for (UINT i = 0; i < m_uHashTableSize; i++)
		{
			LA_CHAR_NODE* pNode = m_pHashTable[i];
			while (pNode)
			{
				LA_CHAR_NODE* pNode2 = pNode;

				pNode = pNode->pNextNode;

				XTPGetLexAutomatMemMan()->FreeObject(pNode2);
			}
		}

		XTPGetLexAutomatMemMan()->FreeObject(m_pHashTable);
		m_pHashTable = NULL;
	}
}

UINT CXTPSyntaxEditLexAutomatWordsMap::PrimeAdjustU_50(UINT uNumber)
{
	ASSERT(uNumber <= 50);

	static UINT s_arPrimes_50[] = {1, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53};
	static CUIntArray s_arMap_50;

	if (s_arMap_50.GetSize() == 0)
	{
		int nPrimeIdx = 0;
		for (UINT i = 0; i < 50; i++)
		{
			if (i > s_arPrimes_50[nPrimeIdx] && nPrimeIdx < _countof(s_arPrimes_50))
			{
				nPrimeIdx++;
				ASSERT(i <= s_arPrimes_50[nPrimeIdx]);
			}
			s_arMap_50.SetAtGrow(i, s_arPrimes_50[nPrimeIdx]);
		}
	}

	if (uNumber < 50)
	{
		UINT uPrameNum = s_arMap_50[uNumber];
		return uPrameNum;
	}
	return uNumber;
}

UINT CXTPSyntaxEditLexAutomatWordsMap::DivideHTSize(UINT uHashTableSize, UINT uMin)
{
	UINT uDiv = 2;
	if (uHashTableSize <= 10)
	{
		uDiv = 2;
	}
	else if (uHashTableSize <= 20)

	{
		uDiv = 3;
	}
	else
	{
		uDiv = 4;
	}

	UINT uNewSize = max(uHashTableSize/uDiv, uMin);
	uNewSize = PrimeAdjustU_50(uNewSize);
	return uNewSize;
}

WORD CXTPSyntaxEditLexAutomatWordsMap::_GetChar(LPCTSTR pcszStr, int& rnCharLen) const
{
	WORD wChar = 0;

	LPCTSTR p2 = _tcsinc(pcszStr);
	rnCharLen = int(p2 - pcszStr);

	if (rnCharLen == 1)
	{
		wChar = *((BYTE*)pcszStr);
	}
	else if (rnCharLen == 2)

	{
		wChar = *((WORD*)pcszStr);
	}
	else
	{
		ASSERT(FALSE);
		rnCharLen = 0;
	}

	return wChar;
}

WORD CXTPSyntaxEditLexAutomatWordsMap::_ChangeCase(WORD wChar) const
{
	WORD dwChar0[2] = {wChar, 0 };

	if (_istlower(wChar))
	{
		STRUPR_S((LPTSTR)&dwChar0, 2);
	}
	else if (_istupper(wChar))
	{
		TCSLWR_S((LPTSTR)&dwChar0, 2);
	}
	return dwChar0[0];
}

WORD CXTPSyntaxEditLexAutomatWordsMap::_MakeLower(WORD wChar) const
{
	if (_istupper(wChar))
	{
		WORD dwChar0[2] = {wChar, 0 };
		TCSLWR_S((LPTSTR)&dwChar0, 2);
		return dwChar0[0];
	}
	return wChar;
}

const LA_CHAR_NODE* CXTPSyntaxEditLexAutomatWordsMap::Lookup(WORD wChar) const
{
	if (m_pHashTable)
	{
		UINT uIndex = wChar % m_uHashTableSize;
		LA_CHAR_NODE* pNode = m_pHashTable[uIndex];
		while (pNode)
		{
			if (pNode->wChar == wChar)
			{
				return pNode;
			}
			pNode = pNode->pNextNode;
		}
	}
	return NULL;
}

const LA_CHAR_NODE* CXTPSyntaxEditLexAutomatWordsMap::SetAt(const LA_CHAR_NODE& newNode)
{
	if (!m_pHashTable)
	{
		ASSERT(m_uHashTableSize >= 1);
		m_pHashTable = XTPGetLexAutomatMemMan()->NewHashTable(m_uHashTableSize);
		if (!m_pHashTable)
		{
			return NULL;
		}
	}

	LA_CHAR_NODE* pNode2 = (LA_CHAR_NODE*)Lookup(newNode.wChar);
	if (!pNode2)
	{
		UINT uIndex = newNode.wChar % m_uHashTableSize;
		LA_CHAR_NODE* pNode0 = m_pHashTable[uIndex];

		pNode2 = XTPGetLexAutomatMemMan()->NewNode();
		*pNode2 = newNode;

		pNode2->pNextNode = pNode0;

		m_pHashTable[uIndex] = pNode2;
	}
	else
	{
		ASSERT(pNode2->wChar == newNode.wChar);
		*pNode2 = newNode;
	}

	return pNode2;
}

void CXTPSyntaxEditLexAutomatWordsMap::AddWord(CString strWord, UINT uHashTableSize )
{
	int nCharLen = 0;
	WORD wChar1 = _GetChar(strWord, nCharLen);
	strWord.Delete(0, nCharLen);

	BOOL bWordEnded = strWord.GetLength() <= 0;

	LA_CHAR_NODE* pWordData = (LA_CHAR_NODE*)Lookup(wChar1);

	if (!pWordData)
	{
		LA_CHAR_NODE wordData2;
		wordData2.wChar = wChar1;

		pWordData = (LA_CHAR_NODE*)SetAt(wordData2);
		if (!pWordData)
		{
			return;
		}
	}

	if (!bWordEnded && !pWordData->pNextMap)
	{
		pWordData->pNextMap = XTPGetLexAutomatMemMan()->NewMap(uHashTableSize); //new CXTPSyntaxEditLexAutomatWordsMap;
		if (!pWordData->pNextMap)
		{
			return;
		}
	}

	if (bWordEnded)
	{
		pWordData->wFlags |= LA_CHAR_NODE::nfSubWordEnd;
	}
	else
	{
		pWordData->pNextMap->AddWord(strWord, DivideHTSize(uHashTableSize, 1));
	}
}

BOOL CXTPSyntaxEditLexAutomatWordsMap::_FindWord(LPCTSTR pcszBuffer, CString& rstrWord, int nBufSize,
										WORD wEndFlags, BOOL bConvertToLowerCase,
										BOOL bTryToChangeCaseDyn, BOOL bChangeCase) const
{
	ASSERT((bConvertToLowerCase && bTryToChangeCaseDyn) == FALSE);

	int nCharLen = 0;
	WORD wChar1 = _GetChar(pcszBuffer, nCharLen);

	if (bConvertToLowerCase)
	{
		wChar1 = _MakeLower(wChar1);
	}
	else if (bChangeCase)
	{
		wChar1 = _ChangeCase(wChar1);

		if (wChar1 == 0)
		{
			return FALSE;
		}
	}

	LA_CHAR_NODE* pWordData = (LA_CHAR_NODE*)Lookup(wChar1);
	if (!pWordData)
	{
		return FALSE;
	}

	DWORD dwChar2 = wChar1;
	rstrWord += (LPCTSTR)&dwChar2;

	if (!pWordData->pNextMap || (pWordData->wFlags & wEndFlags) )
	{
		return TRUE;
	}

	if (nBufSize < nCharLen)
	{
		return FALSE;
	}

	pcszBuffer += nCharLen;
	nBufSize -= nCharLen;

	BOOL bRes = pWordData->pNextMap->_FindWord(pcszBuffer, rstrWord, nBufSize,
					wEndFlags, bConvertToLowerCase, bTryToChangeCaseDyn, FALSE);

	if (!bRes && bTryToChangeCaseDyn)
	{
		bRes = pWordData->pNextMap->_FindWord(pcszBuffer, rstrWord, nBufSize,
					wEndFlags, bConvertToLowerCase, bTryToChangeCaseDyn, TRUE);
	}

	if (!bRes && (pWordData->wFlags & LA_CHAR_NODE::nfSubWordEnd) )
	{
		return TRUE;
	}

	return bRes;
}

BOOL CXTPSyntaxEditLexAutomatWordsMap::FindWord(BOOL bMinWord, LPCTSTR pcszBuffer, CString& rstrWord, int nBufSize,
										 BOOL bConvertToLowerCase, BOOL bIgnoreCaseDyn) const
{
	BOOL bRes = _FindWord(pcszBuffer, rstrWord, nBufSize,
					(WORD)(bMinWord ? LA_CHAR_NODE::nfSubWordEnd : 0),
					bConvertToLowerCase, bIgnoreCaseDyn, FALSE);

	if (!bRes && bIgnoreCaseDyn)
	{
		bRes = _FindWord(pcszBuffer, rstrWord, nBufSize,
					(WORD)(bMinWord ? LA_CHAR_NODE::nfSubWordEnd : 0),
					bConvertToLowerCase, bIgnoreCaseDyn, TRUE);
	}

	return bRes;
}

////////////////////////////////////////////////////////////////////////////
CXTPSyntaxEditLexTagsAutomat::CXTPSyntaxEditLexTagsAutomat()
{
}

CXTPSyntaxEditLexTagsAutomat::~CXTPSyntaxEditLexTagsAutomat()
{
}

void CXTPSyntaxEditLexTagsAutomat::CopyFrom(const CXTPSyntaxEditLexTagsAutomat& rSrc)
{
	m_ptrWordsMap = rSrc.m_ptrWordsMap;
	m_ptrWordsMap_not = rSrc.m_ptrWordsMap_not;
}

void CXTPSyntaxEditLexTagsAutomat::RemoveAll()
{
	m_ptrWordsMap = NULL;
	m_ptrWordsMap_not = NULL;
}

UINT CXTPSyntaxEditLexTagsAutomat::_CalcHashTableSize(int nCount)
{
	if (!nCount)
	{
		return 1;
	}
	UINT uHashTableSize = 29;
	if (nCount <= 10)
	{         uHashTableSize = 3;
	} else if (nCount <= 30) {  uHashTableSize = 7;
	} else if (nCount <= 60) {  uHashTableSize = 11;
	} else if (nCount <= 100) { uHashTableSize = 17;
	} else if (nCount <= 200) { uHashTableSize = 23; }

	return uHashTableSize;
}

void CXTPSyntaxEditLexTagsAutomat::_AddWords(CXTPSyntaxEditLexAutomatWordsMapPtr& rPtrMap, CStringArray& arTags,
								  BOOL bConvertToLowerCase)
{
	int nCount = (int)arTags.GetSize();
	if (!nCount)
	{
		return;
	}

	if (!rPtrMap)
	{
		UINT uHashTableSize0 = _CalcHashTableSize(nCount);
		rPtrMap = XTPGetLexAutomatMemMan()->NewMap(uHashTableSize0);
		if (!rPtrMap)
		{
			return;
		}
	}
	UINT uHashTableSize = rPtrMap->GetHashTableSize();

	for (int i = 0; i < nCount; i++)
	{
		CString strTag = arTags[i];
		if (bConvertToLowerCase)
		{
			strTag.MakeLower();
		}
		rPtrMap->AddWord(strTag, CXTPSyntaxEditLexAutomatWordsMap::DivideHTSize(uHashTableSize, 3));
	}
}

void CXTPSyntaxEditLexTagsAutomat::AddTagsList(CXTPSyntaxEditLexVariantPtrArray* pArTags, BOOL bConvertToLowerCase)
{
	if (!pArTags)
	{
		ASSERT(FALSE);
		return;
	}

	CStringArray arTags, arTags_not;

	int nCount = (int)pArTags->GetSize();
	for (int i = 0; i < nCount; i++)
	{
		CXTPSyntaxEditLexVariant* pLV = pArTags->GetAt(i, FALSE);
		if (!pLV)
		{
			ASSERT(FALSE);
			continue;
		}
		ASSERT(pLV->m_nObjType == xtpEditLVT_valStr || pLV->m_nObjType == xtpEditLVT_valVar);

		if (pLV->m_nObjType == xtpEditLVT_valStr)
		{
			arTags.Append(pLV->m_arStrVals);
		}
		else if (pLV->m_nObjType == xtpEditLVT_valVar)
		{
			CStringArray arVarData;
			pLV->m_Variable.GetVariableData(pLV->m_Variable.m_nVarID, arVarData);

			if (pLV->m_Variable.m_nVarFlags & CXTPSyntaxEditLexVariable::xtpEditVarfNot)
			{
				arTags_not.Append(arVarData);
			}
			else
			{
				arTags.Append(arVarData);
			}
		}
	}

	_AddWords(m_ptrWordsMap, arTags, bConvertToLowerCase);
	_AddWords(m_ptrWordsMap_not, arTags_not, bConvertToLowerCase);
}

BOOL CXTPSyntaxEditLexTagsAutomat::_FindWord(BOOL bMinWord, LPCTSTR pcszBuffer, CString& rstrWord, int nBufSize,
									 BOOL bConvertToLowerCase, BOOL bIgnoreCaseDyn)

{
	rstrWord.Empty();

	if (m_ptrWordsMap)
	{
		if (m_ptrWordsMap->FindWord(bMinWord, pcszBuffer, rstrWord, nBufSize, bConvertToLowerCase, bIgnoreCaseDyn))
		{
			return TRUE;
		}
	}

	if (m_ptrWordsMap_not)
	{
		//if (!m_ptrWordsMap->FindWord(bMinWord, pcszBuffer, rstrWord, nBufSize, bConvertToLowerCase, bIgnoreCaseDyn))
		if (!m_ptrWordsMap_not->FindWord(bMinWord, pcszBuffer, rstrWord, nBufSize, bConvertToLowerCase, bIgnoreCaseDyn))
		{
			DWORD dwChar2 = 0;
			TCSNCCPY_S((LPTSTR)&dwChar2, 2, pcszBuffer, 1);
			rstrWord += (LPCTSTR)&dwChar2;

			return TRUE;
		}
	}

	return FALSE;
}

BOOL CXTPSyntaxEditLexTagsAutomat::FindMinWord(LPCTSTR pcszBuffer, CString& rstrWord, int nBufSize,
									 BOOL bConvertToLowerCase, BOOL bIgnoreCaseDyn)
{
	return _FindWord(TRUE, pcszBuffer, rstrWord, nBufSize, bConvertToLowerCase, bIgnoreCaseDyn);
}

BOOL CXTPSyntaxEditLexTagsAutomat::FindMaxWord(LPCTSTR pcszBuffer, CString& rstrWord, int nBufSize,
									 BOOL bConvertToLowerCase, BOOL bIgnoreCaseDyn)
{
	return _FindWord(FALSE, pcszBuffer, rstrWord, nBufSize, bConvertToLowerCase, bIgnoreCaseDyn);
}

BOOL CXTPSyntaxEditLexTagsAutomat::IsEmpty()
{
	return m_ptrWordsMap == NULL && m_ptrWordsMap_not == NULL;
}


////////////////////////////////////////////////////////////////////////////
CMapStringToPtr CXTPSyntaxEditLexVariable::s_mapVar2ID;
BOOL CXTPSyntaxEditLexVariable::s_bVarMapInitialized = FALSE;

//////////////////////////////////////////////////////
class CXTPSyntaxEditLexVariable_initializer : public CXTPSyntaxEditLexVariable
{
public:
	CXTPSyntaxEditLexVariable_initializer() {
		InitStandartVarsIfNeed();
	};
} s_LVarIniter;

//////////////////////////////////////////////////////

void CXTPSyntaxEditLexVariable::InitStandartVarsIfNeed()
{
	if (s_bVarMapInitialized)
	{
		return;
	}
	s_bVarMapInitialized = TRUE;

	s_mapVar2ID[_T("@alpha")]   = (void*)xtpEditVarID_alpha;
	s_mapVar2ID[_T("@digit")]   = (void*)xtpEditVarID_digit;
	s_mapVar2ID[_T("@hexdigit")] = (void*)xtpEditVarID_HexDigit;
	s_mapVar2ID[_T("@specs")]   = (void*)xtpEditVarID_specs;
	s_mapVar2ID[_T("@eol")]     = (void*)xtpEditVarID_EOL;
}

CXTPSyntaxEditLexVariable::CXTPSyntaxEditLexVariable()
{
	m_nVarFlags = 0;
	m_nVarID = 0;
}

CXTPSyntaxEditLexVariable::~CXTPSyntaxEditLexVariable()
{
}

const CXTPSyntaxEditLexVariable& CXTPSyntaxEditLexVariable::operator=(const CXTPSyntaxEditLexVariable& rSrc)
{
	m_strVar = rSrc.m_strVar;
	m_nVarFlags = rSrc.m_nVarFlags;
	m_nVarID = rSrc.m_nVarID;
	return *this;
}

BOOL CXTPSyntaxEditLexVariable::SetVariable(LPCTSTR pcszVarName)
{
	m_nVarFlags = 0;
	m_nVarID = xtpEditVarID_Unknown;
	m_strVar = pcszVarName;

	//==================================
	CStringArray arVar;
	if (!SplitStr(pcszVarName, _T(':'), arVar) || arVar.GetSize() < 1)
	{
		//TRACE
		ASSERT(FALSE);
		return FALSE;
	}
	//----------------------------------
	CString strVar = arVar[0];
	//----------------------------------
	int nVarSize = (int)arVar.GetSize();
	if (nVarSize > 1)
	{
		CString strOp = arVar[1];
		if (strOp.CompareNoCase(_T("not")) == 0)
		{
			m_nVarFlags |= xtpEditVarfNot;
		}
	}
	//==================================

	m_nVarID = GetVarID(strVar);
	ASSERT(m_nVarID != xtpEditVarID_Unknown);

	return m_nVarID != xtpEditVarID_Unknown;
}

int CXTPSyntaxEditLexVariable::GetVarID(LPCTSTR pcszVarName)
{
	void* pVarID = 0;
	CString strVar = pcszVarName;
	strVar.MakeLower();

	if (s_mapVar2ID.Lookup(strVar, pVarID))
	{
		return (int)(INT_PTR)pVarID;
	}
	return xtpEditVarID_Unknown;
}

BOOL CXTPSyntaxEditLexVariable::operator == (const CXTPSyntaxEditLexVariable& rSrc) const
{
	return m_nVarID == rSrc.m_nVarID && m_nVarFlags == rSrc.m_nVarFlags;
}

BOOL CXTPSyntaxEditLexVariable::GetVariableData(int nVarID, CStringArray& rarVarData)
{
	CUIntArray arFrom, arTo;
	int i;

	if (nVarID == CXTPSyntaxEditLexVariable::xtpEditVarID_alpha)
	{
		arFrom.Add(_T('a'));    arTo.Add(_T('z'));
		arFrom.Add(_T('A'));    arTo.Add(_T('Z'));
	}
	else if (nVarID == CXTPSyntaxEditLexVariable::xtpEditVarID_digit)
	{
		arFrom.Add(_T('0'));    arTo.Add(_T('9'));
	}
	else if (nVarID == CXTPSyntaxEditLexVariable::xtpEditVarID_HexDigit)
	{
		arFrom.Add(_T('0'));    arTo.Add(_T('9'));
		arFrom.Add(_T('a'));    arTo.Add(_T('f'));
		arFrom.Add(_T('A'));    arTo.Add(_T('F'));
	}

	for (i = 0; i < arFrom.GetSize(); i++)
	{
		for (UINT c = arFrom[i]; c <= arTo[i]; c++)
		{
			CString strChar((TCHAR)c);
			rarVarData.Add(strChar);
		}
	}

	if (arFrom.GetSize())
	{
		return TRUE;
	}

	//------------------------------------------------------------------------
	if (nVarID == CXTPSyntaxEditLexVariable::xtpEditVarID_specs)
	{
		LPCTSTR pChar = cszSpecs;
		int nCountC = (int)_tcsclen(cszSpecs);
		for (i = 0; i < nCountC; i++)
		{
			CString strChar((TCHAR)(*pChar));
			rarVarData.Add(strChar);
			pChar = _tcsinc(pChar);
		}
	}
	else if (nVarID == CXTPSyntaxEditLexVariable::xtpEditVarID_EOL)
	{
		rarVarData.Add(_T("\r"));
		rarVarData.Add(_T("\n"));
	}
	else
	{
		ASSERT(FALSE);
		return FALSE;
	}
	return TRUE;
}
//===========================================================================
CXTPSyntaxEditLexVariant::~CXTPSyntaxEditLexVariant()
{
}

CXTPSyntaxEditLexVariant::CXTPSyntaxEditLexVariant()
{
	m_nObjType = xtpEditLVT_Unknown;
	m_nValue = 0;
	m_ptrLVArrayPtr = NULL;
}

CXTPSyntaxEditLexVariant::CXTPSyntaxEditLexVariant(const CXTPSyntaxEditLexVariant& rSrc)
{
	*this = rSrc;
}

CXTPSyntaxEditLexVariant::CXTPSyntaxEditLexVariant(CXTPSyntaxEditLexClass* pClass):
				m_ptrClass(pClass, TRUE)
{
	m_nObjType = xtpEditLVT_classPtr;
	m_nValue = 0;
	m_ptrLVArrayPtr = NULL;
}

CXTPSyntaxEditLexVariant::CXTPSyntaxEditLexVariant(CXTPSyntaxEditLexVariantPtrArray* pLVArray)
{
	m_nObjType = xtpEditLVT_LVArrayPtr;
	m_nValue = 0;
	m_ptrLVArrayPtr = pLVArray;
}

CXTPSyntaxEditLexVariant::CXTPSyntaxEditLexVariant(const CXTPSyntaxEditLexVariable& rSrcVar)
{
	m_nObjType = xtpEditLVT_valVar;
	m_Variable = rSrcVar;
	m_nValue = 0;
	m_ptrLVArrayPtr = NULL;
}

CXTPSyntaxEditLexVariant::CXTPSyntaxEditLexVariant(LPCTSTR pcszStr, int eType)
{
	ASSERT( eType == xtpEditLVT_valStr || eType == xtpEditLVT_className);
	m_nObjType = eType;
	m_nValue = 0;
	m_ptrLVArrayPtr = NULL;
	m_arStrVals.SetAtGrow(0, pcszStr);
}

CXTPSyntaxEditLexVariant::CXTPSyntaxEditLexVariant(const CStringArray* pArStrVals)
{
	m_nObjType = xtpEditLVT_valStr;
	m_nValue = 0;
	m_ptrLVArrayPtr = NULL;
	if (pArStrVals)
	{
		m_arStrVals.Append(*pArStrVals);
	}
}

CXTPSyntaxEditLexVariant::CXTPSyntaxEditLexVariant(int nValue)
{
	m_nObjType = xtpEditLVT_valInt;
	m_nValue = nValue;
	m_ptrLVArrayPtr = NULL;
}


BOOL CXTPSyntaxEditLexVariant::IsStrType() const
{
	if (m_nObjType == xtpEditLVT_valStr || m_nObjType == xtpEditLVT_className)
	{
		return TRUE;
	}
	return FALSE;
}

LPCTSTR CXTPSyntaxEditLexVariant::GetStr() const
{
	if (IsStrType())
	{
		if (m_arStrVals.GetSize() > 0)
		{
			return m_arStrVals[0];
		}
		return _T("");
	}
	ASSERT(FALSE);
	return _T("");
}

const CXTPSyntaxEditLexVariant& CXTPSyntaxEditLexVariant::operator = (int nVal)
{
	m_nValue = nVal;
	m_nObjType = xtpEditLVT_valInt;

	return *this;
}

const CXTPSyntaxEditLexVariant& CXTPSyntaxEditLexVariant::operator = (const CXTPSyntaxEditLexVariable& rSrcVar)
{
	m_nValue = 0;
	m_nObjType = xtpEditLVT_valVar;
	m_Variable = rSrcVar;
	return *this;
}

const CXTPSyntaxEditLexVariant& CXTPSyntaxEditLexVariant::operator = (const CXTPSyntaxEditLexVariant& rSrc)
{
	m_nObjType = rSrc.m_nObjType;

	m_ptrClass = rSrc.m_ptrClass;
	m_ptrLVArrayPtr = rSrc.m_ptrLVArrayPtr;

	m_Variable = rSrc.m_Variable;

	m_nValue = rSrc.m_nValue;

	m_arStrVals.RemoveAll();
	m_arStrVals.Append(rSrc.m_arStrVals);

	return *this;
}

BOOL CXTPSyntaxEditLexVariant::SetVariable(LPCTSTR pcszVarName)
{
	m_nValue = 0;
	m_nObjType = xtpEditLVT_valVar;
	BOOL bRes = m_Variable.SetVariable(pcszVarName);
	return bRes;
}

CXTPSyntaxEditLexVariant* CXTPSyntaxEditLexVariant::Clone() const
{
	CXTPSyntaxEditLexVariant* pClone = new CXTPSyntaxEditLexVariant(*this);

	return pClone;
}

BOOL CXTPSyntaxEditLexVariant::operator == (const CXTPSyntaxEditLexVariant& rSrc) const
{
	if (m_nObjType != rSrc.m_nObjType)
	{
		return FALSE;
	}
	switch (m_nObjType)
	{
	case xtpEditLVT_Unknown:
		return TRUE;
	case xtpEditLVT_className:
	case xtpEditLVT_valStr:
		if (m_arStrVals.GetSize() == rSrc.m_arStrVals.GetSize())
		{
			for (int i = 0; i < m_arStrVals.GetSize(); i++)
			{
				if (m_arStrVals[i] != rSrc.m_arStrVals[i])
				{
					return FALSE;
				}
			}
			return TRUE;
		}
		return FALSE;

	case xtpEditLVT_valInt:
		return m_nValue == rSrc.m_nValue;
	case xtpEditLVT_valVar:
		return m_Variable == rSrc.m_Variable;

	case xtpEditLVT_classPtr:
		return m_ptrClass && rSrc.m_ptrClass &&
			m_ptrClass->GetClassName() == rSrc.m_ptrClass->GetClassName();
	case xtpEditLVT_LVArrayPtr:
		if (m_ptrLVArrayPtr && rSrc.m_ptrLVArrayPtr &&
			m_ptrLVArrayPtr->GetSize() == rSrc.m_ptrLVArrayPtr->GetSize())
		{
			for (int i = 0; i < m_ptrLVArrayPtr->GetSize(); i++)
			{
				if (!(*m_ptrLVArrayPtr->GetAt(i, FALSE) == *rSrc.m_ptrLVArrayPtr->GetAt(i, FALSE)) )
				{
					return FALSE;
				}
			}
			return TRUE;
		}
		return FALSE;
	default:
		ASSERT(FALSE);
	}
	return FALSE;
}

#ifdef _DEBUG
void CXTPSyntaxEditLexVariant::Dump(CDumpContext& dc) const
{
	if (IsStrType())
	{
		int nC = (int)m_arStrVals.GetSize();
		for (int k = 0; k < nC; k++)
		{
			CString strTmp = m_arStrVals[k];

			if (k)
			{
				dc << _T(", ");
			}

			if (m_nObjType == xtpEditLVT_valStr)
			{
				strTmp = XTPSyntaxEditLexConfig()->ESToStr(strTmp, FALSE);
				dc << strTmp;
			}
			else
			{
				dc << strTmp;
			}
		}
	}
	else if (m_nObjType == xtpEditLVT_valInt)
	{
		dc << m_nValue;
	}
	else if (m_nObjType == xtpEditLVT_valVar)
	{
		dc << m_Variable.m_strVar;
	}
	else
	{
		dc << _T(" ?<LV type=") << m_nObjType;
		ASSERT(FALSE);
	}
}
#endif

////////////////////////////////////////////////////////////////////////////
CXTPSyntaxEditLexOnScreenParseCnt::CXTPSyntaxEditLexOnScreenParseCnt()
{
	m_nRowStart = m_nRowEnd = 0;
}

CXTPSyntaxEditLexOnScreenParseCnt::~CXTPSyntaxEditLexOnScreenParseCnt()
{
}

////////////////////////////////////////////////////////////////////////////
CXTPSyntaxEditLexClass_file::CXTPSyntaxEditLexClass_file()
{
	m_bExtInitialized = FALSE;
}

CXTPSyntaxEditLexClass_file::~CXTPSyntaxEditLexClass_file()
{
}

CXTPSyntaxEditLexClass* CXTPSyntaxEditLexClass_file::Clone(CXTPSyntaxEditLexClassSchema* pOwnerSch)
{
	CXTPSyntaxEditLexClass* pNewClass = NULL;
	if (pOwnerSch)
	{
		pNewClass = pOwnerSch->GetNewClass(TRUE);
	}
	else
	{
		pNewClass = new CXTPSyntaxEditLexClass_file();
	}

	if (pNewClass)
	{
		pNewClass->CopyFrom(this);
	}

	return pNewClass;
}

BOOL CXTPSyntaxEditLexClass_file::InternalInitExts(BOOL bReInit)
{
	if (m_bExtInitialized && !bReInit)
	{
		return TRUE;
	}
	m_bExtInitialized = FALSE;

	m_arExt.RemoveAll();

	if (!m_Parent.arClassNames.GetSize())
	{
		TRACE(_T("ERROR! No File extentions string. \n"));
		return FALSE;
	}

	ASSERT(m_Parent.arClassNames.GetSize() == 1);

	CString strExtsSet = m_Parent.arClassNames[0];
	strExtsSet.TrimLeft();
	strExtsSet.TrimRight();
	int nESLen = strExtsSet.GetLength();

	if (nESLen < 2 || strExtsSet[0] != _T('<') ||
		strExtsSet[nESLen-1] != _T('>'))
	{
		TRACE(_T("ERROR! File extentions bad format: '%s'. Right format: <*.ex1|*.ext2|...> \n"), (LPCTSTR)strExtsSet);
		return FALSE;
	}

	strExtsSet.Delete(nESLen-1);
	strExtsSet.Delete(0);

	SplitStr(strExtsSet, _T('|'), m_arExt);

	int nCount = (int)m_arExt.GetSize();
	for (int i = 0; i < nCount; i++)
	{
		CString strExt = m_arExt[i];
		strExt.Replace(_T("*"), _T(""));
		strExt.TrimLeft();
		strExt.TrimRight();

		m_arExt[i] = strExt;
	}

	//-----------------------------------------------------------------------
	m_bExtInitialized = TRUE;
	return TRUE;
}

BOOL CXTPSyntaxEditLexClass_file::TestExt(LPCTSTR pcszExt) const
{
	ASSERT(m_bExtInitialized);

	int nCount = (int)m_arExt.GetSize();
	for (int i = 0; i < nCount; i++)
	{
		CString strExt = m_arExt[i];
		if (_tcsicoll(strExt, pcszExt) == 0)
		{
			return TRUE;
		}
	}
	return FALSE;
}

CXTPSyntaxEditLexVariantPtr CXTPSyntaxEditLexClass_file::PropV(LPCTSTR pcszPropName)
{
	CXTPSyntaxEditLexVariantPtr ptrRes = CXTPSyntaxEditLexClass::PropV(pcszPropName);
	if (ptrRes)
	{
		return ptrRes;
	}

	static LPCTSTR pcszIsExtPref = _T("IsExt=");
	static int nIsExtPrefLen = (int)_tcsclen(pcszIsExtPref);

	if (_tcsnicmp(pcszPropName, pcszIsExtPref, nIsExtPrefLen) == 0)
	{
		CString strExt = pcszPropName;
		ASSERT(strExt.GetLength() >= nIsExtPrefLen);

		strExt.Delete(0, nIsExtPrefLen);

		InternalInitExts(TRUE);

		BOOL bRes = TestExt(strExt);

		CXTPSyntaxEditLexVariant* pV = new CXTPSyntaxEditLexVariant((int)bRes);
		return pV;
	}

	return NULL;
}

int CXTPSyntaxEditLexClass_file::RunParse(CTextIter* pTxtIter,
						CXTPSyntaxEditLexTextSchema* pTxtSch,
						CXTPSyntaxEditLexTextBlockPtr& rPtrTxtBlock,
						CXTPSyntaxEditLexOnScreenParseCnt* pOnScreenRunCnt
						)
{
	if (!pTxtIter || !pTxtSch)
	{
		ASSERT(FALSE);
		//TRACE
		return xtpEditLPR_Error;
	}
	int nParseRes = 0;

	InternalInitExts();

	//===========================================================================
	BOOL bStarted = (rPtrTxtBlock != NULL);
	if (!bStarted )
	{
		CString strFileExt = pTxtIter->GetFileExt();
		bStarted = TestExt(strFileExt);

		if (!bStarted )
		{
			return 0;
		}

		rPtrTxtBlock = pTxtSch->GetNewBlock();
		if (rPtrTxtBlock)
		{
			rPtrTxtBlock->m_ptrLexClass.SetPtr(this, TRUE);

			rPtrTxtBlock->m_PosStartLC = pTxtIter->GetPosLC();
			rPtrTxtBlock->m_nStartTagLen = 0;
		}
		else
		{
			return xtpEditLPR_StartFound | xtpEditLPR_Error;
		}

		nParseRes |= xtpEditLPR_StartFound | xtpEditLPR_Iterated;
	}

	//===========================================================================
	// Run End
	if (pTxtIter->IsEOF() && rPtrTxtBlock)
	{
		CSingleLock singleLock(pTxtSch->GetDataLoker(), TRUE);

		rPtrTxtBlock->m_PosEndLC = pTxtIter->GetPosLC();
		rPtrTxtBlock->m_nEndTagXLCLen = 0;

		nParseRes |= xtpEditLPR_EndFound | xtpEditLPR_Iterated;
		return nParseRes;
	}

	if (nParseRes)
	{
		return nParseRes;
	}


	//===========================================================================
	// *** run childs ***
	int nChildsCount = (int)m_arChildrenClasses.GetSize() + (int)m_arDynChildrenClasses.GetSize();
	if (nChildsCount)
	{
		int nCHres = pTxtSch->RunChildren(pTxtIter, rPtrTxtBlock, this,
											pOnScreenRunCnt);
		nParseRes |= ~(xtpEditLPR_StartFound|xtpEditLPR_EndFound) & nCHres;

		if (nParseRes & (xtpEditLPR_Error|xtpEditLPR_RunBreaked|xtpEditLPR_RunFinished))
		{
			return nParseRes;
		}
		//---------------------------------------------------------------------------
		// Run End
		if (pTxtIter->IsEOF() && rPtrTxtBlock)
		{
			CSingleLock singleLock(pTxtSch->GetDataLoker(), TRUE);

			rPtrTxtBlock->m_PosEndLC = pTxtIter->GetPosLC();
			rPtrTxtBlock->m_nEndTagXLCLen = 0;

			nParseRes |= xtpEditLPR_EndFound;
		}
	}
	return nParseRes;
}


////////////////////////////////////////////////////////////////////////////
CXTPSyntaxEditLexClass::CXTPSyntaxEditLexClass()
{
	SetSubMembers();

	ClearAttributesCache();

	m_Parent.Clear();
	m_Children.Clear();

	m_nActiv_EndTags_Offset = 0;
}

CXTPSyntaxEditLexClass::~CXTPSyntaxEditLexClass()
{
}

void CXTPSyntaxEditLexClass::ClearAttributesCache()
{
	m_bCaseSensitive_Cached = -1; // ask
	m_nCollapsable_Cached = -1; // ask
	m_bRestartRunLoop_Cached = -1; // ask
	m_bEndClassParent_this_Cached = -1; // ask

	m_bTxtAttr_cached = FALSE; // ask
}

CXTPSyntaxEditLexVariantPtr CXTPSyntaxEditLexClass::PropV(LPCTSTR pcszPropName)
{
	if (_tcsicmp(pcszPropName, _T("name")) == 0)
	{
		return new CXTPSyntaxEditLexVariant(m_strClassName, xtpEditLVT_className);
	}

	CXTPSyntaxEditLexVariantPtrArray* ptrData = GetIfMy(pcszPropName);
	if (ptrData && ptrData->GetSize())
	{
		return new CXTPSyntaxEditLexVariant(ptrData);
	}

	return NULL;
}

void CXTPSyntaxEditLexClass::CloseClasses(CXTPSyntaxEditLexClassPtrArray* pArClasses)
{
	if (!pArClasses)
	{
		ASSERT(FALSE);
		return;
	}
	// 1. ***
	int nCount = (int)pArClasses->GetSize();
	for (int i = 0; i < nCount; i++)
	{
		CXTPSyntaxEditLexClassPtr ptrC = pArClasses->GetAt(i);
		ASSERT(ptrC);
		if (ptrC)
		{
			ptrC->Close();
		}
	}
	pArClasses->RemoveAll();
}

void CXTPSyntaxEditLexClass::Close()
{
	// 1. ***
	CXTPSyntaxEditLexClass::CloseClasses(&m_arChildrenClasses);
	CXTPSyntaxEditLexClass::CloseClasses(&m_arDynChildrenClasses);

	// 2. ***
	m_arChildrenSelfRefClasses.RemoveAll();

	// 3. ***
	TBase::RemoveAll();

	m_mapAttributes.RemoveAll();

	// 4. ***
	m_Parent.ptrDirect = NULL;
}

BOOL CXTPSyntaxEditLexClass::SetProp(const XTP_EDIT_LEXPROPINFO* pPropDesc)
{
	if (!pPropDesc || pPropDesc->arPropName.GetSize() < 1)
	{
		ASSERT(FALSE);
		return FALSE;
	}

	BOOL bProcessed = FALSE;
	BOOL bOK = SetProp_ProcessSpecials(pPropDesc, bProcessed);
	if (!bOK || bProcessed)
	{
		return bOK;
	}

	//-----------------------------------------------------------------------
	bProcessed = FALSE;
	bOK = SetProp_ProcessSpecObjects(pPropDesc, bProcessed);
	if (!bOK || bProcessed)
	{
		return bOK;
	}

	//-----------------------------------------------------------------------
	bProcessed = FALSE;
	bOK = SetProp_ProcessAttributes(pPropDesc, bProcessed);
	if (!bOK || bProcessed)
	{
		return bOK;
	}
	return FALSE;
}

BOOL CXTPSyntaxEditLexClass::ParseValues(const XTP_EDIT_LEXPROPINFO* pPropDesc,
								CXTPSyntaxEditLexVariantPtrArray* pLVArray)
{
	if (!pPropDesc || pPropDesc->arPropName.GetSize() < 1 || !pLVArray)
	{
		ASSERT(FALSE);
		return FALSE;
	}
	pLVArray->RemoveAll();

	int nNCount = (int)pPropDesc->arPropName.GetSize();
	CString strLastName = pPropDesc->arPropName[nNCount-1];
	strLastName.MakeLower();

	CString strFullName = MakeStr(pPropDesc->arPropName, _T(":"));
	strFullName.MakeLower();

	//ref, class, tag, separators
	CXTPSyntaxEditLexVariantPtr ptrLexVar;

	int nVCount = (int)pPropDesc->arPropValue.GetSize();
	for (int i = 0; i < nVCount; i++)
	{
		CString strVal = pPropDesc->arPropValue[i];
		CString strVal2;
		int nVType = xtpEditLVT_Unknown;

		if (IsQuoted(strVal, &strVal2))
		{
			if (strLastName == _T("tag") || strLastName == _T("separators"))
			{
				nVType = xtpEditLVT_valStr;
			}
			else
			{
				TRACE_ASSERT(FALSE);
				//TRACE
				TRACE(_T("ERROR! Quoted values ('%s') are not allowed for <:%s>'. (only for <:tag> and <:separators>) '%s'  \n"),
						(LPCTSTR)strVal, (LPCTSTR)strLastName, (LPCTSTR)strFullName);
			}
		}
		else if (IsVar(strVal, &strVal2))
		{
			if (strLastName == _T("tag") || strLastName == _T("separators"))
			{
				nVType = xtpEditLVT_valVar;
			}
			else
			{
				TRACE_ASSERT(FALSE);
				//TRACE
				TRACE(_T("ERROR! Variable values ('%s') are not allowed for <:%s>'. (only for <:tag> and <:separators>) '%s'  \n"),
					(LPCTSTR)strVal, (LPCTSTR)strLastName, (LPCTSTR)strFullName);
			}
		}
		else
		{
			//class
			if (strLastName == _T("class"))
			{
				nVType = xtpEditLVT_className;
				strVal2 = strVal;
				strVal2.TrimLeft();
				strVal2.TrimRight();
			}
			else
			{
				TRACE_ASSERT(FALSE);
				TRACE(_T("ERROR! Unknown ref-expression '%s' \n"), (LPCTSTR)strVal);
			}
		}
		//----------------------------------
		if (ptrLexVar &&
			(ptrLexVar->m_nObjType != nVType || !ptrLexVar->IsStrType()) )
		{
			ASSERT(ptrLexVar->m_nObjType != xtpEditLVT_Unknown);

			pLVArray->Add(ptrLexVar);
			ptrLexVar = NULL;
		}

		if (nVType != xtpEditLVT_Unknown)
		{
			if (!ptrLexVar)
			{
				ptrLexVar = new CXTPSyntaxEditLexVariant();
			}
			if (!ptrLexVar)
			{
				return FALSE;
			}
			if (nVType == xtpEditLVT_valVar)
			{
				if (!ptrLexVar->SetVariable(strVal2))
				{
					TRACE(_T("ERROR! Unknown Variable '%s' \n"), (LPCTSTR)strVal2);
				}
			}
			else
			{
				ptrLexVar->m_nObjType = nVType;
				ptrLexVar->m_arStrVals.Add(strVal2);
				ASSERT(ptrLexVar->IsStrType());
			}

		}
	}

	//-----------------------------------------
	if (ptrLexVar)
	{
		ASSERT(ptrLexVar->m_nObjType != xtpEditLVT_Unknown);
		pLVArray->Add(ptrLexVar);
		ptrLexVar = NULL;
	}

	return TRUE;
}

BOOL CXTPSyntaxEditLexClass::SetProp_ProcessSpecObjects(const XTP_EDIT_LEXPROPINFO* pPropDesc,
										BOOL& rbProcessed)
{
	rbProcessed = FALSE;

	if (!pPropDesc || pPropDesc->arPropName.GetSize() < 1)
	{
		ASSERT(FALSE);
		return FALSE;
	}

	CString strFullName = MakeStr(pPropDesc->arPropName, _T(":"));
	strFullName.MakeLower();

	if (IfMy(strFullName))
	{
		CXTPSyntaxEditLexVariantPtrArray arPtrLVar;

		if (!ParseValues(pPropDesc, &arPtrLVar))
		{
			return FALSE;
		}

		if (!AppendIfMy(strFullName, arPtrLVar))
		{
			ASSERT(FALSE);
			return FALSE;
		}
		rbProcessed = TRUE;
		return TRUE;
	}


	return TRUE;
}

BOOL CXTPSyntaxEditLexClass::IsQuoted(CString strValue, CString* pstrUnQuotedVal)
{
	CString strTmp = strValue;
	strTmp.TrimLeft();
	strTmp.TrimRight();

	int nLen = strTmp.GetLength();
	if (nLen >= 2)
	{
		if (strTmp[0] == _T('\'') && strTmp[nLen-1] == _T('\'') )
		{
			if (pstrUnQuotedVal)
			{
				strTmp.Delete(nLen-1);
				strTmp.Delete(0);

				*pstrUnQuotedVal = strTmp;
			}
			return TRUE;
		}
	}

	if (pstrUnQuotedVal)
	{
		*pstrUnQuotedVal = _T("");
	}
	return FALSE;
}

BOOL CXTPSyntaxEditLexClass::IsVar(CString strValue, CString* pstrVarVal)
{
	CString strTmp = strValue;
	strTmp.TrimLeft();
	strTmp.TrimRight();

	int nLen = strTmp.GetLength();
	if (nLen >= 2)
	{
		if (strTmp[0] == _T('@'))
		{
			if (pstrVarVal)
			{
				*pstrVarVal = strTmp;
			}
			return TRUE;
		}
	}

	if (pstrVarVal)
	{
		*pstrVarVal = _T("");
	}
	return FALSE;
}

BOOL CXTPSyntaxEditLexClass::SetProp_ProcessSpecials(const XTP_EDIT_LEXPROPINFO* pPropDesc,
										  BOOL& rbProcessed)
{
	rbProcessed = FALSE;

	if (!pPropDesc || pPropDesc->arPropName.GetSize() < 1)
	{
		ASSERT(FALSE);
		return FALSE;
	}

	int nNCount = (int)pPropDesc->arPropName.GetSize();
	CString strMainName = pPropDesc->arPropName[0];

	if (strMainName.CompareNoCase(_T("parent")) == 0)
	{
		if (nNCount == 1)
		{
			m_Parent.eOpt = xtpEditOptParent_direct;
		}
		else
		{
			ASSERT(nNCount == 2);
			CString strName2 = pPropDesc->arPropName[1];

			if (strName2.CompareNoCase(_T("file")) == 0)
			{
				m_Parent.eOpt = xtpEditOptParent_file;
			}
			else if (strName2.CompareNoCase(_T("dyn")) == 0)
			{
				m_Parent.eOpt = xtpEditOptParent_dyn;
			}
			else //if (strName2.CompareNoCase(_T("Override")) == 0)
			{
				ASSERT(FALSE);
				return FALSE;
			}
		}
		m_Parent.arClassNames.Append(pPropDesc->arPropValue);
		rbProcessed = TRUE;
	}
	else if (strMainName.CompareNoCase(_T("children")) == 0)
	{
		int nValCount = (int)pPropDesc->arPropValue.GetSize();

		if (nValCount == 0)
		{
			m_Children.eOpt = xtpEditOptChildren_No;

			TRACE_ASSERT(m_Children.arClassNames.GetSize() == 0);
			//TRACE(_T(""));

		}
		else
		{
			CString strVal0 = pPropDesc->arPropValue[0];
			strVal0.TrimLeft();
			strVal0.TrimRight();
			if (strVal0 == _T("0"))
			{
				m_Children.eOpt = xtpEditOptChildren_No;
				TRACE_ASSERT(m_Children.arClassNames.GetSize() == 0);
			}
			else
			{

				TRACE_ASSERT(m_Children.arClassNames.GetSize() == 0 &&
							m_Children.eOpt == xtpEditOptChildren_Unknown ||
							m_Children.eOpt == xtpEditOptChildren_List);

				m_Children.eOpt = xtpEditOptChildren_List;
				m_Children.arClassNames.Append(pPropDesc->arPropValue);
			}
		}
		rbProcessed = TRUE;
	}

	return TRUE;
}

BOOL CXTPSyntaxEditLexClass::SetProp_ProcessAttributes(const XTP_EDIT_LEXPROPINFO* pPropDesc,
											BOOL& rbProcessed)
{
	rbProcessed = FALSE;

	if (!pPropDesc || pPropDesc->arPropName.GetSize() < 1)
	{
		ASSERT(FALSE);
		return FALSE;
	}

	//-----------------------------------------------------------------------
	CString strFullName = MakeStr(pPropDesc->arPropName, _T(":"));
	strFullName.MakeLower();

	BOOL bKnown = FALSE;
	for (int i = 0; i < _countof(g_arKnownLexClassAttribs); i++)
	{
		if (strFullName.CompareNoCase(g_arKnownLexClassAttribs[i]) == 0)
		{
			bKnown = TRUE;
			break;
		}
	}
	if (!bKnown)
	{
		TRACE(_T("WARNING! Unknown attribute '%s'. \n"), (LPCTSTR)strFullName);
		//return TRUE;
	}

	//===========================================================================
	CXTPSyntaxEditLexVariantPtr ptrLvData = new CXTPSyntaxEditLexVariant();
	if (!ptrLvData)
	{
		return FALSE;
	}

	//---------------------------------------------------------------------------
	int nPCount = (int)pPropDesc->arPropValue.GetSize();
	if (nPCount == 1)
	{
		CString strVal = pPropDesc->arPropValue[0];
		CString strVal2;
		if (IsQuoted(strVal, &strVal2))
		{
			*ptrLvData = CXTPSyntaxEditLexVariant(strVal2);
		}
		else if (strFullName == _T("end:class:parent"))
		{
			*ptrLvData = CXTPSyntaxEditLexVariant(&pPropDesc->arPropValue);
		}
		else
		{
			static const int c_nClrPrefLen = (int)_tcsclen(XTPLEX_ATTR_COLORPREFIX);

			TCHAR* pCh = NULL;
			int nValue = _tcstol(strVal, &pCh, 0);

			if (_tcsnicmp(strFullName, XTPLEX_ATTR_COLORPREFIX, c_nClrPrefLen) == 0)
			{
				nValue = XTP_EDIT_RGB_INT2CLR(nValue);
			}
			*ptrLvData = nValue;

		}
		m_mapAttributes[strFullName] = ptrLvData;
	}
	else if (nPCount > 1)
	{
		*ptrLvData = CXTPSyntaxEditLexVariant(&pPropDesc->arPropValue);
		m_mapAttributes[strFullName] = ptrLvData;
	}
	else
	{
		//TRACE
		TRACE(_T("ERROR! There is not values present for attribute '%s'  \n"), (LPCTSTR)strFullName);
	}
	rbProcessed = TRUE;

	//-----------------------------------------------------------------------
	return TRUE;
}

void CXTPSyntaxEditLexClass::SortTags()
{
	BOOL bAsc = FALSE;
	BOOL bNoCase = !IsCaseSensitive();

	SortTagsInLexVarArray(m_previous.m_tag, bAsc, bNoCase);
	SortTagsInLexVarArray(m_previous.m_tag_separators, bAsc, bNoCase);

	SortTagsInLexVarArray(m_start.m_tag, bAsc, bNoCase);

	SortTagsInLexVarArray(m_end.m_tag, bAsc, bNoCase);
	SortTagsInLexVarArray(m_end.m_separators, bAsc, bNoCase);

	SortTagsInLexVarArray(m_token.m_tag, bAsc, bNoCase);
	SortTagsInLexVarArray(m_token.m_start_separators, bAsc, bNoCase);
	SortTagsInLexVarArray(m_token.m_end_separators, bAsc, bNoCase);

	SortTagsInLexVarArray(m_skip.m_tag, bAsc, bNoCase);

	bAsc = TRUE;
	SortTagsInLexVarArray(m_ActiveTags, bAsc, bNoCase);
	//m_ActiveTags.BuildAutomat(TRUE);
}

BOOL CXTPSyntaxEditLexClass::IsCaseSensitive()
{
	if (m_bCaseSensitive_Cached < 0)
	{
		m_bCaseSensitive_Cached = FALSE;

		CXTPSyntaxEditLexVariantPtr ptrCase = GetAttribute(XTPLEX_ATTR_CASESENSITIVE, TRUE);
		if (ptrCase && ptrCase->m_nObjType == xtpEditLVT_valInt)
		{
			m_bCaseSensitive_Cached = ptrCase->m_nValue > 0;
		}
	}
	return m_bCaseSensitive_Cached;
}

int CXTPSyntaxEditLexClass::IsCollapsable()
{
	if (m_nCollapsable_Cached < 0)
	{
		m_nCollapsable_Cached = FALSE;

		CXTPSyntaxEditLexVariantPtr ptrLV = GetAttribute(XTPLEX_ATTR_COLLAPSABLE, FALSE);
		if (ptrLV && ptrLV->m_nObjType == xtpEditLVT_valInt)
		{
			m_nCollapsable_Cached = ptrLV->m_nValue;// > 0;
		}
	}
	return m_nCollapsable_Cached;
}

BOOL CXTPSyntaxEditLexClass::IsEndClassParent_this()
{
	if (m_bEndClassParent_this_Cached < 0)
	{
		m_bEndClassParent_this_Cached = FALSE;

		CXTPSyntaxEditLexVariantPtr ptrAttrVal = GetAttribute(XTPLEX_ATTR_ENDCLASSPARENT, FALSE);
		ASSERT(!ptrAttrVal || ptrAttrVal && ptrAttrVal->m_nObjType == xtpEditLVT_valStr);

		if (ptrAttrVal && ptrAttrVal->m_nObjType == xtpEditLVT_valStr)
		{
			m_bEndClassParent_this_Cached = Find_noCase(ptrAttrVal->m_arStrVals, _T("this")) >= 0;
		}
	}
	return m_bEndClassParent_this_Cached;
}

BOOL CXTPSyntaxEditLexClass::StrCmpEQ(LPCTSTR pcszStr1, LPCTSTR pcszStr2, int nLen,
							BOOL bCaseSensitive,
							BOOL bParseDirection_Back)
{
	int nRes = 0;

	if (bParseDirection_Back)
	{
		for (int i = 0; i < nLen; i++)
		{
			nRes = StrCmp(pcszStr1, pcszStr2, 1, bCaseSensitive);
			if (nRes)
			{
				break;
			}
			if (*pcszStr1 == 0 || *pcszStr2 == 0)
			{
				break;
			}
			if (i+1 < nLen)
			{
				pcszStr1 = _tcsdec(pcszStr1-2, pcszStr1);
				pcszStr2 = _tcsdec(pcszStr2-2, pcszStr2);
			}
		}
	}
	else
	{
		nRes = StrCmp(pcszStr1, pcszStr2, nLen, bCaseSensitive);
	}

	return nRes == 0;
}

BOOL CXTPSyntaxEditLexClass::StrVarCmpEQ(LPCTSTR pcszStr,
							   const CXTPSyntaxEditLexVariable& lexVar,
							   CString& rstrValue, BOOL bParseDirection_Back)
{
	UNREFERENCED_PARAMETER(bParseDirection_Back);

	BOOL bRes = FALSE;
	TCHAR chChar = *pcszStr;

	if (lexVar.m_nVarID == CXTPSyntaxEditLexVariable::xtpEditVarID_alpha)  //a-z, A-Z
	{
		bRes = chChar >= _T('a') && chChar <= _T('z') ||
				chChar >= _T('A') && chChar <= _T('Z');
	}
	else if (lexVar.m_nVarID == CXTPSyntaxEditLexVariable::xtpEditVarID_digit) // 0-9
	{
		bRes = chChar >= _T('0') && chChar <= _T('9');
	}
	else if (lexVar.m_nVarID == CXTPSyntaxEditLexVariable::xtpEditVarID_HexDigit) // 0-9, a-f, A-F
	{
		bRes = chChar >= _T('0') && chChar <= _T('9') ||
				chChar >= _T('a') && chChar <= _T('f') ||
				chChar >= _T('A') && chChar <= _T('F');
	}
	else if (lexVar.m_nVarID == CXTPSyntaxEditLexVariable::xtpEditVarID_specs)
	{
		TCHAR* pF = _tcschr((TCHAR*)cszSpecs, chChar);
		bRes = (pF != NULL);
	}
	// @EOL
	else if (lexVar.m_nVarID == CXTPSyntaxEditLexVariable::xtpEditVarID_EOL)
	{
		bRes = chChar == _T('\r') || chChar == _T('\n');
	}
	else
	{
		ASSERT(FALSE);
		TRACE(_T("ERROR! Unknown lexVariable '%s' \n"), (LPCTSTR)lexVar.m_strVar);
		return FALSE;
	}

	if (lexVar.m_nVarFlags & CXTPSyntaxEditLexVariable::xtpEditVarfNot)
	{
		bRes = !bRes;
	}

	if (bRes)
	{
		rstrValue = chChar;
	}

	return bRes;
}

CXTPSyntaxEditLexClassPtrArray* CXTPSyntaxEditLexClass::GetChildren()
{
	return &m_arChildrenClasses;
}

CXTPSyntaxEditLexClassPtrArray* CXTPSyntaxEditLexClass::GetChildrenDyn()
{
	return &m_arDynChildrenClasses;
}

CXTPSyntaxEditLexClassPtrArray* CXTPSyntaxEditLexClass::GetChildrenSelfRef()
{
	return &m_arChildrenSelfRefClasses;
}

BOOL CXTPSyntaxEditLexClass::AddChild(CXTPSyntaxEditLexClass* pChild, BOOL bDyn)
{
	if (!pChild)
	{
		ASSERT(FALSE);
		return FALSE;
	}

	CXTPSyntaxEditLexClassPtr ptrC(pChild, TRUE);
	if (pChild == this)
	{
		int nCount = (int)m_arChildrenSelfRefClasses.GetSize();
		for (int i = 0; i < nCount; i++)
		{
			CXTPSyntaxEditLexClassPtr ptrCSelf = m_arChildrenSelfRefClasses[i];
			if (ptrC == ptrCSelf )
			{
				return FALSE;
			}
		}
		m_arChildrenSelfRefClasses.Add(ptrC);
		return TRUE;
	}

	pChild->m_Parent.ptrDirect.SetPtr(this, TRUE);
	if (bDyn)
	{
		m_arDynChildrenClasses.Add(ptrC);
	}
	else
	{
		m_arChildrenClasses.Add(ptrC);
	}
	return TRUE;
}

void CXTPSyntaxEditLexClass::GetParentOpt(int& rnOpt, CStringArray& rArData) const
{
	rnOpt = m_Parent.eOpt;
	rArData.RemoveAll();
	rArData.Append(m_Parent.arClassNames);
}

void CXTPSyntaxEditLexClass::GetChildrenOpt(int& rnOpt, CStringArray& rArData) const
{
	rnOpt = m_Children.eOpt;
	rArData.RemoveAll();
	rArData.Append(m_Children.arClassNames);
}

CXTPSyntaxEditLexClass* CXTPSyntaxEditLexClass::FindParent(LPCTSTR pcszClassName)
{
	if (!m_Parent.ptrDirect)
	{
		return NULL;
	}

	CString strParent = m_Parent.ptrDirect->GetClassName();
	if (strParent.CompareNoCase(pcszClassName) == 0)
	{
		return m_Parent.ptrDirect;
	}
	return m_Parent.ptrDirect->FindParent(pcszClassName);
}

int CXTPSyntaxEditLexClass::RunParse(CTextIter* pTxtIter,
						CXTPSyntaxEditLexTextSchema* pTxtSch,
						CXTPSyntaxEditLexTextBlockPtr& rPtrTxtBlock,
						CXTPSyntaxEditLexOnScreenParseCnt* pOnScreenRunCnt
						)
{
	if (!pTxtIter || !pTxtSch)
	{
		ASSERT(FALSE);
		//TRACE
		return xtpEditLPR_Error | xtpEditLPR_Iterated;
	}

	if (!m_token.IsEmpty() && (!m_start.IsEmpty() || !m_end.IsEmpty()) )
	{
		TRACE(_T("WARNING: Start/End and Token options cannot be used together! '%s' \n"), (LPCTSTR)m_strClassName);
	}

	int nParseRes = 0;

	BOOL bStarted = (rPtrTxtBlock != NULL);
	BOOL bPrevCondition = TRUE;

	//===========================================================================
	if (!bStarted)
	{
		if (!m_previous.IsEmpty())
		{
			bPrevCondition = Run_Previous(pTxtIter, pTxtSch, rPtrTxtBlock,
											pOnScreenRunCnt);
		}

		//===========================================================================
		if (!m_start.IsEmpty())
		{
			if (bPrevCondition && !bStarted )
			{
				int nResStart = Run_Start(pTxtIter, pTxtSch, rPtrTxtBlock,
											pOnScreenRunCnt);
				bStarted = nResStart & xtpEditLPR_StartFound;
				nParseRes |= nResStart;

				return nParseRes;
			}
		}
		else if (bPrevCondition)
		{
			if (!m_token.IsEmpty())
			{
				int nResToken = Run_Token(pTxtIter, pTxtSch, rPtrTxtBlock);
				BOOL bEnded = nResToken & xtpEditLPR_EndFound;

				nParseRes |= nResToken;
				if (nParseRes & xtpEditLPR_Error)
				{
					return nParseRes;
				}
				//---------------------------------------------------------------------------
				if (bEnded)
				{
					return nParseRes;
				}
			}
			else
			{
				bStarted = TRUE;
				nParseRes |= xtpEditLPR_StartFound|xtpEditLPR_Iterated;

				rPtrTxtBlock = pTxtSch->GetNewBlock();
				if (rPtrTxtBlock)
				{
					rPtrTxtBlock->m_ptrLexClass.SetPtr(this, TRUE);
					rPtrTxtBlock->m_PosStartLC = pTxtIter->GetPosLC();
					rPtrTxtBlock->m_nStartTagLen = 0;
				}
				else
				{
					nParseRes |= xtpEditLPR_Error;
				}

				return nParseRes;
			}
		}
	} // if (!bStarted)

	//---------------------------------------------------------------------------
	if (!bStarted)
	{
		return 0;
	}

	//===========================================================================
	if (!m_skip.IsEmpty())
	{
		int nResSkip = Run_Skip(pTxtIter, pTxtSch, rPtrTxtBlock);

		nParseRes |= nResSkip;
		if (nParseRes & xtpEditLPR_Error)
		{
			return nParseRes;
		}
	}

	//===========================================================================
	if (!m_end.IsEmpty())
	{
		int nResEnd = Run_End(pTxtIter, pTxtSch, rPtrTxtBlock, pOnScreenRunCnt);
		BOOL bEnded = nResEnd & xtpEditLPR_EndFound;

		nParseRes |= nResEnd;
		if (nParseRes & xtpEditLPR_Error)
		{
			return nParseRes;
		}

		//---------------------------------------------------------------------------
		if (bEnded)
		{
			return nParseRes;
		}
	}

	//===========================================================================
	// *** run childs ***
	int nChildsCount = (int)m_arChildrenClasses.GetSize() +
						(int)m_arDynChildrenClasses.GetSize() +
						(int)m_arChildrenSelfRefClasses.GetSize();
	if (nChildsCount)
	{
		int nCHres = pTxtSch->RunChildren(pTxtIter, rPtrTxtBlock, this, pOnScreenRunCnt);
		nParseRes |= ~(xtpEditLPR_StartFound|xtpEditLPR_EndFound) & nCHres;

		if (nParseRes & (xtpEditLPR_Error|xtpEditLPR_RunBreaked|xtpEditLPR_RunFinished))
		{
			return nParseRes;
		}

		//---------------------------------------------------------------------------
		int nResEnd = Run_End(pTxtIter, pTxtSch, rPtrTxtBlock, pOnScreenRunCnt);
		nParseRes |= nResEnd;
	}
	return nParseRes;
}

BOOL CXTPSyntaxEditLexClass::Run_Previous(CTextIter* pTxtIter,
								 CXTPSyntaxEditLexTextSchema* pTxtSch,
								 CXTPSyntaxEditLexTextBlockPtr& rPtrTxtBlock,
								 CXTPSyntaxEditLexOnScreenParseCnt* pOnScreenRunCnt)
{
	UNREFERENCED_PARAMETER(rPtrTxtBlock);

	BOOL bRes_Class = TRUE, bRes_Tag = TRUE;

	//=======================================================================
	if (!m_previous.m_class.IsEmpty())
	{
		bRes_Class = Run_PrevClass(NULL, pTxtSch, &m_previous.m_class,
									c_nPrevClassDepth_default, NULL,
									 NULL, pOnScreenRunCnt);
		if (!bRes_Class)
		{
			return FALSE;
		}
	}

	//=======================================================================
	if (!m_previous.m_tag.IsEmpty())
	{
		bRes_Tag = FALSE;

		if (!m_previous.m_tag_separators.IsEmpty())
		{
			int nMaxBackOffset = pTxtIter->GetMaxBackOffset();
			BOOL bContinue = TRUE;
			int nOffset;
			for (nOffset = 0; bContinue && labs(nOffset) < nMaxBackOffset; nOffset--)
			{
				CString strSep;
				bContinue = Run_Tags(pTxtIter, pTxtSch, &m_previous.m_tag_separators,
									 strSep, TRUE);

				if (bContinue)
				{
					pTxtIter->SetTxtOffset(nOffset-1);
				}
			}
			ASSERT(labs(nOffset) < nMaxBackOffset);
		}

		CString strTag;

		bRes_Tag = Run_Tags(pTxtIter, pTxtSch, &m_previous.m_tag, strTag, TRUE);

		pTxtIter->SetTxtOffset(0);
	}

	return bRes_Class && bRes_Tag;
}


BOOL CXTPSyntaxEditLexClass::Run_PrevClass(CXTPSyntaxEditLexTextBlock** ppPrevTB,
								 CXTPSyntaxEditLexTextSchema* pTxtSch,
								 CXTPSyntaxEditLexVariantPtrArray* pLVPrevClasses,
								 int nDepth, XTP_EDIT_LINECOL* pMinPrevPos,
								 CXTPSyntaxEditLexTextBlock* pPrevForParentBlockOnly,
								 CXTPSyntaxEditLexOnScreenParseCnt* pOnScreenRunCnt)
{
	if (ppPrevTB)
	{
		*ppPrevTB = NULL;
	}

	CXTPSyntaxEditLexTextBlock* pTBprev = NULL;
	if (pOnScreenRunCnt)
	{
		pTBprev = pOnScreenRunCnt->m_ptrTBLast;
	}
	else
	{
		pTBprev = pTxtSch->GetPrevBlock(FALSE);
	}

	if (!pLVPrevClasses || !pTBprev || !pTBprev->m_ptrLexClass)
	{
		return FALSE;
	}
	if (pPrevForParentBlockOnly && pPrevForParentBlockOnly != pTBprev->m_ptrParent)
	{
		return FALSE;
	}

	//=======================================================================
	for (int nD = 0;
		pTBprev && pTBprev->m_ptrLexClass &&
		(!pMinPrevPos || pTBprev->m_PosStartLC >= *pMinPrevPos) &&
		nD < nDepth;
		nD++, pTBprev = pTBprev->m_ptrPrev)
	{
		const CString& strPrevClassName = pTBprev->m_ptrLexClass->m_strClassName;

		int nPCCont1 = (int)pLVPrevClasses->GetSize();
		for (int i = 0; i < nPCCont1; i++)
		{
			CXTPSyntaxEditLexVariant* pVarPrevC = pLVPrevClasses->GetAt(i, FALSE);
			if (!pVarPrevC || !pVarPrevC->IsStrType())
			{
				ASSERT(FALSE);
				continue;
			}
			ASSERT(pVarPrevC->m_nObjType == xtpEditLVT_className);

			int nCCount2 = (int)pVarPrevC->m_arStrVals.GetSize();
			for (int k = 0; k < nCCount2; k++)
			{
				const CString& strCName = pVarPrevC->m_arStrVals[k];
				if (strPrevClassName.CompareNoCase(strCName) == 0)
				{

					if (ppPrevTB)
					{
						*ppPrevTB = pTBprev;
					}
					return TRUE;
				}
			}
		}
	}
	return FALSE;
}

int CXTPSyntaxEditLexClass::Run_Start(CTextIter* pTxtIter,
						CXTPSyntaxEditLexTextSchema* pTxtSch,
						CXTPSyntaxEditLexTextBlockPtr& rPtrTxtBlock,
						CXTPSyntaxEditLexOnScreenParseCnt* pOnScreenRunCnt
						)
{
	if (!pTxtIter || !pTxtSch)
	{
		ASSERT(FALSE);
		//TRACE
		return xtpEditLPR_Error;
	}

	BOOL bStarted = (rPtrTxtBlock != NULL);
	ASSERT(!bStarted);

	if (bStarted || m_start.IsEmpty())
	{
		return 0;
	}

	//===========================================================================
	BOOL bRes_Class = TRUE;
	CXTPSyntaxEditLexTextBlock* pPrevClass = NULL;

	if (!m_start.m_class.IsEmpty())
	{
		bRes_Class = Run_PrevClass(&pPrevClass, pTxtSch, &m_start.m_class,
							c_nPrevClassDepth_default, NULL,  NULL, pOnScreenRunCnt);
		if (!bRes_Class)
		{
			return 0;
		}
	}

	//===========================================================================
	BOOL bRes_Tag = TRUE;
	CString strTagVal;
	BOOL bTag_Empty = m_start.m_tag.IsEmpty();

	if (!bTag_Empty)
	{
		bRes_Tag = Run_Tags(pTxtIter, pTxtSch, &m_start.m_tag, strTagVal);
		if (!bRes_Tag)
		{
			return 0;
		}
	}

	bStarted = bRes_Class && bRes_Tag;
	int nRes = 0;
	if (bStarted)
	{
		nRes |= xtpEditLPR_StartFound;
		if (!m_start.m_class.IsEmpty() && pPrevClass && pPrevClass->m_ptrLexClass &&
			m_Parent.ptrDirect )
		{
			CString strC0 = m_Parent.ptrDirect->GetClassName();
			CString strC1 = pPrevClass->m_ptrLexClass->GetClassName();

			if (strC0.CompareNoCase(strC1) != 0)
			{
				nRes |= xtpEditLPR_TBpop1;
			}
		}

		rPtrTxtBlock = pTxtSch->GetNewBlock();
		if (rPtrTxtBlock)
		{
			rPtrTxtBlock->m_ptrLexClass = this;
			rPtrTxtBlock->m_ptrLexClass->InternalAddRef();

			if (bRes_Tag && !bTag_Empty)
			{
				int nLenC = (int)_tcsclen(strTagVal);
				ASSERT(nLenC);

				rPtrTxtBlock->m_PosStartLC = pTxtIter->GetPosLC();
				rPtrTxtBlock->m_nStartTagLen = nLenC;

				pTxtIter->SeekNext(nLenC);
				nRes |= xtpEditLPR_Iterated;
			}
			else
			{
				CSingleLock singleLock(pTxtSch->GetDataLoker(), TRUE);

				ASSERT(pPrevClass);
				if (pPrevClass)
				{
					rPtrTxtBlock->m_PosStartLC = pPrevClass->m_PosStartLC;
					rPtrTxtBlock->m_nStartTagLen = pPrevClass->m_nStartTagLen;
				}
			}
		}

		if (!rPtrTxtBlock)
		{
			return xtpEditLPR_Error | nRes;
		}
	}

	//---------------------------------------------------------------------------
	return nRes;
}

int CXTPSyntaxEditLexClass::Run_Skip(CTextIter* pTxtIter,
							CXTPSyntaxEditLexTextSchema* pTxtSch,
							CXTPSyntaxEditLexTextBlockPtr& rPtrTxtBlock
							)
{
	if (!pTxtIter || !pTxtSch)
	{
		ASSERT(FALSE);
		//TRACE
		return xtpEditLPR_Error;
	}

	BOOL bStarted = (rPtrTxtBlock != NULL);
	ASSERT(bStarted);

	if (!bStarted || m_skip.IsEmpty())
	{
		return 0;
	}

	//===========================================================================
	CString strTagVal;

	if (!m_skip.m_tag.IsEmpty())
	{
		BOOL bIterated = FALSE;

		while (!pTxtIter->IsEOF() && Run_Tags(pTxtIter, pTxtSch, &m_skip.m_tag, strTagVal))
		{
			int nLen = strTagVal.GetLength();
			pTxtIter->SeekNext(nLen);

			bIterated = TRUE;
		}
		if (bIterated)
		{
			return xtpEditLPR_Iterated;
		}
	}

	return 0;
}

int CXTPSyntaxEditLexClass::Run_End(CTextIter* pTxtIter,
						CXTPSyntaxEditLexTextSchema* pTxtSch,
						CXTPSyntaxEditLexTextBlockPtr& rPtrTxtBlock,
						CXTPSyntaxEditLexOnScreenParseCnt* pOnScreenRunCnt)
{
	if (!pTxtIter || !pTxtSch)
	{
		ASSERT(FALSE);
		//TRACE
		return xtpEditLPR_Error;
	}

	BOOL bEnded = FALSE;

	if (m_end.IsEmpty())
	{
		return 0;
	}

	ASSERT(rPtrTxtBlock);

	//===========================================================================
	BOOL bRes_Class = TRUE;
	CXTPSyntaxEditLexTextBlock* pPrevClass = NULL;

	if (!m_end.m_class.IsEmpty())
	{
		CXTPSyntaxEditLexTextBlock* pTBEndParent = IsEndClassParent_this() ? rPtrTxtBlock : NULL;

		bRes_Class = Run_PrevClass(&pPrevClass, pTxtSch, &m_end.m_class,
						c_nPrevClassDepth_default, &rPtrTxtBlock->m_PosStartLC,
						pTBEndParent, pOnScreenRunCnt);
		if (!bRes_Class)
		{
			return 0;
		}
	}

	//===========================================================================
	BOOL bRes_Tag = TRUE;
	CString strTagVal;
	int nTagLenC = 0;

	if (!m_end.m_tag.IsEmpty())
	{
		bRes_Tag = Run_Tags(pTxtIter, pTxtSch, &m_end.m_tag, strTagVal);
		if (!bRes_Tag)
		{
			return 0;
		}
		nTagLenC = (int)_tcsclen(strTagVal);
	}

	//===========================================================================
	BOOL bRes_Separators = TRUE;
	CString strSepVal;

	if (!m_end.m_separators.IsEmpty())
	{
		pTxtIter->SetTxtOffset(nTagLenC);

		bRes_Separators = Run_Tags(pTxtIter, pTxtSch, &m_end.m_separators, strSepVal);

		pTxtIter->SetTxtOffset(0);

		if (!bRes_Separators)
		{
			return 0;
		}
	}

	//-----------------------------------------------------------------------
	bEnded = bRes_Class && bRes_Tag && bRes_Separators;
	int nRes = 0;

	if (bEnded)
	{
		nRes |= xtpEditLPR_EndFound;
		nRes |= xtpEditLPR_Iterated;

		if (bRes_Tag && !m_end.m_tag.IsEmpty() ||
			bRes_Separators && !m_end.m_separators.IsEmpty())
		{
			CSingleLock singleLock(pTxtSch->GetDataLoker(), TRUE);

			XTP_EDIT_LINECOL runLC = pTxtIter->GetPosLC();

			if (bRes_Tag && !m_end.m_tag.IsEmpty())
			{
				pTxtIter->SeekNext(nTagLenC);
			}

			ASSERT(this == (CXTPSyntaxEditLexClass*)rPtrTxtBlock->m_ptrLexClass);

			rPtrTxtBlock->m_PosEndLC = pTxtIter->GetPosLC();

			const XTP_EDIT_LINECOL beginLC = {1, 0};
			if (rPtrTxtBlock->m_PosEndLC > beginLC)
			{
				pTxtIter->LCPosDec(rPtrTxtBlock->m_PosEndLC);
			}
			else
			{
				TRACE(_T("WARNING (parser): unexpected end position (1, 0) \n"));
			}

			if (bRes_Separators && !m_end.m_separators.IsEmpty())
			{
				int nSepLenC = (int)_tcsclen(strSepVal);

				XTP_EDIT_LINECOL endLC2 = rPtrTxtBlock->m_PosEndLC;

				pTxtIter->LCPosAdd(endLC2, nTagLenC+nSepLenC);

				rPtrTxtBlock->m_nEndTagXLCLen = rPtrTxtBlock->m_PosEndLC.GetXLC() -
												endLC2.GetXLC();
			}
			else
			{
				rPtrTxtBlock->m_nEndTagXLCLen = rPtrTxtBlock->m_PosEndLC.GetXLC() -
												runLC.GetXLC();
			}
		}
		else
		{
			CSingleLock singleLock(pTxtSch->GetDataLoker(), TRUE);

			ASSERT(pPrevClass);
			if (pPrevClass)
			{
				rPtrTxtBlock->m_PosEndLC = pPrevClass->m_PosEndLC;
				rPtrTxtBlock->m_nEndTagXLCLen = pPrevClass->m_nEndTagXLCLen;
			}
		}
	}

	//---------------------------------------------------------------------------
	return nRes;
}

int CXTPSyntaxEditLexClass::Run_Token(CTextIter* pTxtIter,
						  CXTPSyntaxEditLexTextSchema* pTxtSch,
						  CXTPSyntaxEditLexTextBlockPtr& rPtrTxtBlock )
{
	if (!pTxtIter || !pTxtSch)
	{
		ASSERT(FALSE);
		//TRACE
		return xtpEditLPR_Error;
	}

	//===========================================================================
	if (!m_token.m_tag.IsEmpty())
	{
		CString strTokenVal;
		//if (Run_Tags(pTxtIter, pTxtSch, &m_token.m_tag, strTokenVal))
		//BOOL bTagBegins = Run_Tags(pTxtIter, pTxtSch, &m_token.m_tag, strTokenVal);

		BOOL bTagBegins = m_token.m_tag.FindMaxWord(pTxtIter->GetText(1024),
								strTokenVal, 1024, FALSE, !IsCaseSensitive());

#ifdef DBG_AUTOMAT
		BOOL bTagBeginsX = Run_Tags(pTxtIter, pTxtSch, &m_token.m_tag, strTokenVal);
		if (bTagBeginsX  != bTagBegins)
		{
			ASSERT(FALSE);
		}
#endif
		if (bTagBegins)
		{
			CString strSeparator1, strSeparator2;
			if (Run_TokenSeparators(strTokenVal, pTxtIter, pTxtSch,
									strSeparator1, strSeparator2) )
			{
				int nLenC = (int)_tcsclen(strTokenVal);

				rPtrTxtBlock = pTxtSch->GetNewBlock();
				if (rPtrTxtBlock)
				{
					rPtrTxtBlock->m_ptrLexClass.SetPtr(this, TRUE);

					rPtrTxtBlock->m_PosStartLC = pTxtIter->GetPosLC();
					rPtrTxtBlock->m_nStartTagLen = nLenC;
				}

				pTxtIter->SeekNext(nLenC);

				int nRes = xtpEditLPR_StartFound | xtpEditLPR_EndFound | xtpEditLPR_Iterated;

				if (rPtrTxtBlock)
				{
					rPtrTxtBlock->m_PosEndLC = pTxtIter->GetPosLC();
					if (nLenC)
					{
						pTxtIter->LCPosDec(rPtrTxtBlock->m_PosEndLC);
					}
					rPtrTxtBlock->m_nEndTagXLCLen = rPtrTxtBlock->m_PosEndLC.GetXLC() -
										rPtrTxtBlock->m_PosStartLC.GetXLC();
				}
				else
				{
					nRes |= xtpEditLPR_Error;
				}

				return nRes;
			}
		}
	}

	return 0;
}

BOOL CXTPSyntaxEditLexClass::Run_TokenSeparators(CString strToken,
									  CTextIter* pTxtIter,
									  CXTPSyntaxEditLexTextSchema* pTxtSch,
									  CString& rstrSeparator1,
									  CString& rstrSeparator2)
{
	rstrSeparator1.Empty();
	rstrSeparator2.Empty();

	//===========================================================================
	BOOL bTSyes = TRUE;
	BOOL bTEyes = TRUE;

	if (!m_token.m_start_separators.IsEmpty())
	{
		bTSyes = Run_Tags(pTxtIter, pTxtSch, &m_token.m_start_separators, rstrSeparator1, TRUE);
	}

	if (!m_token.m_end_separators.IsEmpty())
	{
		int nLen = strToken.GetLength();
		pTxtIter->SetTxtOffset(nLen);

		bTEyes = Run_Tags(pTxtIter, pTxtSch, &m_token.m_end_separators, rstrSeparator2);

		pTxtIter->SetTxtOffset(0);
	}

	return bTSyes && bTEyes;
}

BOOL CXTPSyntaxEditLexClass::Run_Tags(CTextIter* pIter,
							 CXTPSyntaxEditLexTextSchema* pTxtSch,
							 CXTPSyntaxEditLexVariantPtrArray* pLVTags,
							 CString& rstrTagVal, BOOL bParseDirection_Back
							 )
{
	UNREFERENCED_PARAMETER(pTxtSch);

	BOOL bCaseSensitive = IsCaseSensitive();

	return Run_Tags1(pIter, pLVTags, rstrTagVal, bCaseSensitive, bParseDirection_Back);
}

BOOL CXTPSyntaxEditLexClass::Run_Tags1(CTextIter* pIter,
							CXTPSyntaxEditLexVariantPtrArray* pLVTags,
							CString& rstrTagVal, BOOL bCaseSensitive,
							BOOL bParseDirection_Back
							)
{
	if (!pLVTags)
	{
		ASSERT(FALSE);
		return FALSE;
	}

	int nCount = (int)pLVTags->GetSize();

	for (int i = 0; i < nCount; i++)
	{
		CXTPSyntaxEditLexVariant* pVTag = pLVTags->GetAt(i, FALSE);

		if (Run_Tags2(pIter, pVTag, rstrTagVal, bCaseSensitive, bParseDirection_Back) )
		{
			return TRUE;
		}
	}
	return FALSE;
}

int CXTPSyntaxEditLexClass::Run_Tags2(CTextIter* pIter,
							CXTPSyntaxEditLexVariant* pVTags,
							CString& rstrTagVal,
							BOOL bCaseSensitive,
							BOOL bParseDirection_Back
						   )
{
	LPCTSTR pText = pIter->GetText();

	if (!pVTags)
	{
		ASSERT(FALSE);
		//TRACE
		return 0;
	}

	if (pVTags->m_nObjType == xtpEditLVT_valStr)
	{
		if (bParseDirection_Back)
		{
			pText = _tcsdec(pText-5, pText);
		}

		for (int k = 0; k < pVTags->m_arStrVals.GetSize(); k++)
		{
			LPCTSTR pcszTag = pVTags->m_arStrVals[k];
			int nLen = (int)_tcsclen(pcszTag);

			if (nLen <= 0)
			{
				ASSERT(FALSE);
				continue;
			}

			if (bParseDirection_Back)
			{
				pcszTag = _tcsninc(pcszTag, nLen-1);
			}

			if (StrCmpEQ(pcszTag, pText, nLen, bCaseSensitive, bParseDirection_Back))
			{
				rstrTagVal = pcszTag;
				return TRUE;
			}
		}
		return FALSE;
	}
	else if (pVTags->m_nObjType == xtpEditLVT_valVar)
	{
		if (bParseDirection_Back)
		{
			pText = _tcsdec(pText-5, pText);
		}
		if (StrVarCmpEQ(pText, pVTags->m_Variable, rstrTagVal, bParseDirection_Back))
		{
			return TRUE;
		}

		return FALSE;
	}
	else
	{
		ASSERT(FALSE);
		//TRACE
	}
	return FALSE;
}

void CXTPSyntaxEditLexClass::CopyFrom(const CXTPSyntaxEditLexClass* pSrc)
{
	if (!pSrc)
	{
		ASSERT(FALSE);
		return;
	}

	m_Parent.eOpt = pSrc->m_Parent.eOpt;
	m_Parent.ptrDirect = pSrc->m_Parent.ptrDirect;

	m_Parent.arClassNames.RemoveAll();
	m_Parent.arClassNames.Append(pSrc->m_Parent.arClassNames);

	m_Children.eOpt = pSrc->m_Children.eOpt;

	m_Children.arClassNames.RemoveAll();
	m_Children.arClassNames.Append(pSrc->m_Children.arClassNames);

	m_strClassName = pSrc->GetClassName();

	TBase::CopyFrom(*pSrc);

	CopyAttributes(pSrc);

	m_arChildrenClasses.RemoveAll();
	m_arDynChildrenClasses.RemoveAll();
	m_arChildrenSelfRefClasses.RemoveAll();
}

const CXTPSyntaxEditLexClass& CXTPSyntaxEditLexClass::operator=(const CXTPSyntaxEditLexClass& rSrc)
{
	CopyFrom(&rSrc);

	return *this;
}

CXTPSyntaxEditLexClass* CXTPSyntaxEditLexClass::Clone(CXTPSyntaxEditLexClassSchema* pOwnerSch)
{
	CXTPSyntaxEditLexClass* pNewClass = NULL;
	if (pOwnerSch)
	{
		pNewClass = pOwnerSch->GetNewClass(FALSE);
	}
	else
	{
		pNewClass = new CXTPSyntaxEditLexClass();
	}

	if (pNewClass)
	{
		pNewClass->CopyFrom(this);
	}

	return pNewClass;
}

void CXTPSyntaxEditLexClass::RemoveAttributes(LPCTSTR pcszAttrPrefix)
{
	ClearAttributesCache();

	if (pcszAttrPrefix)
	{
		int nLenC = (int)_tcsclen(pcszAttrPrefix);
		CString strKey;
		CStringArray arKeysToRemove;

		POSITION pos = m_mapAttributes.GetStartPosition();
		while (pos)
		{
			CXTPSyntaxEditLexVariantPtr ptrVal;
			m_mapAttributes.GetNextAssoc(pos, strKey, ptrVal);
			if (_tcsnicmp(pcszAttrPrefix, strKey, nLenC) == 0)
			{
				arKeysToRemove.Add(strKey);
			}
		}

		//-----------------------------------------
		int nCount = (int)arKeysToRemove.GetSize();
		for (int i = 0; i < nCount; i++)
		{
			strKey = arKeysToRemove[i];
			m_mapAttributes.RemoveKey(strKey);
		}
	}
	else
	{
		m_mapAttributes.RemoveAll();
	}
}

void CXTPSyntaxEditLexClass::CopyAttributes(const CXTPSyntaxEditLexClass* pSrcAttrClass,
								  LPCTSTR pcszAttrPrefix)
{
	RemoveAttributes(pcszAttrPrefix);

	if (!pSrcAttrClass)
	{
		ASSERT(FALSE);
		return;
	}

	int nLenC = pcszAttrPrefix ? (int)(_tcsclen(pcszAttrPrefix)) : 0;
	CString strKey;

	POSITION pos = pSrcAttrClass->m_mapAttributes.GetStartPosition();
	while (pos)
	{
		CXTPSyntaxEditLexVariantPtr ptrVal;
		pSrcAttrClass->m_mapAttributes.GetNextAssoc(pos, strKey, ptrVal);

		if (pcszAttrPrefix)
		{
			if (_tcsnicmp(pcszAttrPrefix, strKey, nLenC) == 0)
			{
				m_mapAttributes[strKey] = ptrVal;
			}
		}
		else
		{
			m_mapAttributes[strKey] = ptrVal;
		}
	}
}

void CXTPSyntaxEditLexClass::SetAttribute(CString strName, const CXTPSyntaxEditLexVariant& rVal)
{
	ClearAttributesCache();

	strName.MakeLower();
	CXTPSyntaxEditLexVariantPtr ptrData = new CXTPSyntaxEditLexVariant(rVal);

	m_mapAttributes[strName] = ptrData;
}

CXTPSyntaxEditLexVariantPtr CXTPSyntaxEditLexClass::GetAttribute(LPCTSTR strName, BOOL bDyn) const
{
	CString strName_lower = strName;
	strName_lower.MakeLower();
	CXTPSyntaxEditLexVariantPtr ptrData;

	if (m_mapAttributes.Lookup(strName_lower, ptrData))
	{
		return ptrData;
	}
	if (bDyn && m_Parent.ptrDirect)
	{
		ptrData = m_Parent.ptrDirect->GetAttribute(strName_lower, TRUE);
		return ptrData;
	}
	return NULL;
}

#ifdef _DEBUG
void CXTPSyntaxEditLexClass::DumpOffset(CDumpContext& dc, LPCTSTR pcszOffset)
{
	if (!pcszOffset)
	{
		pcszOffset = _T("");
	}
	int i;
	dc << _T("\n");

	dc << pcszOffset;
	dc << _T("lexClass:   NAME=") << m_strClassName << _T(" \n");

	//------------------------------------
	dc << pcszOffset;
	if (m_Parent.eOpt == xtpEditOptParent_file)
	{
		dc << _T("parent:file = ");
	}
	else if (m_Parent.eOpt == xtpEditOptParent_direct)
	{
		dc << _T("parent = ");
	}
	else if (m_Parent.eOpt == xtpEditOptParent_dyn)
	{
		dc << _T("parent:dyn = ");
	}
	else
	{
		dc << _T("parent:??? = ");
	}

	for (i = 0; i < m_Parent.arClassNames.GetSize(); i++)
	{
		dc << m_Parent.arClassNames[i] << _T(", ");
	}
	if (m_Parent.ptrDirect)
	{
		dc << _T(" // [parent_by_ptr=[") << m_Parent.ptrDirect->m_strClassName << _T("] ");
	}
	dc << _T(" \n");

	//------------------------------------
	if (m_Children.eOpt == xtpEditOptChildren_No)
	{
		dc << pcszOffset;
		dc << _T("children = 0 \n");
	}
	if (m_Children.eOpt == xtpEditOptChildren_List)
	{
		dc << pcszOffset;
		dc << _T("children = ");
		for (i = 0; i < m_Children.arClassNames.GetSize(); i++)
		{
			dc <<  m_Children.arClassNames[i] << _T(", ");
		}
		dc << _T(" \n");
	}

	//------------------------------------

	m_previous.DumpOffset(dc, pcszOffset);

	m_start.DumpOffset(dc, pcszOffset);
	m_end.DumpOffset(dc, pcszOffset);

	m_token.DumpOffset(dc, pcszOffset);

	m_skip.DumpOffset(dc, pcszOffset);

	m_ActiveTags.DumpOffset(dc, pcszOffset);
}
#endif

void CXTPSyntaxEditLexClass::GetTextAttributes(XTP_EDIT_TEXTBLOCK& rTB)
{
	if (!m_bTxtAttr_cached)
	{
		m_bTxtAttr_cached = TRUE;

		m_txtAttr_cached.clrBlock.crText = COLORREF_NULL;
		m_txtAttr_cached.clrBlock.crBack = COLORREF_NULL;
		m_txtAttr_cached.clrBlock.crHiliteText  = COLORREF_NULL;
		m_txtAttr_cached.clrBlock.crHiliteBack = COLORREF_NULL;

		m_txtAttr_cached.lf.lfWeight = XTP_EDIT_FONTOPTIONS_UNSPEC_OPTION;
		m_txtAttr_cached.lf.lfItalic = XTP_EDIT_FONTOPTIONS_UNSPEC_OPTION;
		m_txtAttr_cached.lf.lfUnderline = XTP_EDIT_FONTOPTIONS_UNSPEC_OPTION;

		//====================================================================
		CXTPSyntaxEditLexVariantPtr ptrLVA;
		ptrLVA = GetAttribute(XTPLEX_ATTR_TXT_COLORFG, TRUE);
		if (ptrLVA && ptrLVA->m_nObjType == xtpEditLVT_valInt)
		{
			m_txtAttr_cached.clrBlock.crText = (COLORREF)ptrLVA->m_nValue;
		}

		ptrLVA = GetAttribute(XTPLEX_ATTR_TXT_COLORBK, TRUE);
		if (ptrLVA && ptrLVA->m_nObjType == xtpEditLVT_valInt)
		{
			m_txtAttr_cached.clrBlock.crBack = (COLORREF)ptrLVA->m_nValue;
		}

		ptrLVA = GetAttribute(XTPLEX_ATTR_TXT_COLORSELFG, TRUE);
		if (ptrLVA && ptrLVA->m_nObjType == xtpEditLVT_valInt)
		{
			m_txtAttr_cached.clrBlock.crHiliteText  = (COLORREF)ptrLVA->m_nValue;
		}

		ptrLVA = GetAttribute(XTPLEX_ATTR_TXT_COLORSELBK, TRUE);
		if (ptrLVA && ptrLVA->m_nObjType == xtpEditLVT_valInt)
		{
			m_txtAttr_cached.clrBlock.crHiliteBack = (COLORREF)ptrLVA->m_nValue;
		}

		//===========================================================================
		ptrLVA = GetAttribute(XTPLEX_ATTR_TXT_BOLD, TRUE);
		if (ptrLVA && ptrLVA->m_nObjType == xtpEditLVT_valInt)
		{
			m_txtAttr_cached.lf.lfWeight =
					ptrLVA->m_nValue ? FW_BOLD : XTP_EDIT_FONTOPTIONS_UNSPEC_OPTION;
		}

		ptrLVA = GetAttribute(XTPLEX_ATTR_TXT_ITALIC, TRUE);
		if (ptrLVA && ptrLVA->m_nObjType == xtpEditLVT_valInt)
		{
			m_txtAttr_cached.lf.lfItalic =
					ptrLVA->m_nValue ? (BYTE)1 : XTP_EDIT_FONTOPTIONS_UNSPEC_OPTION;
		}

		ptrLVA = GetAttribute(XTPLEX_ATTR_TXT_UNDERLINE, TRUE);
		if (ptrLVA && ptrLVA->m_nObjType == xtpEditLVT_valInt)
		{
			m_txtAttr_cached.lf.lfUnderline =
					ptrLVA->m_nValue ? (BYTE)1 : XTP_EDIT_FONTOPTIONS_UNSPEC_OPTION;
		}
	}

	//===========================================================================
	if (m_txtAttr_cached.clrBlock.crText != COLORREF_NULL)
	{
		rTB.clrBlock.crText = m_txtAttr_cached.clrBlock.crText;
	}
	if (m_txtAttr_cached.clrBlock.crBack != COLORREF_NULL)
	{
		rTB.clrBlock.crBack = m_txtAttr_cached.clrBlock.crBack;
	}
	if (m_txtAttr_cached.clrBlock.crHiliteText != COLORREF_NULL)
	{
		rTB.clrBlock.crHiliteText = m_txtAttr_cached.clrBlock.crHiliteText;
	}
	if (m_txtAttr_cached.clrBlock.crHiliteBack != COLORREF_NULL)
	{
		rTB.clrBlock.crHiliteBack = m_txtAttr_cached.clrBlock.crHiliteBack;
	}

	rTB.lf.lfWeight = m_txtAttr_cached.lf.lfWeight;
	rTB.lf.lfItalic = m_txtAttr_cached.lf.lfItalic;
	rTB.lf.lfUnderline = m_txtAttr_cached.lf.lfUnderline;
}

CXTPSyntaxEditLexVariantPtrArray* CXTPSyntaxEditLexClass::BuildActiveTags(int& rnStartCount)
{
	m_ActiveTags.RemoveAll();
	m_nActiv_EndTags_Offset = 0;

	//== start class tags =====
	const TCHAR* s_arActiveTagsObjs1[] = {
			_T("start:Tag"),
			_T("previous:tag"),
			_T("previous:tag:separators"),
			_T("Token:tag")
	};

	//== end class tags =====
	const TCHAR* s_arActiveTagsObjs2[] = {
			_T("skip:Tag"),
			_T("end:Tag"),
			_T("end:separators")
	};

	//== 1. process start tags =====
	int a;
	for (a = 0; a < _countof(s_arActiveTagsObjs1); a++)
	{
		CXTPSyntaxEditLexVariantPtrArray* ptrAT = GetIfMy(s_arActiveTagsObjs1[a]);
		ASSERT(ptrAT);
		if (ptrAT)
		{
			ConcatenateLVArrays(&m_ActiveTags, ptrAT);

			// if start:Tag not empty - skip previous tags.
			// else previous tags are used to determine class start.
			if (a == 0 && ptrAT->GetSize() > 0)
			{
				a += 2;
			}
		}
	}

	//m_ActiveTags.Dump(_T("~a1~ "));

	//== 2. process children and add start tags only =====
	CXTPSyntaxEditLexClassPtrArray* arChildren[2];

	arChildren[0] = GetChildren();
	arChildren[1] = GetChildrenDyn();

	int i;
	for (i = 0; i < _countof(arChildren); i++)
	{
		int nKCount = arChildren[i] ? (int)arChildren[i]->GetSize() : 0;
		int k;
		for (k = 0; k < nKCount; k++)
		{
			CXTPSyntaxEditLexClass* pCh = arChildren[i]->GetAt(k, FALSE);
			ASSERT(pCh);
			if (!pCh)
				continue;

			int nStartCount = 0;
			CXTPSyntaxEditLexVariantPtrArray* ptrATch = pCh->BuildActiveTags(nStartCount);
			if (ptrATch)
			{
				ConcatenateLVArrays(&m_ActiveTags, ptrATch, nStartCount);
			}
		}
	}

	//== 3. process end tags =====
	m_nActiv_EndTags_Offset = (int)m_ActiveTags.GetSize();

	for (a = 0; a < _countof(s_arActiveTagsObjs2); a++)
	{
		CXTPSyntaxEditLexVariantPtrArray* ptrAT = GetIfMy(s_arActiveTagsObjs2[a]);
		ASSERT(ptrAT);
		if (ptrAT)
		{
			ConcatenateLVArrays(&m_ActiveTags, ptrAT);
		}
	}

	//m_ActiveTags.Dump(_T("~a2~ "));

	//=======================
	rnStartCount = m_nActiv_EndTags_Offset;

	m_ActiveTags.BuildAutomat(TRUE);

	//********************
	m_token.m_tag.BuildAutomat(FALSE);
	//********************
	return &m_ActiveTags;
}