#include "stdafx.h"
#include "Finder.h"
#include <algorithm>
#include <AplGuiEx.h>

typedef std::pair<CaplAttr*, CaplInstance*> PAttrInst;

CString &CaplFinder_Impl::CAttr::GetOpName()
{
	static CString arr[2][9] = {
		{_T(" = "),  _T(" LIKE "),	 _T(" LIKE_LEFT "),     _T(" LIKE_RIGHT "),     _T(" IN "),     _T(" < "),  _T(" > "),  _T(" <= "),  _T(" >= ")},
		{_T(" != "), _T(" NOT LIKE "), _T(" NOT LIKE_LEFT "), _T(" NOT LIKE_RIGHT "), _T(" NOT_IN "), _T(" >= "), _T(" <= "), _T(" > "),   _T(" < ")}
	};
	return arr[m_bNot ? 1 : 0][m_cmpop];
}

CString &CaplFinder_Impl::GetGrpTypeName(groupType gt)
{
	static CString sAnd(_T(" AND "));
	static CString sOr(_T(" OR "));
	return ((gt == CaplFinder::grpAND) ? sAnd : sOr);
}

int CaplFinder_Impl::GetNextId(CElement *el)
{
	if(!el) return 0;
	int ret = m_allElements.size();
	m_allElements.push_back(el);
	return ret;
}

int CaplFinder::CreateSqlExtent(aplExtent &ext, LPCTSTR name, CString &strExt, CString *sqIN, CString *sqNotIN, int maxLoad, int *nFrom)
{
	int i = 0, co = 0, to = ext.GetSize();
	strExt.Empty();
	if(sqIN) sqIN->Empty();
	if(sqNotIN) sqNotIN->Empty();
	CString sq, s;
	CaplInstance *inst;
	if(nFrom) i = *nFrom;
	if(maxLoad <= 0) maxLoad = ext.GetSize();
	for(; (i<to) && (co < maxLoad); i++)
	{
		inst = ext[i];
		if(!inst) continue;
		if((inst->GetId() == 0) || !inst->GetType()) continue;
		if(sq.IsEmpty()) sq.Format(_T("#%d"), inst->GetId());
		else { s.Format(_T(", #%d"), inst->GetId()); sq += s; }
		++co;
	}
	if(nFrom) *nFrom = i;
	if(co == 0) return 0;
	if(!name && !sqIN && !sqNotIN)
	{
		strExt = sq;
		return co;
	}
	if(co == 1)
	{
		if(sqIN)	sqIN->Format(_T("= %s"), sq);
		if(sqNotIN)	sqNotIN->Format(_T("!= %s"), sq);
		if(!sqIN && !sqNotIN) strExt.Format(_T("%s{%s}"), name, sq);
	}
	else
	{
		strExt.Format(_T("%s{%s} \n"), name, sq);
		if(sqIN)	sqIN->Format(_T("IN #%s"), name);
		if(sqNotIN)	sqNotIN->Format(_T("NOT_IN #%s"), name);
	}
	return co;
}

bool CaplFinder::sm_bCanCutQuery = true;

void CaplFinder::SetCanCutQuery(bool bCutQuery)
{
	sm_bCanCutQuery = bCutQuery;
}

CaplFinder::CaplFinder(const CString& _source/*используйте макрос DEF_SOURCE как параметр*/)
{
	m_finder = new CaplFinder_Impl(_source);
	m_finder->m_bCanCutQuery = sm_bCanCutQuery;
}

CaplFinder::~CaplFinder()
{
	if(m_finder) delete m_finder;
	m_finder = NULL;
}

void CaplFinder::Clear()
{
	if(m_finder)
		m_finder->Clear();
}


CaplEntity *CaplFinder::GetEntity(int ext)
{
	CaplFinder_Impl::CExt *pExt = m_finder->GetExtByExt(ext);
	if(!pExt) return NULL;
	if(pExt->GetValsExt()) return NULL;
	CaplFinder_Impl::CSubQueryExt *PSub = (CaplFinder_Impl::CSubQueryExt *)pExt;
	return PSub->m_ent;
}

bool CaplFinder::IsExtent(int ext, bool bRoot /* = true */)
{
	CaplFinder_Impl::CExt *pExt = m_finder->GetExtByExt(ext);
	return (!pExt ? false : (bRoot ? pExt->m_bIsRoot : true));
}

bool CaplFinder::CreateQStr(CString &strQL, bool bLoadAttrs)
{
	return m_finder->MakeQStr(strQL, bLoadAttrs);;
}

bool CaplFinder::CreateSQLStr(CaplNetStepData* data, CString &strQL, bool bLoadAttrs)
{
	return m_finder->MakeSQLStr(data,strQL, bLoadAttrs);;
}

//Нужно ли разбить запрос на несколько запросов
bool CaplFinder_Impl::NeedCutQueryGroup(CElement*& pTargetGroupOut, int& iPartSizeOut)
{
	pTargetGroupOut = NULL;
	iPartSizeOut = MAX_COUNT_OBJECTS_IN_QUERY;

	if (m_subExts.size() != 1)
		return false;

	CSubQueryExt* pSubExt = dynamic_cast<CSubQueryExt*>(*m_subExts.begin());
	if (pSubExt == NULL)
		return false;

	////Превышает максимальное количество addAttr`ов?

	//Проверка на удовлетворение запроса требованиям сложности: только запросы содержащие простую(без подгрупп) группу "ИЛИ" разбиваются на подзапросы)
	mapCountElement mapElemCnt;
	FillElementCount(&pSubExt->m_grp, mapElemCnt);

	int iCntAll = 0;
	for (itMapCountElement it = mapElemCnt.begin(); it != mapElemCnt.end(); ++it)
		iCntAll += it->first;

	int iTargetSize = mapElemCnt.begin()->first;
	pTargetGroupOut = mapElemCnt.begin()->second;

	//Запрос удовлетворяет требованиям сложности и количество объектов в запросе превышает максимально допустимое => нужно разбить на позапросы
	if (pTargetGroupOut == NULL || iCntAll <= MAX_COUNT_OBJECTS_IN_QUERY)
		return false;

	if (iTargetSize != iCntAll)
		iPartSizeOut = MAX_COUNT_OBJECTS_IN_QUERY - (iCntAll - iTargetSize);

	if (iPartSizeOut <= 0)
		return false;
	
	return true;
}

// Получить все элементы запроса и количество входящих простых addAttr'ов и инстансов.
int CaplFinder_Impl::FillElementCount(CElement* pElem, mapCountElement& mapElemCntOut)
{
	int iCount = 1;
	CAttrGroup* pGrp = dynamic_cast<CAttrGroup*>(pElem);
	CExtAttr* pExtAttr = dynamic_cast<CExtAttr*>(pElem);

	if (pGrp != NULL)
	{
		// Подсчет addAttr`ов в подзапросе
		iCount = 0;
		listElements& rItems = pGrp->m_items;
		for (listElIter it = rItems.begin(); it != rItems.end(); ++it)
		{
			iCount += FillElementCount(*it, mapElemCntOut);
		}

		mapElemCntOut.insert(std::make_pair(iCount, pElem));
		return 0;
	}
	else if (pExtAttr != NULL)
	{
		// Подсчет инстансов в запросе
		CExtVals* pVal = dynamic_cast<CExtVals*>(pExtAttr->GetInnerExtent());
		if (pVal != NULL && pVal->m_ext != NULL)
		{
			iCount = pVal->m_ext->GetSize();
			mapElemCntOut.insert(std::make_pair(iCount, pElem));
		}

		return 0;
	}

	return iCount;
}

bool CaplFinder_Impl::FindDB(CaplNetStepData *data, aplExtent &ret, bool bDlg, bool bAttrs)
{
	bool bRet = true;
	CString sql;
	SetData(data);
	
	int	iMaxPartSize = MAX_COUNT_OBJECTS_IN_QUERY;
	CElement* pCutGrp;
	if (m_bCanCutQuery && NeedCutQueryGroup(pCutGrp, iMaxPartSize) && iMaxPartSize > 0)
	{
		CAttrGroup* pGrp = dynamic_cast<CAttrGroup*>(pCutGrp);
		if (pGrp != NULL)
		{
			listElements& rItems = pGrp->m_items;
			int iExtSize = rItems.size();

			aplExtent extRetPart;
			vectElements vAllItems(rItems.begin(), rItems.end());
			listElIter itListItem;

			//Если запрос более MAX_COUNT_OBJECTS_IN_QUERY объектов, то разбиваем на несколько запросов
			int iPos = 0;
			int iCurPartSize = iMaxPartSize;
			rItems.resize(iCurPartSize);
			while (iPos < iExtSize)
			{
				if (iExtSize - iPos < iMaxPartSize)
				{
					iCurPartSize = iExtSize - iPos;
					rItems.resize(iCurPartSize);
				}

				itListItem = rItems.begin();
				for (int i = iPos; i < iPos + iCurPartSize; ++i)
				{
					*itListItem = vAllItems[i];
					++itListItem;
				}

				if (!MakeQStr(sql, bAttrs)) return false;

				if(!data->NET_QueryEditParse(sql, bDlg)) return false;

				bRet &= data->NET_QueryExecute(extRetPart, NULL, m_sSource);

				ret.Append(extRetPart);
				iPos += iCurPartSize;
			}

			return bRet;
		}
		else
		{
			CExtAttr* pExtAttr = dynamic_cast<CExtAttr*>(pCutGrp);
			if (pExtAttr == NULL)
				return false;

			CExtVals* pVal = dynamic_cast<CExtVals*>(pExtAttr->GetInnerExtent());
			if (pVal == NULL || pVal->m_ext == NULL)
				return false;

			aplExtent& rValExt = *(pVal->m_ext);
			int iExtSize = rValExt.GetSize();

			aplExtent extRetPart;
			aplExtent extAllItems;
			extAllItems.Append(rValExt);

			//Если запрос более MAX_COUNT_OBJECTS_IN_QUERY объектов, то разбиваем на несколько запросов
			int iPos = 0;
			int iCurPartSize = iMaxPartSize;
			while (iPos < iExtSize)
			{
				rValExt.Clear();
				if (iExtSize - iPos < iMaxPartSize)
				{
					iCurPartSize = iExtSize - iPos;
				}

				for (int i = iPos; i < iPos + iCurPartSize; ++i)
					rValExt.Add(extAllItems[i]);

				if (!MakeQStr(sql, bAttrs)) return false;

				if(!data->NET_QueryEditParse(sql, bDlg)) return false;

				bRet &= data->NET_QueryExecute(extRetPart, NULL, m_sSource);

				ret.Append(extRetPart);
				iPos += iCurPartSize;
			}

			return bRet;
		}
	}

	if (!MakeQStr(sql, bAttrs)) return false;

	if(!data->NET_QueryEditParse(sql, bDlg)) return false;

	bRet &= data->NET_QueryExecute(ret, NULL, m_sSource);

	return bRet;
}

bool CaplFinder::QuickFindByVecStr(CaplNetStepData *data, CStringArray &values, CaplAttr *attr)
{
	if (0 == data || false == data->IsConnected())
		return false;

	Clear();

	aplExtent result, tmpExt;
	int index = CreateExt(attr->entity, 0, 0, CaplFinder::grpOR);

	for (int i = 0; i < values.GetSize(); ++i)
	{
		AddAttr(index, attr, values[i], CaplFinder::cmpEqual);
		if (i % 200 == 0 || i == values.GetSize() - 1)
		{			
			AddToResult(index);
			Find(*data, true, false, false, true, true);

			result.Append(m_innerExtent);
			
			Clear();
			index = CreateExt(attr->entity, 0, 0, CaplFinder::grpOR);
		}
	}

	m_innerExtent.Clear();
	m_innerExtent.Append(result);

	return true;
}

bool CaplFinder::QuickFindByInstances(CaplNetStepData *data, aplExtent &items, CaplAttr *attr)
{
	if(0 == data || false == data->IsConnected())
		return false;

	aplExtent result, tmpExt;
	int index = CreateExt(attr->entity);

	for(int i = 0; i<items.Size; ++i)
	{
		tmpExt.Add(items[i]);		
		if(tmpExt.Size == 500 || i == items.Size - 1)
		{
			AddAttr(index, attr, CreateExt(tmpExt, true));
			AddToResult(index);
			Find(*data, true, false, false, true, true);

			result.Append(m_innerExtent);			
			tmpExt.Clear();

			Clear();
			index = CreateExt(attr->entity);
		}
	}

	m_innerExtent.Clear();
	m_innerExtent.Append(result);

	return true;
}

bool CaplFinder::QuickFind(CaplNetStepData *data, bool bFromBase, int count, ...)
{
	if(count < 1 || 0 == data || false == data->IsConnected())
		return false;

	Clear();

	int index = -1;
	va_list argptr;				
	va_start(argptr, count);	

	for(int i = 0; count; --count, ++i) 
	{
		std::pair<CaplAttr*, CaplInstance*> val = va_arg(argptr, PAttrInst); 		
		if(0 == i)
			index = CreateExt(val.first->entity);					
		
		AddAttr(index, val.first, val.second, cmpEqual);
	}

	AddToResult(index);
	Find(*data, bFromBase, !bFromBase, false, bFromBase, true);
	
	va_end(argptr);
	return true;
}

bool CaplFinder::Find(CaplNetStepData &data, bool bInBase, bool bInCashe, bool bDlg, bool bLoadAttrs, bool bOra)
{
	m_innerExtent.Clear();

	return Find(data, m_innerExtent, bInBase, bInCashe, bDlg, bLoadAttrs,bOra);
}

bool CaplFinder::Find(CaplNetStepData &data, aplExtent &extRet, bool bInBase, bool bInCashe, bool bDlg, bool bLoadAttrs, bool bOra)
{
	return Find(&data, extRet, bInBase, bInCashe, bDlg, bLoadAttrs,bOra);
}

bool CaplFinder::Find(CaplNetStepData *data, aplExtent &extRet, bool bInBase, bool bInCashe, bool bDlg, bool bLoadAttrs, bool bOra)
{
	if(data==NULL)
	{
		return false;
	}

	extRet.Clear();	
	
	if (!bInBase && !bInCashe) return true;

	bool bBufCashe = bInCashe||!data->IsConnected();
	bool bBufBase = bInBase&&data->IsConnected();
	bool bIsOra = false;
	CString s1, s2;
	double dVer;
	data->GetVersionServer(s1, s2);
	dVer = Str2Double(s1);
	s2.MakeUpper();
	bIsOra = !s2.CompareNoCase(_T("ORACLE"));
	bIsOra = bIsOra && (deq(dVer, 4.059) || dVer > 4.059); // номер сервера, с которого возможно работа поисковика

	aplExtent extDB;
	aplExtent extLC;

	bool bOldUnique = extRet.Unique;

	extRet.Unique = false;

	if (bBufBase)
	{
		if (bOra && bIsOra)
			m_finder->FindDB_Ora(data, extDB, bDlg, bLoadAttrs); // поищем ораклом
		else
			m_finder->FindDB(data, extDB, bDlg, bLoadAttrs); // поищем в БД
	}

	if (bBufCashe)
	{		
		m_finder->FindLC(data, extLC); // ищем в локальном кэше
	}
	
	if (bBufCashe && bBufBase)
	{
		for (int i = 0; i < extDB.GetSize(); ++i)
		{
			if (!extDB[i]->GetType()) continue;
			if (!std::binary_search(extLC.begin(), extLC.end(), extDB[i]))
				extRet.Add(extDB[i]);
		}

		extRet.Append(extLC);

		for(int i = 0; i<extRet.GetSize(); ++i)
		{
			if(extRet[i]->GetType()==NULL)
			{
				extRet.Remove(i);
				i--;
			}
		}
	}
	else if (bBufBase && !bBufCashe)
	{
		extRet.Append(extDB);
	}
	else if (!bBufBase && bBufCashe)
	{
		extRet.Append(extLC);
	}

	extRet.Unique = bOldUnique;

	return true;
}

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

int CaplFinder::CreateExt(CaplEntity *entity, CaplAttr *endAttr, CaplEntity *endEnt, groupType grpType)
{
	CaplFinder_Impl::CSubQueryExt *pExt = new CaplFinder_Impl::CSubQueryExt(entity, grpType);
	if(endAttr) {pExt->m_back.attr = endAttr; pExt->m_back.ent = endEnt;}
	m_finder->m_subExts.push_back(pExt);
	return m_finder->GetNextId(pExt);
}

int CaplFinder::CreateExt(aplExtent &ext, bool bCopy)
{
	CaplFinder_Impl::CExtVals *pExt = new CaplFinder_Impl::CExtVals(ext, bCopy);
	m_finder->m_valsExts.push_back(pExt);
	return m_finder->GetNextId(pExt);
}

int CaplFinder::CreateAttrExt(int ext, CaplAttr *attr, CaplEntity *entity, groupType grpType)
{
	CaplFinder_Impl::CAttrGroup *grp = m_finder->GetAGrpByExt(ext);
	if(!grp) return 0;
	CaplFinder_Impl::CSubQueryExt *val = new CaplFinder_Impl::CSubQueryExt(entity, grpType);
	val->m_bIsRoot = false;
	grp->m_items.push_back(new CaplFinder_Impl::CPathAttr(grp, attr, val));
	return m_finder->GetNextId(val);
}

int CaplFinder::CreateGroup(int ext, groupType grpType)
{
	CaplFinder_Impl::CAttrGroup *grp = m_finder->GetAGrpByExt(ext);
	if(!grp) return 0;
	if(grpType == grp->m_type) return ext;
	CaplFinder_Impl::CAttrGroup *pGrp = new CaplFinder_Impl::CAttrGroup(grp, grpType);
	pGrp->m_ext = grp->m_ext;
	grp->m_items.push_back(pGrp);
	return m_finder->GetNextId(pGrp);
}

//////////////////////////////////////////////////////////////////////////
void CaplFinder::AddSelf(int ext, int val, bool bIn)
{
	CaplFinder_Impl::CAttrGroup *grp = m_finder->GetAGrpByExt(ext);
	if(!grp) return;
	CaplFinder_Impl::CExt *pExt = m_finder->GetExtByExt(val);
	if(!pExt) return;
	CaplFinder_Impl::CSelfExt *pn = new CaplFinder_Impl::CSelfExt(grp, bIn, pExt);
	grp->m_items.push_back(pn);
}

void CaplFinder::AddSelf(int ext, CaplInstance *val, bool bEqual)
{
	if(val) if(!val->GetId()) return;
	CaplFinder_Impl::CAttrGroup *grp = m_finder->GetAGrpByExt(ext);
	if(!grp) return;
	CaplFinder_Impl::CSelfInst *pn = new CaplFinder_Impl::CSelfInst(grp, bEqual, val);
	grp->m_items.push_back(pn);
}

void CaplFinder::AddAttrEmpty(int ext, CaplAttr *attr, bool bIsEmpty)
{
	if(!attr) return;
	CaplFinder_Impl::CAttrGroup *grp = m_finder->GetAGrpByExt(ext);
	if(!grp) return;
	grp->m_items.push_back(new CaplFinder_Impl::CEmptyAttr(grp, attr, bIsEmpty));
}

void CaplFinder::AddAttr(int ext, CaplAttr *attr, LPCTSTR strVal, cmpOperation cmpop, bool bNot)
{
	bool bemp = (strVal ? !strVal[0] : true);
	if((cmpop >= cmpLike)&&(cmpop <= cmpLikeRigth)&&bemp) return;
	CaplFinder_Impl::CAttrGroup *grp = m_finder->GetAGrpByExt(ext);
	if(!grp) return;
	grp->m_items.push_back(new CaplFinder_Impl::CStrAttr(grp, attr, cmpop, strVal, bNot));
}

void CaplFinder::AddAttr(int ext, CaplAttr *attr, CaplInstance *val, cmpOperation cmpop, bool bNot)
{
	if((cmpop != cmpEqual)&&(cmpop != cmpLike)&&(cmpop != cmpNotEqual)) return;
	CaplFinder_Impl::CAttrGroup *grp = m_finder->GetAGrpByExt(ext);
	if(!grp) return;
	grp->m_items.push_back(new CaplFinder_Impl::CInstAttr(grp, attr, cmpop, val, bNot));
}

void CaplFinder::AddAttr(int ext, CaplAttr *attr, double val, cmpOperation cmpop, bool bNot)
{
	if((cmpop == cmpIN)||(cmpop == cmpLike)||(cmpop == cmpLikeLeft)||(cmpop == cmpLikeRigth)) return;
	CaplFinder_Impl::CAttrGroup *grp = m_finder->GetAGrpByExt(ext);
	if(!grp) return;
	grp->m_items.push_back(new CaplFinder_Impl::CDoubleAttr(grp, attr, cmpop, val, bNot));
}

void CaplFinder::AddAttr(int ext, CaplAttr *attr, bool val)
{
	CaplFinder_Impl::CAttrGroup *grp = m_finder->GetAGrpByExt(ext);
	if(!grp) return;
	grp->m_items.push_back(new CaplFinder_Impl::CBoolAttr(grp, attr, val));
}

void CaplFinder::AddAttr(int ext, CaplAttr *attr, int subExt, bool bIn)
{
	CaplFinder_Impl::CExt *pExt = m_finder->GetExtByExt(subExt);
	if (!pExt) return;
	if (!pExt->m_bIsRoot) return;
	CaplFinder_Impl::CAttrGroup *grp = m_finder->GetAGrpByExt(ext);
	if (!grp) return;

	grp->m_items.push_back(new CaplFinder_Impl::CExtAttr(grp, attr, cmpIN, pExt, !bIn));
}

void CaplFinder::AddAggrAttr( int ext, CaplAttr* attr, int subExt, CaplEntity* aggrType, bool bIn /*= true*/ )
{
	CaplFinder_Impl::CExt *pExt = m_finder->GetExtByExt(subExt);
	if (!pExt) return;
	if (!pExt->m_bIsRoot) return;
	CaplFinder_Impl::CAttrGroup *grp = m_finder->GetAGrpByExt(ext);
	if (!grp) return;

	grp->m_items.push_back(new CaplFinder_Impl::CExtAttr(grp, attr, cmpIN, pExt, !bIn, aggrType));
}

void CaplFinder::AddAttr(int ext, CaplAttr *attr, CaplAttr *val, cmpOperation cmpop, bool bNot)
{
	CaplFinder_Impl::CAttrGroup *grp = m_finder->GetAGrpByExt(ext);
	if(!grp) return;
	grp->m_items.push_back(new CaplFinder_Impl::CAttrAttr(grp, attr, cmpop, val, bNot));
}

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

CaplFinder &CaplFinder::SetResultGrpType(groupType grpType)
{
	m_finder->m_retGrp.m_type = grpType;
	return *this;
}

void CaplFinder_Impl::AddItemToRG(CRetItemGroup *pGrp, int ext, CaplAttr *attr)
{
	if(!pGrp) return;
	CExt *pExt = GetExtByExt(ext);
	if(!pExt) return;
	if(!pExt->m_bIsRoot) return;
	if(pExt->GetValsExt()) attr = NULL;
	CRetItem *item = new CRetItem(pExt, attr);
	pGrp->m_items.push_back(item);
}

CaplFinder &CaplFinder::AddToResult(int grp, int ext, CaplAttr *attr)
{
	m_finder->AddItemToRG(m_finder->GetRGByExt(grp), ext, attr);
	return *this;
}

CaplFinder &CaplFinder::AddToResult(int ext, CaplAttr *attr)
{
	m_finder->AddItemToRG(&m_finder->m_retGrp, ext, attr);
	return *this;
}

int CaplFinder_Impl::AddGrpToRG(CRetItemGroup *pGrp, groupType grt)
{
	CRetItemGroup *ng = new CRetItemGroup(pGrp, grt);
	pGrp->m_items.push_back(ng);
	return GetNextId(ng);
}

int CaplFinder::AddGrpToResult(int grp, groupType grpType)
{
	CaplFinder_Impl::CRetItemGroup *pGrp = m_finder->GetRGByExt(grp);
	if(!pGrp) return 0;
	if(grpType == pGrp->m_type) return grp;
	return m_finder->AddGrpToRG(pGrp, grpType);
}

int CaplFinder::AddGrpToResult(groupType grpType)
{
	if(grpType == m_finder->m_retGrp.m_type) return m_finder->m_rgi;
	return m_finder->AddGrpToRG(&m_finder->m_retGrp, grpType);
}

aplExtent *CaplFinder::GetExtValsExt(int ext)
{
	CaplFinder_Impl::CExtVals *e = m_finder->GetValsExt(ext);
	return (e ? e->m_ext : NULL);
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
void CaplFinder_Impl::Init()
{
	m_allElements.push_back(0);
	m_allElements.push_back(&m_retGrp);
	m_rgi = 1;	m_retGrp.m_type = CaplFinder::grpAND;
	m_bCanCutQuery = false;
}

CaplFinder_Impl::CaplFinder_Impl(const CString& _source/*используйте макрос DEF_SOURCE как параметр*/) : m_sSource(_source)
{
	Init();
}

void CaplFinder_Impl::Clear()
{
	listElIter cndIter;
	CElement *pExt;
	for (cndIter = m_valsExts.begin(); cndIter != m_valsExts.end(); ++cndIter)
	{	pExt = *cndIter;	delete pExt;}
	for (cndIter = m_subExts.begin(); cndIter != m_subExts.end(); ++cndIter)
	{	pExt = *cndIter;	delete pExt;}
	m_retGrp.Clear();
	m_valsExts.clear();
	m_subExts.clear();
	m_allElements.clear();
	Init();
}


CaplFinder_Impl::CExt *CaplFinder_Impl::GetExtByExt(subQuery ext)
{
	if((ext<1) || (ext >= (int)m_allElements.size())) return NULL;
	return m_allElements[ext]->GetExt();
}
CaplFinder_Impl::CExtVals *CaplFinder_Impl::GetValsExt(subQuery ext)
{
	if((ext<1) || (ext >= (int)m_allElements.size())) return NULL;
	return m_allElements[ext]->GetValsExt();
}
CaplFinder_Impl::CAttrGroup *CaplFinder_Impl::GetAGrpByExt(subQuery ext)
{
	if((ext<1) || (ext >= (int)m_allElements.size())) return NULL;
	return m_allElements[ext]->GetAGrp();
}
CaplFinder_Impl::CRetItemGroup *CaplFinder_Impl::GetRGByExt(retGroup ext)
{
	if((ext<1) || (ext >= (int)m_allElements.size())) return NULL;
	return m_allElements[ext]->GetRG();
}

CaplFinder_Impl::CExtVals::CExtVals(aplExtent &ext, bool bCopy)
{
	m_bCopy = bCopy;
	if(!bCopy) m_ext = &ext;
	else
	{
		m_ext = new aplExtent;
		m_ext->Unique = false;
		m_ext->Append(ext);
		m_ext->Unique = ext.Unique;
	}
}

void CaplFinder_Impl::SetExtNames()
{
	listElIter cndIter;
	for (cndIter = m_valsExts.begin(); cndIter != m_valsExts.end(); ++cndIter)
		((CExt *)*cndIter)->SetName();
	for (cndIter = m_subExts.begin(); cndIter != m_subExts.end(); ++cndIter)
		((CExt *)*cndIter)->SetName();
}

bool CaplFinder_Impl::MakeQStr(CString &str, bool bLoadAttrs)
{
	SetExtNames();
	CString s1, sCap, si;
	listElIter iter;
	CElement *ext;
	if (!m_retGrp.ToStr(sCap, this)) return false;

	for (iter = m_valsExts.begin(); iter != m_valsExts.end(); ++iter)
	{
		ext = *iter;
		if (!ext->ToStr(si, this)) return false;
		s1 += si + _T("\n");
	}

	for (iter = m_subExts.begin(); iter != m_subExts.end(); ++iter)
	{
		ext = *iter;
		if (!ext->ToStr(si, this)) return false;
		s1 += si + _T("\n");
	}

	str.Format(_T("SELECT%s \n%s \nFROM \n%s \nEND_SELECT"), (bLoadAttrs ? _T("_LOAD_ALL"): _T("")), sCap, s1);
	return true;
}

//////////////////////////////////////////////////////////////////////////
void CaplFinder_Impl::CGroup::Clear()
{
	listElIter iter;
	CElement *item;
	for(iter = m_items.begin(); iter != m_items.end(); ++iter)
	{	item = *iter;	delete item;}
	m_items.clear();
}

bool CaplFinder_Impl::CGroup::ToStr(CString &val, CaplFinder_Impl *data)
{
	if(m_items.size() == 0) return true;
	if(m_items.size() == 1)	return m_items.front()->ToStr(val, data);
	CElement *cnd;
	listElIter iter;
	CRetItemGroup *rg = GetRG();
	CString str1;
	int co = 0;
	for (iter = m_items.begin(); iter != m_items.end(); ++iter)
	{
		cnd = *iter;
		if (!cnd->ToStr(str1, data)) return false;
		if (str1 == _T(""))
			continue;
		if (co == 0)	val = str1;
		else			val += data->GetGrpTypeName(m_type) + (rg ? _T("") : _T("\n")) + str1;
		++co;
	}
	if (PrintSk(co))	val = _T('(') + val + _T(')');
	return (co > 0);
}

bool CaplFinder_Impl::CAttrGroup::PrintSk(int co)
{
	bool bSk = (co>1);
	if(m_parent) if((m_parent->m_items.size()<2) && (m_parent->m_parent != NULL)) bSk = false;
	return bSk;
}

bool CaplFinder_Impl::CRetItemGroup::PrintSk(int co)
{
	bool bSk = ((co > 1) && (m_parent != NULL));
	if(m_parent) bSk = bSk && (m_parent->m_items.size() > 1);
	return bSk;
}

bool CaplFinder_Impl::CEmptyAttr::ToStr(CString &val, CaplFinder_Impl *data)
{
	int n = (m_bNot ? 0 : 1);
	static CString strs[] = {_T(" = "),  _T(" != ")};
	switch(m_attr->type)
	{
	case aplAGGR     : if(!m_bNot) return false; // *****
					   val = _T("(.") + m_attr->name + _T(" aggr_empty)");		break;
	case aplENUMERATION :
	case aplSTRING   : val = _T(".") + m_attr->name + strs[n] + _T("\'\'");		break;
	case aplSELECT   :
	case aplINSTANCE : val = _T(".") + m_attr->name + strs[n] + _T("#0");		break;
	case aplBOOL :     val = _T(".") + m_attr->name + strs[n] + _T("false");	break;
	case aplREAL :				   
	case aplINTEGER :  val = _T(".") + m_attr->name + strs[n] + _T("0");		break;
	default: return false;
	}
	return true;
}

bool CaplFinder_Impl::CExt::ToStr(CString &val, CaplFinder_Impl *data)
{
	CString str;
	if (!Print(str, data)) return false;

	val = m_name + _T(" {") + str + _T("} ");
	if(m_back.attr)
	{
		val += _T('.') + m_back.attr->name;
		if(m_back.ent) val += _T("->") + m_back.ent->name;
	}
	return true;
}

bool CaplFinder_Impl::CExtVals::Print(CString &val, CaplFinder_Impl *data)
{
	return CaplFinder::CreateSqlExtent(*m_ext, NULL, val, NULL, NULL) > 0;
}

bool CaplFinder_Impl::CSubQueryExt::Print(CString &val, CaplFinder_Impl *data)
{
	CString str1;

	if (!m_grp.ToStr(str1, data)) return false;

	val = m_ent->name + _T("\n") + str1;

	return true;
}

bool CaplFinder_Impl::CRetItem::ToStr(CString &val, CaplFinder_Impl *data)
{
	val = (m_attr ? m_ext->m_name + _T('.') + m_attr->name : m_ext->m_name);
	return true;
}

//////////////////////////////////////////////////////////////////////////
// Поиск по локальному кэшу

void CaplFinder_Impl::FindLC(CaplStepData *data, aplExtent &ret)
{
	ret.Clear();
	int i, co = m_valsExts.size() + m_subExts.size();
	if(co < 1) return;
	aplExtent *subexts = new aplExtent[co]; // результаты всех подзапросов
	CExt *pExt;

	// получение результатов подзапросов
	listElIter iter = m_valsExts.begin();
	for(i = 0; i<co; ++i)
	{
		if (iter == m_valsExts.end())
			break;
		subexts[i].Unique = false;
		pExt = (*iter)->GetExt();
		pExt->m_extRet = subexts + i;
		pExt->FindLC(data, subexts[i]);
		++iter;
	}
	iter = m_subExts.begin();
	while (i<co)
	{
		subexts[i].Unique = false;
		pExt = (*iter)->GetExt();
		pExt->m_extRet = subexts + i;
		pExt->FindLC(data, subexts[i]);
		++iter;
		++i;
	}
	

	// получение результирующего экстента
	m_retGrp.CalcRetExt(ret);

	// обнулление указателей на результат у подзапросов
	for (iter = m_valsExts.begin(); iter != m_valsExts.end(); ++iter)
	{
		pExt = (*iter)->GetExt();
		pExt->ClearRE();
	}
	for (iter = m_subExts.begin(); iter != m_subExts.end(); ++iter)
	{
		pExt = (*iter)->GetExt();
		pExt->ClearRE();
	}


	delete[] subexts;
}

void CaplFinder_Impl::CExtVals::FindLC(CaplStepData *data, aplExtent &ret)
{
	ret.Append(*m_ext);
	std::sort(ret.Data, ret.Data + ret.Size);
	ret.Size = std::unique(ret.Data, ret.Data + ret.Size) - ret.Data;
}

void CaplFinder_Impl::CSubQueryExt::FindLC(CaplStepData *data, aplExtent &ret)
{
	ret.Clear();
	aplExtent eext;
	data->GetEntityExtent(m_ent, eext);
	int i, co = eext.GetSize();
	if(co == 0) return;
	CaplInstance *inst, *inst2;
	for (i = 0; i<co; ++i)
	{
		inst2 = inst = eext[i];
		if(!inst) continue;
		if(m_back.attr)
		{
			if(inst->GetAccessmode() > aplRO) continue;
			data->GetAttr(inst, m_back.attr, inst2);
			if(!inst2) continue;
			if(m_back.ent) if(!data->IsKindOf(inst2, m_back.ent)) continue;
		}
		if(m_grp.CheckItem(data, inst))  ret.Add(inst2);
	}
	
	std::sort(ret.Data, ret.Data + ret.Size);
	ret.Size = std::unique(ret.Data, ret.Data + ret.Size) - ret.Data;
}

bool CaplFinder_Impl::CSubQueryExt::CheckItem(CaplStepData *data, CaplInstance *inst)
{
	if(!inst) return false;
	if(!data->IsKindOf(inst, m_ent)) return false;
	return m_grp.CheckItem(data, inst);
}

bool CaplFinder_Impl::CAttrGroup::CheckItem(CaplStepData *data, CaplInstance *inst)
{
	listElIter iter = m_items.begin();
	if(iter == m_items.end()) return true;
	if(m_type == CaplFinder::grpAND)
	{
		while(iter != m_items.end())
		{
			if(!(*iter)->CheckItem(data, inst)) return false;
			++iter;
		}
	}
	else
	{
		while(iter != m_items.end())
		{
			if((*iter)->CheckItem(data, inst)) return true;
			++iter;
		}
	}
	return (m_type == CaplFinder::grpAND);
}

///
bool CaplFinder_Impl::CSelfInst::CheckItem(CaplStepData *data, CaplInstance *inst)
{
	return ((inst == m_val) == m_EqOrIn);
}

bool CaplFinder_Impl::CSelfExt::CheckItem(CaplStepData *data, CaplInstance *inst)
{
	int iSize = m_val->m_extRet->Size;
	CaplInstance** pExtRetData = m_val->m_extRet->Data;
	
	return (std::binary_search(pExtRetData, pExtRetData + iSize, inst) == m_EqOrIn);
}

bool CaplFinder_Impl::CEmptyAttr::CheckItem(CaplStepData *data, CaplInstance *inst)
{
	if (inst->GetAccessmode() > aplRO) return false;
	if (inst->attrs == NULL) return false;	// [18/8/2009 ZiloT] если атрибуты не зачитаны у инстанса, то пшел вон :)

	CaplValue val;
	data->GetAttr(inst, m_attr, val);
	
	switch(val.type)
	{
	case aplNOTYPE	 : return m_bNot; 
	case aplAGGR     : if(!val.aggrval) return m_bNot;
					   if(val.aggrval->GetSize() == 0) return m_bNot;
					   return !m_bNot;
	case aplENUMERATION :
	case aplSTRING   : if(!val.sval) return m_bNot;
					   if(!val.sval[0]) return m_bNot;
					   return !m_bNot;
	case aplSELECT   :
	case aplINSTANCE : return ((val.instval == NULL) == m_bNot);
	case aplBOOL :     return (val.bval != m_bNot);
	case aplREAL :     return ((val.rval == 0) == m_bNot);
	case aplINTEGER :  return ((val.ival == 0) == m_bNot);
	}
	return false;
}

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

bool CaplFinder_Impl::CStrAttr::CheckItem(CaplStepData *data, CaplInstance *inst)
{
	if(inst->GetAccessmode() > aplRO) return false;
	CString aVal;
	
	data->GetAttr(inst, m_attr, aVal);
	if ((m_cmpop == CaplFinder::cmpLike) || (m_cmpop == CaplFinder::cmpLikeLeft) || (m_cmpop == CaplFinder::cmpLikeRigth))
	{
		aVal.MakeUpper();
		m_val.MakeUpper();
	}
	int avLe = aVal.GetLength();
	int vLe = m_val.GetLength();
	bool bNotLike = (vLe > avLe);

	bool ret1;
	if(m_cmpop == CaplFinder::cmpLike)
		ret1 = (bNotLike ? false : aVal.Find(m_val) >= 0);
	else if(m_cmpop == CaplFinder::cmpLikeLeft)
		ret1 = (bNotLike ? false : _strncmp(m_val, aVal, vLe) == 0);
	else if(m_cmpop == CaplFinder::cmpLikeRigth)
		ret1 = (bNotLike ? false : _strncmp(m_val, ((LPCTSTR)aVal) + (avLe-vLe), vLe) == 0);
	else if(m_cmpop == CaplFinder::cmpEqual)
		ret1 = (aVal.Compare(m_val) == 0);
	else if(m_cmpop == CaplFinder::cmpIN)
		ret1 = ((avLe > vLe) ? false : m_val.Find(aVal) >= 0);
	else if(m_cmpop == CaplFinder::cmpLess)
		ret1 = (aVal.Compare(m_val) < 0);
	else if(m_cmpop == CaplFinder::cmpGreater)
		ret1 = (aVal.Compare(m_val) > 0);
	
	return (ret1 != m_bNot);
}

bool CaplFinder_Impl::CStrAttr::ToStr( CString &val, CaplFinder_Impl *data )
{
	TCHAR sQutes = _T('\'');

	// проверим, может сравниваемое значение уже содержит апостроф
	// если это так, то надо обрамлять не в одинарные кавычки, а в двойные!
	if (m_val.Find(_T('\'')) > -1)
	{
		sQutes = _T('"');
	}

	val = _T('.') + m_attr->name + GetOpName() + sQutes + m_val + sQutes;
	
	return true;
}
//////////////////////////////////////////////////////////////////////////

bool CaplFinder_Impl::CDoubleAttr::CheckItem(CaplStepData *data, CaplInstance *inst)
{
	if(inst->GetAccessmode() > aplRO) return false;
	double aVal;
	bool ret1 = false;

	data->GetAttr(inst, m_attr, aVal);

	if(m_cmpop == CaplFinder::cmpEqual)
		ret1 = (aVal == m_val);
	else if(m_cmpop == CaplFinder::cmpLess)
		ret1 = (aVal < m_val);
	else if(m_cmpop == CaplFinder::cmpGreater)
		ret1 = (aVal > m_val);
	
	return (ret1 != m_bNot);
}

bool CaplFinder_Impl::CBoolAttr::CheckItem(CaplStepData *data, CaplInstance *inst)
{
	if(inst->GetAccessmode() > aplRO) return false;
	bool aVal;
	data->GetAttr(inst, m_attr, aVal);
	return (aVal != m_bNot);
}

bool CaplFinder_Impl::CInstAttr::CheckItem(CaplStepData *data, CaplInstance *inst)
{
	if(inst->GetAccessmode() > aplRO) return false;
	if(m_cmpop == CaplFinder::cmpEqual)
	{
		CaplInstance *aValI;
		data->GetAttr(inst, m_attr, aValI);
		return ((aValI == m_val) != m_bNot);
	}
	else if(m_cmpop == CaplFinder::cmpLike)
	{
		aplExtent aValE;
		data->GetAttr(inst, m_attr, aValE);
		return ((aValE.Find(inst) >= 0) != m_bNot);
	}
	return false;
}

bool CaplFinder_Impl::CAttrAttr::CheckItem(CaplStepData *data, CaplInstance *inst)
{
	//произвольный атрибут, вроде никакой комбинации не забыл
	if(inst->GetAccessmode() > aplRO)
		return false;
	int i;
	bool ret1 = false;
	double dVal1, dVal2;
	int iVal1, iVal2;
	bool bVal1, bVal2;
	aplExtent aeExt1, aeExt2;
	CString sVal1,sVal2;
	CaplInstance* ciVal1,*ciVal2;
	if (m_val == m_attr)
		return !m_bNot;
	if (m_attr->type == aplREAL && m_val->type == aplREAL)
	{
		data->GetAttr(inst,m_attr,dVal1);
		data->GetAttr(inst,m_val,dVal2);
		if(m_cmpop == CaplFinder::cmpEqual)
			ret1 = (deq(dVal1, dVal2));
		else if(m_cmpop == CaplFinder::cmpLess)
			ret1 = (dVal1 < dVal2);
		else if(m_cmpop == CaplFinder::cmpGreater)
			ret1 = (dVal1 > dVal2);
		return ret1!=m_bNot;
	}
	if (m_attr->type == aplINTEGER &&  m_val->type == aplINTEGER)
	{
		data->GetAttr(inst,m_attr,iVal1);
		data->GetAttr(inst,m_val,iVal2);
		if(m_cmpop == CaplFinder::cmpEqual)
			ret1 = iVal1 == iVal2;
		else if(m_cmpop == CaplFinder::cmpLess)
			ret1 = (iVal1 < iVal2);
		else if(m_cmpop == CaplFinder::cmpGreater)
			ret1 = (iVal1 > iVal2);
		return ret1!=m_bNot;
	}
	if (m_attr->type == aplBOOL && m_val->type == aplBOOL)
	{
		data->GetAttr(inst,m_attr,bVal1);
		data->GetAttr(inst,m_val,bVal2);
		ret1 = bVal1 == bVal2;
		return ret1!=m_bNot;
	}
	if ((m_attr->type == aplINTEGER || m_attr->type == aplSELECT)&&(m_val->type == aplINTEGER || m_val->type == aplSELECT))
	{
		data->GetAttr(inst,m_attr,ciVal1);
		data->GetAttr(inst,m_val,ciVal2);
		ret1 = ciVal1 == ciVal2;
		return ret1!=m_bNot;
	}
	if ((m_attr->type == aplINSTANCE || m_attr->type == aplSELECT)&&(m_val->type == aplAGGR))
	{
		data->GetAttr(inst,m_attr,ciVal1);
		data->GetAttr(inst,m_val,aeExt2);
		if (m_cmpop == CaplFinder::cmpEqual)
		{
			if (aeExt2.Size == 1)
			{
				ret1 = ciVal1 == aeExt2[0];
			}
		}
		else
		{
			if (m_cmpop == CaplFinder::cmpLike)
			{
				if (aeExt2.Find(ciVal1) != -1)
					ret1 = true;
			}
		}
			return ret1!=m_bNot;
	}
	if ((m_val->type == aplINSTANCE || m_val->type == aplSELECT)&&(m_attr->type == aplAGGR))
	{
		data->GetAttr(inst,m_attr,aeExt1);
		data->GetAttr(inst,m_val,ciVal2);
		if (m_cmpop == CaplFinder::cmpEqual)
		{
			if (aeExt1.Size == 1)
			{
				ret1 = ciVal2 == aeExt1[0];
			}
		}
		else
		{
			if (m_cmpop == CaplFinder::cmpLike)
			{
				if (aeExt1.Find(ciVal2) != -1)
					ret1 = true;
			}
		}
			return ret1!=m_bNot;
	}
	if ((m_attr->type == aplAGGR)&&(m_val->type == aplAGGR))
	{
		data->GetAttr(inst,m_attr,aeExt1);
		data->GetAttr(inst,m_val,aeExt2);
		for (i = 0;i<aeExt1.Size;i++)
			aeExt2.Remove(aeExt2.Find(aeExt1[i]));
		if (m_cmpop == CaplFinder::cmpEqual)
			ret1 = (!aeExt1.Size&&!aeExt2.Size);
		if (m_cmpop == CaplFinder::cmpLike)
			ret1 = !aeExt1.Size;
		return ret1!=m_bNot;
	}
	if ((m_attr->type == aplSTRING)&&(m_val->type == aplSTRING))
	{
		data->GetAttr(inst,m_attr,sVal1);
		data->GetAttr(inst,m_val,sVal2);
		int avLe = sVal1.GetLength();
		int vLe = sVal2.GetLength();
		bool bNotLike = (vLe > avLe);
		if(m_cmpop == CaplFinder::cmpLike)
			ret1 = (bNotLike ? false : sVal1.Find(sVal2) >= 0);
		else if(m_cmpop == CaplFinder::cmpLikeLeft)
			ret1 = (bNotLike ? false : _strncmp(sVal2, sVal1, vLe) == 0);
		else if(m_cmpop == CaplFinder::cmpLikeRigth)
			ret1 = (bNotLike ? false : _strncmp(sVal2, ((LPCTSTR)sVal1) + (avLe-vLe), vLe) == 0);
		else if(m_cmpop == CaplFinder::cmpEqual)
			ret1 = (sVal1.Compare(sVal2) == 0);
		else if(m_cmpop == CaplFinder::cmpIN)
			ret1 = ((avLe > vLe) ? false : sVal2.Find(sVal1) >= 0);
		else if(m_cmpop == CaplFinder::cmpLess)
			ret1 = (sVal1.Compare(sVal2) < 0);
		else if(m_cmpop == CaplFinder::cmpGreater)
			ret1 = (sVal1.Compare(sVal2) > 0);

		return (ret1 != m_bNot);
	}
	return false;
}


aplExtent *CaplFinder_Impl::CRetItem::CalcRetExt(aplExtent &ret)
{
	if(!m_attr) return m_ext->m_extRet;
	ret.Clear();

	ret.SetSize(m_ext->m_extRet->GetSize());
	ret.Unique = false;
	CaplInstance *inst, *inst2;

	for (int i = 0; i<m_ext->m_extRet->GetSize(); i++)
	{
		inst = m_ext->m_extRet->GetAt(i);
		if(!inst) continue;
		if(!inst->GetType() || !inst->attrs) continue;
		if(inst->GetAccessmode()>aplRO) continue;
		inst->GetMyData()->GetAttr(inst, m_attr, inst2);
		if(!inst2) continue;
		ret.Add(inst2);
	}

	std::sort(ret.Data, ret.Data + ret.Size);
	ret.Size = std::unique(ret.Data, ret.Data + ret.Size) - ret.Data;

	return &ret;
}

void MakeUnion(aplExtent *ext1, aplExtent *ext2, aplExtent *res)
{
	if(0 == ext1 || 0 == ext2 || 0 == res)
		return;

	res->Clear();
	res->Append(*ext1);
	res->Append(*ext2);
	res->Normalize();	
}

void MakeIntersection(aplExtent *ext1, aplExtent *ext2, aplExtent *res)
{
	if(0 == ext1 || 0 == ext2 || 0 == res)
		return;

	res->Clear();
	for(int i = 0; i<ext1->Size; ++i)
	{
		CaplInstance *value = ext1->GetAt(i);

		if(-1 != ext2->Find(value))
			res->Add(value);												
	}

	res->Normalize();	
}

aplExtent *CaplFinder_Impl::CRetItemGroup::CalcRetExt(aplExtent &ret)
{
	ret.Clear();
	listElIter iter = m_items.begin();
	if(iter == m_items.end()) return &ret;
	ret.Unique = false;
	aplExtent we[2], ext1, *pExt1;

	aplExtent *pExt = (*iter)->CalcRetExt(we[0]);
	int k = 0, sz;
	int h = 0;

	for (++iter; iter != m_items.end(); ++iter)
	{
		k = k ^ 1; 
		pExt1 = (*iter)->CalcRetExt(ext1);
		if(m_type == CaplFinder::grpAND)
		{
			sz = ((pExt1->Size < pExt->Size) ? pExt1->Size : pExt->Size);
			we[k].Clear();
			if(aplExtent1::GetMaxSize(we[k]) < sz) 	we[k].SetSize(sz);

			MakeIntersection(pExt1, pExt, &we[k]);			
			if(we[k].Size == 0) 
				break;
		}
		else
		{
			sz = pExt1->Size + pExt->Size;
			if(aplExtent1::GetMaxSize(we[k]) < sz) 	we[k].SetSize(sz);

			MakeUnion(pExt1, pExt, &we[k]);						
		}
		pExt = we + k;
	}

	ret.Append(*pExt);
	return &ret;
}

void CaplFinder_Impl::InvertCMP(cmpOperation &op, bool &bNot)
{
	if(op <= CaplFinder::cmpGreater) return;
	int pos = ((int)op) - ((int)CaplFinder::cmpGreater) - 1;
	static cmpOperation arr[] = 
	{
		CaplFinder::cmpGreater, CaplFinder::cmpLess,
		CaplFinder::cmpEqual,	CaplFinder::cmpLike,
		CaplFinder::cmpLikeLeft,CaplFinder::cmpLikeRigth,
		CaplFinder::cmpNotIN
	};
	op = arr[pos];
	bNot = !bNot;
}


int CaplFinder_Impl::CElement::m_ExtNames = 0;


CString CaplFinder_Impl::ConvertIdToStr_Ora(long iId)
{
	CString sBuf;
	sBuf.Format(_T("a%06ld"),iId);
	return sBuf;
}

CString CaplFinder_Impl::GetTableNameByEntity(CaplEntity* pEnt)
{
	if (!pEnt)
		return _T("");
	int iTable  = -1;
	CString sBuf;
	iTable = pEnt->m_table_id;
	if(-1 == iTable) 
		iTable = m_data->GetTable4Entity(pEnt);
	if (-1 == iTable)
	{
		if (!m_miiEntTable.size())
		{
			FillEntTableMap(m_data);
		}
		iTable = GetTableByEntity(pEnt->id);
	}

	if (-1==iTable)
		return _T("");
	sBuf.Format(_T("e%06d"),iTable);
	return sBuf;
}

CString CaplFinder_Impl::GetEntWithChilds(CaplEntity* pEnt)
{
	if (!pEnt)
		return _T("(0)");
	int i;
	CaplEntity* pChildEnt;
	CString sBuf,sRes;
	sRes.Format(_T("%d"),pEnt->id);
	for (i = 0;i<pEnt->all_subtypes.Size;i++)
	{
		pChildEnt = pEnt->all_subtypes.GetAt(i);
		if (!pChildEnt)
			continue;
		sBuf.Format(_T("%d"),pChildEnt->id);
		sRes += _T(", ")+sBuf;
	}
	sRes = _T("(")+sRes+_T(")");
	return sRes;
}

void CaplFinder_Impl::CExt::SetName()
{
	m_name.Format(_T("pref%d"), m_ExtNames++);
}

CString &CaplFinder_Impl::CAttr::GetOpName_Ora()
{
	static CString arr[2][9] = { 
		{_T(" = "),  _T(" LIKE "),	  _T(" LIKE  "),     _T(" LIKE  "),     _T(" IN "),     _T(" < "),  _T(" > "),  _T(" <= "),  _T(" >= ")},
		{_T(" != "), _T(" NOT LIKE "), _T(" NOT LIKE  "), _T(" NOT LIKE  "), _T(" NOT IN "), _T(" >= "), _T(" <= "), _T(" > "),   _T(" < ")}
	};
	return arr[m_bNot ? 1 : 0][m_cmpop];
}

bool CaplFinder_Impl::FindDB_Ora(CaplNetStepData *data, aplExtent &ret, bool bDlg, bool bAttrs)
{
	m_data = data;
	CString sql;
	SaplSQLError oracle_error;
	
	if (!MakeSQLStr(data,sql, bAttrs)) 
		return false;

	data->NET_RunSqlReturnExtent(NULL, ret, &oracle_error, sql, m_mc.code1, m_mc.code2, APL_T("Поиск и загрузка данных..."),bAttrs,m_sSource);
	if (oracle_error.m_err_code)
	{
		CString str = APL_T("Запрос сформирован неверно\n");

		TRACE(str+sql);
		return FindDB(data,ret,bDlg,bAttrs);
	}
	return true;
}


CString CaplFinder_Impl::CAttrGroup::GetName_Ora(bool bTrim /*= false*/)
{
	if (m_ext->m_name.IsEmpty())
		m_ext->SetName();

	if (bTrim)
	{
		return m_ext->m_name;
	}

	return _T(" ")+m_ext->m_name;
}

int CaplFinder_Impl::GetTableByEntity(int iEnt)
{
	miiMapIt iter;

	iter = m_miiEntTable.find(iEnt);
	if (iter!=m_miiEntTable.end())
		return iter->second;
	return -1;
}
void CaplFinder_Impl::SetData(CaplNetStepData* data)
{
	m_data = data;
}
void CaplFinder_Impl::FillEntTableMap(CaplNetStepData* data)
{
	//загружаем весь список таблиц в которых находтся различные ентити
	SetData(data);
	if (m_miiEntTable.size())
	{
		return;
	}
	if (!m_data)
	{
		return;
	}
	int i;
	CString sSql = 
		_T("select distinct TO_NUMBER(extract(column_value, \'//a/text()\').getstringval()) v, t.id_table ")
		_T("from dispatchattrtotable t, ")
		_T("table(xmlsequence(extract(xmltype(\'<s><a>\' || replace(trim(both \',\' from t.entities), \',\',\'</a><a>\') || \'</a></s>\'), \'//s/*\')))");
	SaplSQLResult myVals[2];
	SaplSQLError err;
	myVals[0].type = aplINTEGER;
	myVals[1].type = aplINTEGER;
	data->NET_RunSql(sSql,myVals,2,&err,m_mc.code1,m_mc.code2, NULL, NULL, m_sSource);
	if (myVals[0].values.Size)
	{
		for (i = 0;i<myVals[0].values.Size;i++)
		{
			m_miiEntTable.insert(std::make_pair(myVals[0].values[i]->ival,myVals[1].values[i]->ival));
		}
	}
}

//////////////////////////////////////////////////////////////////////////
bool CaplFinder_Impl::CSelfInst::ToStr_Ora(CString &val, CaplFinder_Impl *data)
{
	static char strBuf[128];
	if(m_val== 0)return false;
	if(m_val->GetId()== 0) 
		return false;

	val = m_parent->GetName_Ora()+CString(m_EqOrIn ? _T(".instance_id = ") : _T(".instance_id != ")) + ( _itoa(m_val->GetId(), strBuf, 10) );
	return true;
}


//////////////////////////////////////////////////////////////////////////
bool CaplFinder_Impl::CSelfExt::ToStr_Ora(CString &val, CaplFinder_Impl *data)
{
	val = m_val->GetInsts(data,m_parent->GetName_Ora()+(m_EqOrIn ? _T(".instance_id IN ") : _T(".instance_id NOT IN ")));
	return true;
}


//////////////////////////////////////////////////////////////////////////
bool CaplFinder_Impl::CDoubleAttr::ToStr_Ora(CString &val, CaplFinder_Impl *data)
{
	if (m_val)
	{
		CString sBuf = Double2Str(m_val, 8);
		sBuf.Replace(_T('.'), _T(','));
		val.Format(_T("%s.%s%s%s"), m_parent->GetName_Ora(), ConvertIdToStr_Ora(m_attr->id), GetOpName_Ora(), sBuf);
	}
	else
	{
		if (m_bNot)
		{
			CString sAttr;
			sAttr.Format(_T("%s.%s"), m_parent->GetName_Ora(true), ConvertIdToStr_Ora(m_attr->id));
			val.Format(_T(" (%s %s 0 and %s is not null) "), sAttr, GetOpName_Ora(), sAttr);
		}
		else
		{
			CString sAttr;
			sAttr.Format(_T("%s.%s"), m_parent->GetName_Ora(true), ConvertIdToStr_Ora(m_attr->id));
			val.Format(_T(" (%s %s 0 or %s is null) "), sAttr, GetOpName_Ora(), sAttr);
		}
	}
	return true;
}

//////////////////////////////////////////////////////////////////////////
bool CaplFinder_Impl::CStrAttr::ToStr_Ora(CString &val, CaplFinder_Impl *data)
{
	CString sBuf = m_val;
	CString sLeft;
	CString sRight;
	if (m_val.IsEmpty()&&(m_cmpop == CaplFinder::cmpEqual||m_cmpop == CaplFinder::cmpNotEqual))
	{
		val = m_parent->GetName_Ora()+_T(".LENGTH_") + ConvertIdToStr_Ora(m_attr->id) +  GetOpName_Ora() + _T("0");
	}
	else
	{
		sLeft.Empty();
		sRight.Empty();
		if (m_cmpop == CaplFinder::cmpLike || m_cmpop == CaplFinder::cmpLikeRigth || m_cmpop == CaplFinder::cmpIN)
			sLeft =_T("\'%\'||");
		if (m_cmpop == CaplFinder::cmpLike || m_cmpop == CaplFinder::cmpLikeLeft || m_cmpop == CaplFinder::cmpIN)
			sRight = _T("||\'%\'");
		sBuf.Replace(_T("\'"),_T("\'\'"));
//		sBuf.Replace(_T("\""),_T("\"\"")); - DIV: лишняя замена. В SQL строки ограничиваются одинарными кавычками, экранировать надо только их
		if ((m_cmpop == CaplFinder::cmpLike) || (m_cmpop == CaplFinder::cmpLikeRigth) || (m_cmpop == CaplFinder::cmpLikeLeft))
		{
			val = _T(" UPPER(") + m_parent->GetName_Ora() + _T('.') + ConvertIdToStr_Ora(m_attr->id) + _T(") ") + GetOpName_Ora() +
				sLeft + _T("UPPER(\'") + sBuf + _T("\')") + sRight;
		}
		else
		{
			val = m_parent->GetName_Ora() + _T('.') + ConvertIdToStr_Ora(m_attr->id) + GetOpName_Ora() +
				sLeft + _T("\'") + sBuf + _T("\'") + sRight;
		}
	}
	return true;
}



//////////////////////////////////////////////////////////////////////////
bool CaplFinder_Impl::CBoolAttr::ToStr_Ora(CString &val, CaplFinder_Impl *data)
{
	if (m_bNot)
	{
		CString sAttr;
		sAttr.Format(_T("%s.%s"), m_parent->GetName_Ora(true), ConvertIdToStr_Ora(m_attr->id));
		val.Format(_T("(%s = 0 or %s is null) "), sAttr, sAttr);
	}
	else
	{
		val = m_parent->GetName_Ora() + _T('.') + ConvertIdToStr_Ora(m_attr->id) + _T(" = 1 ");
	}

	return true;
}



//////////////////////////////////////////////////////////////////////////
bool CaplFinder_Impl::CEmptyAttr::ToStr_Ora(CString &val, CaplFinder_Impl *data)
{
	switch(m_attr->type)
	{
	case aplAGGR     :
	{
		CString sOperation = m_bNot ? _T(" = ") : _T(" != ");
		val = m_parent->GetName_Ora() + _T(".") + ConvertIdToStr_Ora(m_attr->id) + sOperation + _T("\'NO Value\'");
		break;
	}
	case aplENUMERATION :
	case aplSTRING   : 
	{
		CString sOperation = m_bNot ? _T(" = ") : _T(" != ");
		val = m_parent->GetName_Ora() + _T(".LENGTH_") + ConvertIdToStr_Ora(m_attr->id) + sOperation + _T("0");
		break;
	}
	case aplSELECT   :
	case aplINSTANCE : 
	case aplBOOL:
	case aplREAL:
	case aplINTEGER:
		if (m_bNot)
		{
			CString sAttr;
			sAttr.Format(_T("%s.%s"), m_parent->GetName_Ora(true), ConvertIdToStr_Ora(m_attr->id));
			val.Format(_T(" (%s = 0 or %s is null) "), sAttr, sAttr);
		}
		else
		{
			CString sAttr;
			sAttr.Format(_T("%s.%s"), m_parent->GetName_Ora(true), ConvertIdToStr_Ora(m_attr->id));
			val.Format(_T(" (%s != 0 and %s is not null) "), sAttr, sAttr);
		}
		break;								
	default: 
		return false;
	}
	return true;
}
//////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
bool CaplFinder_Impl::CInstAttr::ToStr_Ora(CString &val, CaplFinder_Impl *data)
{
	static TCHAR strBuf[128];
	if (m_val && m_val->GetId() == 0) 
		return false;
	if (m_attr->type == aplSELECT || m_attr->type == aplINSTANCE)
	{
		if (m_val)
		{
			val = m_parent->GetName_Ora() + _T('.') + ConvertIdToStr_Ora(m_attr->id) + GetOpName_Ora() + _T(' ') + __itoa(m_val->GetId(), strBuf, 10);
		}
		else
		{
			if (m_bNot)
			{
				CString sAttr;
				sAttr.Format(_T("%s.%s"), m_parent->GetName_Ora(true), ConvertIdToStr_Ora(m_attr->id));
				val.Format(_T(" (%s %s 0 and %s is not null) "), sAttr, GetOpName_Ora(), sAttr);
			}
			else
			{
				CString sAttr;
				sAttr.Format(_T("%s.%s"), m_parent->GetName_Ora(true), ConvertIdToStr_Ora(m_attr->id));
				val.Format(_T(" (%s %s 0 or %s is null) "), sAttr, GetOpName_Ora(), sAttr);
			}
		}
	}
	if (m_attr->type == aplAGGR)
	{
		if (!m_val)
			val = m_parent->GetName_Ora()+_T('.') + ConvertIdToStr_Ora(m_attr->id) + (m_bNot? _T(" != ") : _T(" = ")) + _T("\'No Value\'"); 
		else
		{
			val = __itoa(m_val->GetId(), strBuf, 10) + CString(m_bNot? _T(" NOT IN ") : _T(" IN ")) + GetInsts(data,_T(""));
		}
	}
	return true;
}

//////////////////////////////////////////////////////////////////////////
bool CaplFinder_Impl::CAttrAttr::ToStr_Ora(CString &val, CaplFinder_Impl *data)
{
	CString sLeft;
	CString sRight;
	sLeft.Empty();
	sRight.Empty();
	if (m_cmpop == CaplFinder::cmpLike || m_cmpop == CaplFinder::cmpLikeLeft || m_cmpop == CaplFinder::cmpIN)
		sLeft = _T("\'%\'||");
	if (m_cmpop == CaplFinder::cmpLike || m_cmpop == CaplFinder::cmpLikeRigth || m_cmpop == CaplFinder::cmpIN)
		sRight = _T("||\'%\'");
	if ((m_attr->type == aplSELECT || m_attr->type == aplINSTANCE)&&(m_val->type == aplSELECT || m_val->type == aplINSTANCE))
		val = m_parent->GetName_Ora()+_T('.') + ConvertIdToStr_Ora(m_attr->id) + GetOpName_Ora() + m_parent->GetName_Ora()+_T('.') + ConvertIdToStr_Ora(m_val->id);
	else
		if ((m_attr->type == aplSTRING || m_val->type == aplSTRING)&&(m_attr->type == aplENUMERATION || m_val->type == aplENUMERATION))
			val = _T(" UPPER(")+m_parent->GetName_Ora()+_T('.') + ConvertIdToStr_Ora(m_attr->id)+ _T(") ") + GetOpName_Ora() +sLeft+ _T(" UPPER(")+m_parent->GetName_Ora()+_T('.') + ConvertIdToStr_Ora(m_val->id)+_T(") ")+sRight; 
		else
			if ((m_attr->type == aplBOOL && m_val->type == aplBOOL)||(m_attr->type == aplINTEGER && m_val->type == aplINTEGER)||(m_attr->type == aplREAL && m_val->type == aplREAL))
				val = m_parent->GetName_Ora()+_T('.') + ConvertIdToStr_Ora(m_attr->id) + GetOpName_Ora() + m_parent->GetName_Ora()+_T('.') + ConvertIdToStr_Ora(m_val->id);
			else
				if (m_attr->type == aplAGGR && (m_val->type == aplSELECT || m_val->type == aplINSTANCE))
					val = m_parent->GetName_Ora()+_T('.')+ ConvertIdToStr_Ora(m_val->id) + (m_bNot? _T(" IN "):_T(" NOT IN ")) + GetInsts(data,_T(""),m_attr) ;
				else
					if (m_val->type == aplAGGR && (m_attr->type == aplSELECT || m_attr->type == aplINSTANCE))
						val = m_parent->GetName_Ora()+_T('.')+ ConvertIdToStr_Ora(m_attr->id) + (m_bNot? _T(" IN "):_T(" NOT IN ")) + GetInsts(data,_T(""),m_val) ;
					else
						if (m_val->type == aplAGGR && m_attr->type == aplAGGR)
							val = GetInsts(data,_T(""),m_attr) + (m_bNot? _T(" IN "):_T(" NOT IN ")) + GetInsts(data,_T(""),m_val) ;
						else
							return false;
	return true;
}


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



bool CaplFinder_Impl::CExtVals::Print_Ora(CString &val, CaplFinder_Impl *data, CString sAttrName)
{
	return CaplFinder::CreatePlSqlExtent(*m_ext, val, sAttrName) > 0;
}

bool CaplFinder_Impl::CGroup::ToStr_Ora(CString &val, CaplFinder_Impl *data)
{
	if(m_items.size() == 0) 
		return true;
	if(m_items.size() == 1)	
		return m_items.front()->ToStr_Ora(val, data);
	CElement *cnd;
	listElIter iter;
	CRetItemGroup *rg = GetRG();
	CString str1;
	int co = 0;
	for (iter = m_items.begin(); iter != m_items.end(); ++iter)
	{
		cnd = *iter;
		if (!cnd->ToStr_Ora(str1, data)) 
			return false;
		if (co == 0)	val = str1;
		else			val += data->GetGrpTypeName(m_type) + (rg ? _T("") : _T("\n")) + str1;
		++co;
	}
	if (PrintSk(co))	val = _T('(') + val + _T(')');
	return (co > 0);
}

bool CaplFinder_Impl::CSubQueryExt::Print_Ora(CString &val, CaplFinder_Impl *data, CString sAttrName)
{
	if (!m_grp.ToStr_Ora(val, data)) 
		return false;
	return true;
}

bool CaplFinder_Impl::MakeSQLStr(CaplNetStepData* data, CString &str, bool bLoadAttrs)
{
	SetData(data);
	SetExtNames();
	CString s1, si;
	listElIter iter,iterElems;
	CExt *ext;

	forr (iter, m_retGrp.m_items)
	{
		ext = (CExt*)*iter;
		if (!ext->ToStr_Ora(si, this)) 
			return false;
		if (s1.IsEmpty())
			s1 = si + _T("\n");
		else
			if (m_retGrp.m_type == CaplFinder::grpOR)
				s1+=_T("union\n")+si+_T("\n");
			else
				s1+=_T("intersect\n")+si+_T("\n");

	}
	str = s1;
	return true;
}

bool CaplFinder_Impl::CExt::ToStr_Ora(CString &val, CaplFinder_Impl *data)
{
	val.Empty();
	if (!m_bIsRoot)
		return false;
	listElIter iter;
	CString str,sBuf,sChild;


	if (!Print_Ora(str, data, _T(""))) 
		return false;
	//получили строки с подгруппами
	CSubQueryExt* pExt = ((CSubQueryExt*)(this));
	//конечное условие


	if (!str.IsEmpty())
	{
		sBuf+=_T(" WHERE ")+str + _T(" AND ")+m_name+_T(".ENTITY_ID IN ") +data->GetEntWithChilds(pExt->m_ent);
	}					  
	else				  
		sBuf+=_T(" WHERE ")+m_name+_T(".ENTITY_ID IN ") +data->GetEntWithChilds(pExt->m_ent);

	sBuf = _T("SELECT ")+m_name+_T(".* FROM ")+ data->GetTableNameByEntity(pExt->m_ent)+_T(" ")+m_name+_T(" ") + sBuf;

	if (!m_back.attr)
	{
		sBuf = _T("SELECT ")+m_name+_T("X.INSTANCE_ID, ")+m_name+_T("X.ENTITY_ID, ")+m_name+_T("X.ACCESS_DEF, ")+m_name+_T("X.CHK_PERSONAL FROM (")+sBuf+_T(") ")+m_name+_T("X");
	}
	else
	{
		sBuf = _T("SELECT ")+m_name+_T("X.")+ConvertIdToStr_Ora(m_back.attr->id)+_T(" FROM (")+sBuf+_T(") ")+m_name+_T("X");
		if (m_back.ent)
		{
			sBuf = _T("SELECT ")+m_name+_T("B.INSTANCE_ID, ")+m_name+_T("B.ENTITY_ID, ")+m_name+_T("B.ACCESS_DEF, ")+m_name+_T("B.CHK_PERSONAL FROM ( ")+ sBuf +_T(") ") +m_name+_T("A LEFT JOIN ")
				+data->GetTableNameByEntity(m_back.ent)+_T(" ") + m_name+_T("B ON ")+ m_name+_T("B.INSTANCE_ID")+_T(" IN ")  +ConvertIdToStr_Ora(m_back.attr->id);
		}
		else
		{
			//Пробный вариант, может покатит - если не будет возвращать нормальный back_attr тада буду думать
			sBuf = _T("SELECT (")+m_name+_T("A.")+ConvertIdToStr_Ora(m_back.attr->id)+_T(") INSTANCE_ID, -1 ENTITY_ID, -1 ACCESS_DEF, -1 CHK_PERSONAL FROM ( ")+ sBuf +_T(") ") +m_name+_T("A ");
		}
	}
	val = sBuf;
	return true;
}


bool CaplFinder_Impl::CExtVals::ToStr_Ora(CString &val, CaplFinder_Impl *data)
{
	return false;
}



bool CaplFinder_Impl::CPathAttr::ToStr_Ora(CString &val, CaplFinder_Impl *data)
{
	CString str,sBuf;
	if(!m_val->Print_Ora(str, data,_T("")))
		return false;
	sBuf = _T("SELECT ")+m_val->m_grp.GetName_Ora()+_T(".INSTANCE_ID FROM ")+data->GetTableNameByEntity(m_val->m_grp.m_ext->m_ent)+_T(" ")+m_val->m_grp.GetName_Ora()
		+_T(" WHERE ")+m_val->m_grp.GetName_Ora()+_T(".ENTITY_ID  IN ") +data->GetEntWithChilds(m_val->m_grp.m_ext->m_ent) + ((!str.IsEmpty())? _T(" AND ( ")+str+_T(" )"):_T(""));

	val = m_parent->GetName_Ora()+_T('.') + ConvertIdToStr_Ora(m_attr->id) + _T(" IN (") + sBuf+_T(")");
	return true;
}

bool CaplFinder_Impl::CPathAttr::CheckItem(CaplStepData *data, CaplInstance *inst)
{
	if(inst->GetAccessmode() > aplRO) 
		return false;
	CaplInstance *aVal;
	data->GetAttr(inst, m_attr, aVal);
	return m_val->CheckItem(data, aVal);
}

bool CaplFinder_Impl::CRetItem::ToStr_Ora(CString &val, CaplFinder_Impl *data)
{
	CString sBuf,sRet;
	if(!m_ext->ToStr_Ora(sBuf,data))
		return false;
	if (!m_attr)
	{
		val = sBuf;
	}
	else
	{
		sRet = _T(" SELECT retpref.* FROM ") + data->GetTableNameByEntity(m_attr->entity) + _T(" retpref left join (")
			+sBuf+_T(") retsuff ON retsuff.INSTANCE_ID = retpref.INSTANCE_ID");

		sBuf = _T("SELECT (retprefA.")+ConvertIdToStr_Ora(m_attr->id)+_T(") INSTANCE_ID, -1 ENTITY_ID, -1 ACCESS_DEF, -1 CHK_PERSONAL FROM ( ")+ sRet +_T(") retprefA");

		val = sBuf;
	}
	return true;
}


CString CaplFinder_Impl::CInstAttr::GetInsts(CaplFinder_Impl *data, CString sAttrName, CaplAttr* attr /* = NULL*/)
{
	//здесь attr не учитывается
	CString sRet;
	sRet = _T("(select extract(column_value, \'//a/text()\') .getstringval() v ")
		_T("from ") + data->GetTableNameByEntity(m_parent->m_ext->m_ent) + _T(" t, ")
		_T("table(xmlsequence(extract(xmltype(\'<s><a>\' || ")
		_T(" replace(trim(both \',\' from ")
		_T("t.")+data->ConvertIdToStr_Ora(m_attr->id)+_T("),\',\',\'</a><a>\') || \'</a></s>\'), \'//s/*\'))) " )
		_T("where t.entity_id IN ")+data->GetEntWithChilds(m_parent->m_ext->m_ent)+_T(" and t.")+data->ConvertIdToStr_Ora(m_attr->id)+_T("<> \'NO Value\')");
	return sRet; 
}
CString CaplFinder_Impl::CAttrAttr::GetInsts(CaplFinder_Impl *data, CString sAttrName, CaplAttr* attr /* = NULL*/)
{
	//здесь attr учитывается
	if (!attr)
		attr = m_attr;
	CString sRet;
	sRet = _T("(select extract(column_value, \'//a/text()\') .getstringval() v ")
		_T("from ") + data->GetTableNameByEntity(m_parent->m_ext->m_ent) + _T(" t, ")
		_T("table(xmlsequence(extract(xmltype(\'<s><a>\' || ")
		_T(" replace(trim(both \',\' from ")
		_T("t.")+data->ConvertIdToStr_Ora(attr->id)+_T("),\',\',\'</a><a>\') || \'</a></s>\'), \'//s/*\'))) ") 
		_T("where t.entity_id IN ")+data->GetEntWithChilds(m_parent->m_ext->m_ent)+_T(" and t.")+data->ConvertIdToStr_Ora(attr->id)+_T("<> \'NO Value\')");
	return sRet; 

}

CString CaplFinder_Impl::CExt::GetInsts(CaplFinder_Impl *data, CString sAttrName, CaplAttr* attr /* = NULL*/)
{
	//здесь attr не учитывается
	CString sRet;
	if(!ToStr_Ora(sRet,data))
		return sAttrName + _T("(0)";)
	sRet = _T(" (select instance_id from (")+sRet+_T(")) ");
	sRet = sAttrName + sRet; 
	return sRet; 

}

/************************************************************************/
/*функции, которые надо поменять                                        */
/************************************************************************/


int CaplFinder::CreatePlSqlExtent(aplExtent &ext, CString &strExt, CString sAttrName)
{
	int i = 0, co = 0;
	CaplInstance *inst;
	if (sAttrName.IsEmpty())
	{
		int to = ext.GetSize();
		strExt.Empty();
		CString sq, s;


		for(; (i<to) && (co < ext.GetSize()); i++)
		{
			inst = ext[i];
			if(!inst)
				continue;
			if((inst->GetId() == 0) || !inst->GetType())
				continue;
			if(sq.IsEmpty())
				sq.Format(_T("%d"), inst->GetId());
			else
			{
				s.Format(_T(", %d"), inst->GetId()); 
				sq += s; 
			}
			++co;
		}
		if(co == 0) 
			return 0;
		strExt.Format(_T("select extract(column_value,\'//a/text()\').getstringval() INSTANCE_ID from ")
			_T("table(xmlsequence(extract(xmltype(\'<s><a>\'||replace( ")
			_T("\'%s\' ")
			_T(",\',\',\'</a><a>\')||\'</a></s>\'),\'//s/*\'))) "),sq);

		return co;
	}


	CString sLine;
	CString sBuf;
	CString sRet = _T("");
	bool bSplitted = false;

	sRet.Empty();
	sLine.Empty();
	for (i = 0;i<ext.Size;i++)
	{
		inst = ext[i];
		if(!inst)
			continue;
		if((inst->GetId() == 0) || !inst->GetType())
			continue;
		sBuf.Format(_T("%d"), inst->GetId());
		if (sLine.IsEmpty())
			sLine = sBuf;
		else
			sLine += _T(",")+sBuf;
		if (i&&!(i%500)||(i==ext.Size-1))
		{
			if (sRet.IsEmpty())
				sRet = sAttrName+_T(" (")+sLine+_T(") ");
			else
			{
				bSplitted = true;
				sRet += _T(" OR ") + sAttrName+_T(" (")+sLine+_T(") ");
			}
			sLine.Empty();

		}
		co++;
	}
	if (!sRet.IsEmpty()&&bSplitted)
	{
		sRet = _T(" (")+sRet+_T(") ");
	}
	return co;
}

int CaplFinder::AddConditionByAttrs( CaplEntity *entity, CaplAttr *attr, aplExtent &items )
{
	int index = CreateExt(entity, 0, 0, CaplFinder::grpOR);
	for(int i = 0; i<items.Size; ++i)
		AddAttr(index, attr, items[i], CaplFinder::cmpEqual);

	return index;
}

int CaplFinder::AddConditionBySearchResult( CaplEntity *entity, CaplAttr *attr, int index )
{
	int entityIndex = CreateExt(entity);
	AddAttr(entityIndex, attr, index);
	return entityIndex;
}

CString CaplFinder_Impl::CExtVals::GetInsts(CaplFinder_Impl *data, CString sAttrName, CaplAttr* attr /* = NULL*/)
{
	int i = 0;
	CString sLine;
	CString sBuf;
	CString sRet = _T("");
	CaplInstance *inst;
	if (!data)
		return sRet;
	if(!m_ext || !m_ext->Size)
		return sRet;
	bool bSplitted = false;
	if (m_ext)
	{
		sRet.Empty();
		sLine.Empty();
		for (i = 0;i<m_ext->Size;i++)
		{
			inst = m_ext->GetAt(i);
			if(!inst)
				continue;
			if((inst->GetId() == 0) || !inst->GetType())
				continue;

			sBuf.Format(_T("%d"), m_ext->GetAt(i)->GetId());
			if (sLine.IsEmpty())
				sLine = sBuf;
			else
				sLine += _T(",")+sBuf;
			if (i&&!(i%500)||(i==m_ext->Size-1))
			{
				if (sRet.IsEmpty())
					sRet = sAttrName+_T(" (")+sLine+_T(") ");
				else
				{
					bSplitted = true;
					sRet += _T(" OR ") + sAttrName+_T(" (")+sLine+_T(") ");
				}
				sLine.Empty();
			}
		}
		if (!sRet.IsEmpty()&&bSplitted)
		{
			sRet = _T(" (")+sRet+_T(") ");
		}
	}
	return sRet;
}
bool CaplFinder_Impl::CSelfInst::ToStr(CString &val, CaplFinder_Impl *data)
{
	static TCHAR strBuf[128];
	if(m_val== 0)return false;
	if(m_val->GetId()== 0) return false;
#if _MSC_VER >= 1400
	val = CString(m_EqOrIn ? _T(".# = #") : _T(".# != #")) + ( __itoa(m_val->GetId(), strBuf, 10));
#else													 
	val = CString(m_EqOrIn ? _T(".# = #)" : _T(".# != #")) + ( itoa(m_val->GetId(), strBuf, 10));
#endif
	return true;
}

bool CaplFinder_Impl::CSelfExt::ToStr(CString &val, CaplFinder_Impl *data)
{
	val = (m_EqOrIn ? _T(".# IN #") : _T(".# NOT_IN #")) + m_val->m_name;
	return true;
}

bool CaplFinder_Impl::CDoubleAttr::ToStr(CString &val, CaplFinder_Impl *data)
{
	val.Format(_T(".%s%s%g"), m_attr->name, GetOpName(), m_val);
	return true;
}

bool CaplFinder_Impl::CBoolAttr::ToStr(CString &val, CaplFinder_Impl *data)
{
	val = _T('.') + m_attr->name + _T(" = ") + (m_bNot ? _T("FALSE ") : _T("TRUE "));
	return true;
}

bool CaplFinder_Impl::CInstAttr::ToStr(CString &val, CaplFinder_Impl *data)
{
	static TCHAR strBuf[128];
	if (m_val && m_val->GetId() == 0) return false;
#if _MSC_VER >= 1400
	val = _T('.') + m_attr->name + GetOpName() +  _T('#') + (m_val ? __itoa(m_val->GetId(), strBuf, 10) : _T("0")); 
#else																											
	val = _T('.') + m_attr->name + GetOpName() +  _T('#') + (m_val ? itoa(m_val->GetId(), strBuf, 10) :  _T("0")); 
#endif
	return true;
}

//////////////////////////////////////////////////////////////////////////
CaplFinder_Impl::CExtAttr::CExtAttr( CAttrGroup* parent, CaplAttr *attr, cmpOperation cmpop, CExt *val, bool bNot, CaplEntity* aggrType /*= NULL*/ )
	: CAttr(parent, attr, cmpop, bNot)
	, m_val(val)
	, m_aggrType(aggrType)
{}

bool CaplFinder_Impl::CExtAttr::ToStr(CString &val, CaplFinder_Impl *data)
{
	if (!m_aggrType)
		val = _T('.') + m_attr->name + GetOpName() + _T('#') + m_val->m_name; 
	else			
	{				
		val = _T('.') + m_attr->name + _T("->") + m_aggrType->name + _T(".#") + GetOpName() + _T('#') + m_val->m_name;
	}

	return true;
}

bool CaplFinder_Impl::CExtAttr::ToStr_Ora(CString &val, CaplFinder_Impl *data)
{
	if (!m_aggrType)
	{
		val =  m_val->GetInsts(data,m_parent->GetName_Ora() + _T('.') + ConvertIdToStr_Ora(m_attr->id) + GetOpName_Ora()); 
		if(val.IsEmpty()) 
			return false;
	}
	else
	{
		CString sBufOp = GetOpName_Ora();
		if (sBufOp.CompareNoCase(_T("IN")) != 0)
		{
			sBufOp = _T(" INTERSECT ");
		}
		else
			sBufOp = _T(" EXCEPT ");
		val = _T("(select  to_number(extract(column_value, \'//a/text()\') .getstringval()) v ")
			_T("from ") + data->GetTableNameByEntity(m_attr->entity) + _T(" t, ")
			_T("table(xmlsequence(extract(xmltype(\'<s><a>\' || ")
			_T(" replace(trim(both \',\' from ")
			_T("t.")+data->ConvertIdToStr_Ora(m_attr->id)+_T("),\',\',\'</a><a>\') || \'</a></s>\'), \'//s/*\'))) " )
			_T("where t.entity_id IN ")+data->GetEntWithChilds(m_parent->m_ext->m_ent)+_T(" and t.")+data->ConvertIdToStr_Ora(m_attr->id)+_T("<> \'NO Value\')");
		val = _T(" (exists( ") + m_val->GetInsts(data,val + sBufOp+_T(" (select "))+_T(" from e000005 ))) "); 
	}
	return true;
}

bool CaplFinder_Impl::CExtAttr::CheckItem(CaplStepData *data, CaplInstance *inst)
{
	if (inst->GetAccessmode() > aplRO) return false;

	CaplInstance *aVal;
	data->GetAttr(inst, m_attr, aVal);
	if (!aVal) return false;

	int iSize = m_val->m_extRet->Size;
	CaplInstance** pExtRetData = m_val->m_extRet->Data;

	return (std::binary_search(pExtRetData, pExtRetData + iSize, aVal) != m_bNot);
}
//////////////////////////////////////////////////////////////////////////

bool CaplFinder_Impl::CPathAttr::ToStr(CString &val, CaplFinder_Impl *data)
{
	CString str;
	if(!m_val->Print(str, data)) return false;
	val = _T('.') + m_attr->name + _T("->") + str;
	return true;
}

bool CaplFinder_Impl::CAttrAttr::ToStr(CString &val, CaplFinder_Impl *data)
{
	val = _T('.') + m_attr->name + GetOpName() + _T('.') + m_val->name;
	return true;
}

void CaplFinder_Impl::CExt::ClearRE()
{
	m_extRet = NULL;
}


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

void CaplMagicCodes::GetNums()
{
	code1 = rand();	code2 = code1 ^ 0x7d24cf18; bC1 = 0;
}

CaplMagicCodes::operator int()
{
	if(bC1 == 2) GetNums();
	bC1++;
	return ((bC1 == 1) ? code1 : code2);
}

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

CaplResources::CaplResources(HINSTANCE hDll)
{
	hDllInst = hDll;
	hCurInst = NULL;
	bSet = false;
	Set();
}

CaplResources::~CaplResources()
{
	Reset();
};

void CaplResources::Set()
{
	if(bSet) return;
	hCurInst = AfxGetResourceHandle();
	AfxSetResourceHandle(hDllInst);
	bSet = true;
}

void CaplResources::Reset()
{
	if(!bSet) return;
	AfxSetResourceHandle(hCurInst);
	bSet = false;
}

