#ifndef UNITAZ_KAK_MESTO_DLYA_SRANYA______
#define UNITAZ_KAK_MESTO_DLYA_SRANYA______
#include "aplNetStepData.h"
#include <list>
#include <functional>
#include <math.h>

#define ACCURACY 0.0000001
#define deq(a,b) (fabs((a)-(b))<ACCURACY)
#define dneq(a,b) (fabs((a)-(b))>ACCURACY)

//если хочется вложить любое из выражений друг в друга - ставьте фигурные скобки
#define forr(it,ms) for((it)=(ms).begin();(it)!=(ms).end();++(it))
#define ifnend(it,ms,ke) if(((it)=(ms).find(ke))!=(ms).end())
#define ifend(it,ms,ke) if(((it)=(ms).find(ke))==(ms).end())
#define iffindinsertmap(it,ms,ke,pa) ifend(it,ms,ke)(it)=(ms).insert(std::make_pair((ke),(pa))).first;
#define iffindinsertreplacemap(it,ms,ke,pa) iffindinsertmap(it,ms,ke,pa)else(it)=(ms).insert(std::make_pair((ke),(pa))).first;
/**
вспомогательный класс для составления STEPQL запросов и/или поиска по кэшу.
Примеры использования см. в readme.txt данного проекта.
*/
class CaplFinder_Impl;


/** Строковый массив с дополнительными методами
*/
class AFX_EXT_CLASS CStringArrWithSort : public CStringArray
{
public:
	typedef int(*FNCMP)(const CString &, const CString &);
	typedef bool(*FNNEXTSTR)(CString &, DWORD);
	static int FnCmpNoCase(const CString &s1, const CString &s2){return s1.CompareNoCase(s2);}
	static int FnCmp(const CString &s1, const CString &s2){return s1.Compare(s2);}
protected:	
	class CLess{public:	FNCMP m_fn;	CLess(FNCMP fn){m_fn = fn;}
		bool operator()(const CString &s1, const CString &s2){return (m_fn(s1, s2) < 0);}};
	class CEq
	{public:	
		const CString *m_ps; FNCMP m_fn;	
		CEq(FNCMP fn, const CString &s):m_ps(&s) {m_fn = fn;}
		bool operator()(const CString &s1){return (m_fn(s1, *m_ps) == 0);}};
public:
	CStringArrWithSort(){}
	CStringArrWithSort(int nMax){SetSize(nMax);}
	void Sort(bool bMachCase = true);
	void Sort(FNCMP fnCmp);
	int Find(const CString &s, bool bMachCase = true);
	int Find(const CString &s, FNCMP fnCmp);
	int QFind(const CString &s, bool bMachCase = true);
	int QFind(const CString &s, FNCMP fnCmp);
	bool FindBreak(CString &ret, bool bMachCase, FNNEXTSTR fnNextStr, DWORD data = 0);
};

/**
карта long-aplExtent
*/
class AFX_EXT_CLASS CaplMapExt : public CaplMap
{
	bool m_bUnique;
public:
	void FreeExts(int nFrom = 0);
	static bool MatchAttrs(CaplInstance *inst, CaplAttrValue *av, int co);
	CaplMapExt(){m_bUnique = true;}
	CaplMapExt(int max_size):CaplMap(max_size){m_bUnique = true;}
	~CaplMapExt(){FreeExts();}
	
	/**
	Добавление комбинации
	@param bCopy - если true, то экстент копируется
	return позицию в массиве
	*/
	int  Add(long in, aplExtent *ext = NULL, bool bCopy = false);
	void AddToExtByIn(long in, CaplInstance *inst); // Добавление инстанса в экстент по входному значению(поиск перебором)
	void QAddToExtByIn(long in, CaplInstance *inst); // Добавление инстанса в экстент по входному значению(быстрый поиск)
	void AddToExt(int i, CaplInstance *inst); // Добавление инстанса в экстент по индексу
	
											  /**
											  создание карты из экстентов ключей и значений (распределение итемов
											  из extVals по экстентам, соответствующим тем или иным ключам)
											  @param attr - атрибут, которым итемы из extVals ссылаются 
											  на итемы из extKeys
	*/
	void Classify(aplExtent &extKeys, aplExtent &extVals, CaplAttr *attr);
	
	/**
	распределение итемов из extVals по заранее установленным ключам-инстансам.
	@param attr - атрибут, которым итемы из extVals ссылаются на ключи.
	@param bSortedIn - если true, то ключи считаются отсортированными
	и используется быстрый поиск
	*/
	void Classify(aplExtent &extVals, CaplAttr *attr, bool bSortedIn = true);
	
	void Classify(CaplMapExt &mapVals, CaplAttr *attr, bool bSortedIn = true);
	
	/**
	создание карты с ключами из extKeys и нулевыми значениями
	@param bSort - если true, то ключи будут отсортированы
	*/
	void SetKeys(aplExtent &extKeys, bool bSort = false);
	void Clear(); // очистка содержимого. все экстенты будут удалены из памяти
	void SetExtUnique(bool bUnc); // устанавливает параметр Unique вновь создаваемых экстентов
	void DetachAll(); //обнуляет все out значения. Это предотвращает удаление экстентов при очистке
	
					  /**
					  получает набор всех инстансов out-экстентов
					  @param bAllUnique - укажи true, если гарантируется уникальность всех инстансов
					  (будет работать быстрее)
	*/
	void GetOutExtent(aplExtent &outExt, bool bAllUnique);
	
	void RemoveAll(){FreeExts();CaplMap::RemoveAll();}
	bool Remove(int index);
	
	//	void MProjection(CaplAttrValue *av, int co, CaplMapExt &mp);
	void SProjection(CaplAttrValue *av, int co, CaplMap &mp);
	void QCreateSubSet(aplExtent &extKeys, CaplMapExt &mp, bool bCopy, bool bNN);
	
	void DeleteInstances(bool bDelKeys, bool bDelVals, aplExtent *extRec = NULL);
};

class AFX_EXT_CLASS CaplFinder
{
public:
	typedef int subQuery;
	typedef int retGroup;
	
	enum cmpOperation
	{
		cmpEqual,
		cmpLike,
		cmpLikeLeft,
		cmpLikeRigth,
		cmpIN,
		cmpLess,
		cmpGreater,
		cmpLessEqual,
		cmpGreaterEqual,
		cmpNotEqual,
		cmpNotLike,
		cmpNotLikeLeft,
		cmpNotLikeRigth,
		cmpNotIN
	};

	enum groupType
	{
		grpAND,
		grpOR
	};

	CaplFinder(const CString& _source/*используйте макрос DEF_SOURCE как параметр*/);
	~CaplFinder();

	void Clear();

	/**
	чисто конкретно непосредственно поиск
	@param bInBase - надо ли искать в базе
	@param bInCashe - надо ли искать в кэше
	*/
	bool Find(CaplNetStepData &data, bool bInBase, bool bInCashe, bool bDlg = false, bool bLoadAttrs = false, bool bOra = false);
	bool Find(CaplNetStepData *data, aplExtent &extRet, bool bInBase, bool bInCashe, bool bDlg = false, bool bLoadAttrs = false, bool bOra = false);
	bool Find(CaplNetStepData &data, aplExtent &extRet, bool bInBase, bool bInCashe, bool bDlg = false, bool bLoadAttrs = false, bool bOra = false);

	// упрощенная форма поиска по атрибутам. переменный параметр "std::pair<CaplAttr*, CaplInstance*> &attrVal"
	bool QuickFind(CaplNetStepData *data, bool bFromBase, int count, ...);

	// упрощенная форма поиска. вернуть все attr->entity, у которых attr == одному из items
	bool QuickFindByInstances(CaplNetStepData *data, aplExtent &items, CaplAttr *attr);

	// упрощенная форма поиска. вернуть все attr->entity, у которых attr == одному из values
	bool QuickFindByVecStr(CaplNetStepData *data, CStringArray &values, CaplAttr *attr);

	/**
	Создает STEPQL - строку по содержимому
	*/
	bool CreateQStr(CString &strQL, bool bLoadAttrs = false);
	bool CreateSQLStr(CaplNetStepData* data, CString &strQL, bool bLoadAttrs = false);

	/**
	Добавляет подзапрос
	@param entity - ентити
	@param endAttr - если не NULL, то аттр., который будет браться (т.н. конечный аттрибут)
	@param endEnt - ентити для конечного аттрибута
	@param grpType - групповая операция для условий (CaplFinder::grpAND или CaplFinder::grpOR)
	*/
	int CreateExt(CaplEntity *entity, CaplAttr *endAttr = NULL, CaplEntity *endEnt = NULL, groupType grpType = grpAND);
	
	/**
	Добавляет подзапрос, содержащий инстансы экстента ext (подзапрос вида ext{#3543, #7676 ...})
	@param bCopy - если true, то экстент копируется, иначе используется ссылка на переданный.
	*/
	int CreateExt(aplExtent &ext, bool bCopy);

	/**
	Вставляет группу аттрибутов в подзапрос
	@param ext - подзапрос
	@param grpType - групповая операция для условий
	*/
	int CreateGroup(int ext, groupType grpType);

	/**
	Создает подзапрос-аттрибут (аттрибут типа путь: attr->entity {...})
	@param ext - подзапрос или группа, в которую добавляется аттрбут
	@param attr - аттрибут
	@param entity - ентити
	@param grpType - групповая операция для условий
	*/
	int CreateAttrExt(int ext, CaplAttr *attr, CaplEntity *entity, groupType grpType = grpAND);

	/**
	Добавляет условие псевдоаттрибут ( .# )
	@param ext - подзапрос или группа, в которую добавляется условие
	@param val - значение, с котор. сравнивается значение аттрибута
	@param bEqual - если true, то используется операция =, иначе !=
	*/
	void AddSelf(int ext, CaplInstance *val, bool bEqual = false);

	/**
	Добавляет условие псевдоаттрибут ( .# )
	@param ext - подзапрос или группа, в которую добавляется условие
	@param val - подзапрос, вхождение в который проверяется
	@param bIn - если true, то IN, иначе NOT_IN
	*/
	void AddSelf(int ext, int val, bool bIn = true);

	/** Проверка на пустое значение аттрибута ("", NULL, 0, пустой аггр) 
	  @param bIsEmpty - если true, то проверяет на пустоту (если false, то не работает для аггров при поиске в БД)
	*/
	void AddAttrEmpty(int ext, CaplAttr *attr, bool bIsEmpty = true);

	/**
	Добавляет условие аттрибут (.attr)
	@param ext - подзапрос или группа, в которую добавляется условие
	@param attr - аттрибут
	@param strVal - значение, с котор. сравнивается значение аттрибута
	@param cmpop - операция сравнения (см. в CaplFinder)
	@param bNot - если true, то берется отрицание
	*/
	void AddAttr(int ext, CaplAttr *attr, LPCTSTR strVal, cmpOperation cmpop = cmpLike, bool bNot = false);
	void AddAttr(int ext, CaplAttr *attr, double val, cmpOperation cmpop = cmpEqual, bool bNot = false);
	void AddAttr(int ext, CaplAttr *attr, CaplInstance *val, cmpOperation cmpop = cmpEqual, bool bNot = false);

	/**
	Добавляет условие на булевский аттрибут
	@param ext - подзапрос или группа, в которую добавляется условие
	@param attr - аттрибут
	@param val - значение, с котор. сравнивается значение аттрибута (используется операция =)
	*/
	void AddAttr(int ext, CaplAttr *attr, bool val);

	/**
	Добавляет условие на инстансовый аттрибут
	@param ext - подзапрос или группа, в которую добавляется условие
	@param attr - аттрибут
	@param subExt - подзапрос, вхождение в который проверяется
	@param bIn - если true, то IN, иначе NOT_IN
	*/
	void AddAttr(int ext, CaplAttr *attr, int subExt, bool bIn = true);

	/**
	Добавляет условие на инстансовый аггровый аттрибут
	@param ext - подзапрос или группа, в которую добавляется условие
	@param attr - аттрибут
	@param subExt - подзапрос, вхождение в который проверяется
	@param aggrType - тип инстансов, которые могут содержаться в аггре
	@param bIn - если true, то IN, иначе NOT_IN
	*/
	void AddAggrAttr(int ext, CaplAttr* attr, int subExt, CaplEntity* aggrType, bool bIn = true);

	/**
	Добавляет условие на сравнение аттрибутов
	@param ext - подзапрос или группа, в которую добавляется условие
	@param attr - аттрибут
	@param val - подзапрос, вхождение в который проверяется
	@param cmpop - операция сравнения (см. в CaplFinder)
	@param bNot - если true, то берется отрицание
	*/
	void AddAttr(int ext, CaplAttr *attr, CaplAttr *val, cmpOperation cmpop, bool bNot = false);

	/**
	Добавляет запрос типа: найди все объекты, у которых атрибут равняется...
	entity - тип объекта, который ищем
	attr - атрибут, который используется лдя поиска
	value - значение атрибута
	*/
	template <class T>
	int AddConditionByAttr(CaplEntity *entity, CaplAttr *attr, T value)
	{
		int index = CreateExt(entity);
		AddAttr(index, attr, value, CaplFinder::cmpEqual);
		return index;
	}

	/**
	Добавляет запрос типа: найди все объекты, у которых атрибут равняется...
	entity - тип объекта, который ищем
	attr - атрибут, который используется лдя поиска
	items - варианты атрибута
	*/
	int AddConditionByAttrs(CaplEntity *entity, CaplAttr *attr, aplExtent &items);

	/**
	Добавляет запрос типа: найди все объекты, у которых атрибут равняется...
	entity - тип объекта, который ищем
	attr - атрибут, который используется лдя поиска
	index - результат какого-то предудыщего запроса
	*/
	int AddConditionBySearchResult(CaplEntity *entity, CaplAttr *attr, int index);
	
	/**
	@param grpType - групповая операция, устанавливаемая для группы
	*/
	CaplFinder &SetResultGrpType(groupType grpType);

	/**
	Добавляет элемент в результат
	@param grp - результирующая подгруппа, в котор. добавляется элемент
	@param ext - добавляемый элемент (подзапрос)
	@param attr - конечный аттрибут
	*/
	CaplFinder &AddToResult(int grp, int ext, CaplAttr *attr = NULL);
	CaplFinder &AddToResult(int ext, CaplAttr *attr = NULL);

	/**
	Создает результирующюю подгруппу
	@param grp - результирующая группа или подгруппа, в котор. добавляется новая подгруппа
	@param grpType - групповая операция
	*/
	int AddGrpToResult(int grp, groupType grpType);
	int AddGrpToResult(groupType grpType);


	/**
	Возвращает указатель на экстент у подзапроса типа ext{#3543, #7676 ...}
	*/
	aplExtent *GetExtValsExt(int ext);

	/**
	*/
	CaplEntity *GetEntity(int ext);

	/**
	*/
	bool IsExtent(int ext, bool bRoot = true);

	/**
	*/
	static bool sm_bCanCutQuery;
	static int CreateSqlExtent(aplExtent &ext, LPCTSTR name, CString &strExt, CString *sqIN, CString *sqNotIN, int maxLoad = -1, int *nFrom = NULL);
	static int CreatePlSqlExtent(aplExtent &ext, CString &strExt, CString sAttrName);
	static void SetCanCutQuery(bool bCutQuery);

public:
		
	aplExtent m_innerExtent;

private:
	CaplFinder_Impl *m_finder;
};

class AFX_EXT_CLASS CaplMagicCodes
{
	int bC1;
public:
	int code1, code2;
	CaplMagicCodes(){srand((unsigned)time(NULL));GetNums();}
	void GetNums(); 
	operator int();
};

class CaplFinder_Impl
{
public:

	//Максимальное количество инстансов в запросе
	static const int MAX_COUNT_OBJECTS_IN_QUERY = 300;

	CString m_sSource;
	bool m_bCanCutQuery;				//Можно разбить запрос на подзапросы

	CaplNetStepData* m_data;

	typedef CaplFinder::groupType		groupType;
	typedef CaplFinder::cmpOperation	cmpOperation;
	typedef CaplFinder::subQuery		subQuery;
	typedef CaplFinder::retGroup		retGroup;
	typedef std::map<int,int>			miiMap;
	typedef miiMap::iterator			miiMapIt;
	miiMap			m_miiEntTable;
	static bool FnCheckDeleted(DWORD api, CaplInstance *inst, DWORD d)
	{
		return (inst->GetType() == 0);
	}

	class aplExtent1 : public aplExtent
	{
	public:
		static int GetMaxSize(aplExtent &ext)
		{aplExtent1 *pExt1 = (aplExtent1 *)&ext;
			return pExt1->MaxSize;}
	};

	class CAttrEnt
	{
	public:
		CaplAttr *attr;	CaplEntity *ent;
		CAttrEnt(CaplAttr *a = NULL, CaplEntity *e = NULL):attr(a),ent(e)
		{
		}
	};

	static CString ConvertIdToStr_Ora(long iId);
	void Clear();
	void SetExtNames();
	CString &GetGrpTypeName(groupType gt);
	bool MakeQStr(CString &str, bool bLoadAttrs = false);
	bool MakeSQLStr(CaplNetStepData* data, CString &str, bool bLoadAttrs = false);

	void FindLC(CaplStepData *data, aplExtent &ret);
	bool FindDB(CaplNetStepData *data, aplExtent &ret, bool bDlg, bool bAttrs);
	bool FindDB_Ora(CaplNetStepData *data, aplExtent &ret, bool bDlg, bool bAttrs);

	static void InvertCMP(cmpOperation &op, bool &bNot);

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

	//////////////////////////////////////////////////////////////////////////
	class CExt;
	class CSubQueryExt;
	class CExtVals;
	class CAttrGroup;
	class CRetItemGroup;

	class CElement // базовый класс
	{
	public:
		static int m_ExtNames;
		CElement()
		{
		}
		virtual ~CElement()
		{
		}
		virtual bool ToStr(CString &val, CaplFinder_Impl *data)
		{
			return false;
		}
		virtual bool ToStr_Ora(CString &val, CaplFinder_Impl *data)
		{
			return false;
		}
		virtual CExt *GetExt()
		{
			return NULL;
		}
		virtual CExtVals *GetValsExt()
		{
			return NULL;
		}
		virtual CAttrGroup *GetAGrp()
		{
			return NULL;
		}
		virtual CRetItemGroup *GetRG()
		{
			return NULL;
		}
		virtual CSubQueryExt *GetSQ()
		{
			return NULL;
		}
		virtual bool CheckItem(CaplStepData *data, CaplInstance *inst)
		{
			return false;
		}
		virtual aplExtent *CalcRetExt(aplExtent &ret)
		{
			return NULL;
		}
		virtual CString GetInsts(CaplFinder_Impl *data, CString sAttrName, CaplAttr* attr = NULL)
		{
			AfxMessageBox(_T("Перегрузи функцию"));
			return _T("");
		}
		virtual CElement* GetInnerExtent()
		{
			return NULL;
		}
	};
	
	typedef std::list<CElement *>		listElements;
	typedef listElements::iterator		listElIter;
	typedef std::vector<CElement *>		vectElements;


	class CExt : public CElement  // Базовый класс для подзапроса
	{
	public:
		aplExtent *m_extRet;
		CString m_name;
		bool m_bIsRoot;
		CAttrEnt m_back;
		CExt():m_bIsRoot(true)
		{
			ClearRE();
		}
		virtual ~CExt()
		{
		}
		void SetName();
		virtual bool Print(CString &val, CaplFinder_Impl *data) 
		{
			return true;
		}
		bool ToStr_Ora(CString &val, CaplFinder_Impl *data);
		bool ToStr(CString &val, CaplFinder_Impl *data);
		virtual bool Print_Ora(CString &val, CaplFinder_Impl *data, CString sAttrName) 
		{
			return true;
		}
		CExt *GetExt()
		{
			return this;
		}
		void ClearRE();
		virtual void FindLC(CaplStepData *data, aplExtent &ret)
		{
		}
		virtual CString GetInsts(CaplFinder_Impl *data, CString sAttrName, CaplAttr* attr = NULL);
	};

	class CGroup : public CElement // Группа аттрибутов или возвр. подзапросов
	{
	public:
		groupType m_type;
		CGroup *m_parent;
		listElements m_items;
		void Clear();
		CGroup(CGroup *parent, groupType grpType):m_type(grpType),m_parent(parent)
		{
		}
		~CGroup()
		{
			Clear();
		}
		bool ToStr_Ora(CString &val, CaplFinder_Impl *data);
		bool ToStr(CString &val, CaplFinder_Impl *data);
		virtual bool PrintSk(int co){return true;}
	};

	class CAttrGroup : public CGroup
	{
	public:
		CSubQueryExt *m_ext;
		CAttrGroup(CGroup *parent = NULL, groupType grt = CaplFinder::grpAND):CGroup(parent, grt),m_ext(NULL)
		{
		}
		CAttrGroup *GetAGrp()
		{
			return this;
		}
		bool PrintSk(int co);
		bool CheckItem(CaplStepData *data, CaplInstance *inst);
		CString GetName_Ora(bool bTrim=false);
	};

	class CSelf : public CElement  // псевдоаттрибут #
	{
	public:	
		CAttrGroup* m_parent;
		CSelf(CAttrGroup* parent, bool bEq):m_parent(parent),m_EqOrIn(bEq)
		{
		}
		bool m_EqOrIn;
	};

	class CSelfInst : public CSelf
	{
	public:
		CaplInstance *m_val;
		CSelfInst(CAttrGroup* parent, bool bEq, CaplInstance *val):CSelf(parent,bEq),m_val(val)
		{
		}
		bool ToStr_Ora(CString &val, CaplFinder_Impl *data);
		bool ToStr(CString &val, CaplFinder_Impl *data);
		bool CheckItem(CaplStepData *data, CaplInstance *inst);
	};

	class CSelfExt : public CSelf
	{
	public:
		CExt *m_val;
		CSelfExt(CAttrGroup* parent, bool bIn, CExt *ext):CSelf(parent,bIn),m_val(ext)
		{
		}
		bool ToStr_Ora(CString &val, CaplFinder_Impl *data);
		bool ToStr(CString &val, CaplFinder_Impl *data);
		bool CheckItem(CaplStepData *data, CaplInstance *inst);
	};

	class CAttr : public CElement  // аттрибут
	{
	public:
		CAttrGroup* m_parent;
		CaplAttr *m_attr;
		cmpOperation m_cmpop;
		bool m_bNot;
		CAttr(CAttrGroup* parent, CaplAttr *attr, cmpOperation cmpop, bool bNot):m_attr(attr),m_cmpop(cmpop),m_bNot(bNot),m_parent(parent)
		{
			CaplFinder_Impl::InvertCMP(m_cmpop, m_bNot);
		}

		CString &GetOpName_Ora();
		CString &GetOpName();
	};

	class CEmptyAttr : public CAttr
	{
	public:
		CEmptyAttr(CAttrGroup* parent, CaplAttr *attr, bool bIsEmpty):CAttr(parent, attr, CaplFinder::cmpEqual, bIsEmpty)
		{
		}
		bool ToStr_Ora(CString &val, CaplFinder_Impl *data);
		bool ToStr(CString &val, CaplFinder_Impl *data);
		bool CheckItem(CaplStepData *data, CaplInstance *inst);
	};
	class CStrAttr : public CAttr
	{
	public:
		CString m_val;
		CStrAttr(CAttrGroup* parent, CaplAttr *attr, cmpOperation cmpop, LPCTSTR val, bool bNot):CAttr(parent, attr, cmpop, bNot), m_val(val)
		{
		}
		bool ToStr_Ora(CString &val, CaplFinder_Impl *data);
		bool ToStr(CString &val, CaplFinder_Impl *data);
		bool CheckItem(CaplStepData *data, CaplInstance *inst);
	};
	class CDoubleAttr : public CAttr
	{
	public:
		double m_val;
		CDoubleAttr(CAttrGroup* parent, CaplAttr *attr, cmpOperation cmpop, double val, bool bNot):CAttr(parent, attr, cmpop, bNot), m_val(val)
		{
		}
		bool ToStr_Ora(CString &val, CaplFinder_Impl *data);
		bool ToStr(CString &val, CaplFinder_Impl *data);
		bool CheckItem(CaplStepData *data, CaplInstance *inst);
	};
	class CBoolAttr : public CAttr
	{
	public:
		CBoolAttr(CAttrGroup* parent, CaplAttr *attr, bool val):CAttr(parent, attr, CaplFinder::cmpEqual, !val){}
		bool ToStr_Ora(CString &val, CaplFinder_Impl *data);
		bool ToStr(CString &val, CaplFinder_Impl *data);
		bool CheckItem(CaplStepData *data, CaplInstance *inst);
	};
	class CInstAttr : public CAttr
	{
	public:
		CaplInstance *m_val;
		CInstAttr(CAttrGroup* parent, CaplAttr *attr, cmpOperation cmpop, CaplInstance *val, bool bNot):CAttr(parent, attr, cmpop, bNot), m_val(val){}
		bool ToStr_Ora(CString &val, CaplFinder_Impl *data);
		bool ToStr(CString &val, CaplFinder_Impl *data);
		bool CheckItem(CaplStepData *data, CaplInstance *inst);
		virtual CString GetInsts(CaplFinder_Impl *data, CString sAttrName, CaplAttr* attr = NULL);
	};

	class CExtAttr : public CAttr
	{
	public:

		/** @info
				aggrType -	используется только для аггрового атрибута 
							(это тип инстансов, которые могут содержаться в аггре)
		*/
		CExtAttr(CAttrGroup* parent, CaplAttr *attr, cmpOperation cmpop, CExt *val, bool bNot, CaplEntity* aggrType = NULL);

		virtual bool ToStr_Ora(CString &val, CaplFinder_Impl *data) override;
		virtual bool ToStr(CString &val, CaplFinder_Impl *data) override;
		virtual bool CheckItem(CaplStepData *data, CaplInstance *inst) override;
		virtual CElement* GetInnerExtent() override
		{
			return m_val;
		}

	protected:

		CExt *m_val;
		CaplEntity* m_aggrType;
	};

	class CPathAttr : public CAttr
	{
	public:
		CSubQueryExt *m_val;
		CPathAttr(CAttrGroup* parent, CaplAttr *attr, CSubQueryExt *path):CAttr(parent, attr, CaplFinder::cmpIN, false), m_val(path)
		{
		}
		~CPathAttr()
		{
			delete m_val;
		}
		bool ToStr_Ora(CString &val, CaplFinder_Impl *data);
		bool ToStr(CString &val, CaplFinder_Impl *data);
		bool CheckItem(CaplStepData *data, CaplInstance *inst);
	};
	class CAttrAttr : public CAttr
	{
	public:
		CaplAttr *m_val;
		CAttrAttr(CAttrGroup* parent, CaplAttr *attr, cmpOperation cmpop, CaplAttr *val, bool bNot):CAttr(parent, attr, cmpop, bNot),m_val(val)
		{
		}
		bool ToStr_Ora(CString &val, CaplFinder_Impl *data);
		bool ToStr(CString &val, CaplFinder_Impl *data);
		bool CheckItem(CaplStepData *data, CaplInstance *inst);
		virtual CString GetInsts(CaplFinder_Impl *data, CString sAttrName, CaplAttr* attr = NULL);
	};

	class CExtVals : public CExt
	{
	public:
		aplExtent *m_ext;
		bool m_bCopy;
		CExtVals(aplExtent &ext, bool bCopy);
		~CExtVals()
		{
			if(m_bCopy && m_ext) 
				delete m_ext;
		}
		bool Print(CString &val, CaplFinder_Impl *data);
		bool Print_Ora(CString &val, CaplFinder_Impl *data, CString sAttrName);
		CExtVals *GetValsExt()
		{
			return this;
		}
		void FindLC(CaplStepData *data, aplExtent &ret);
		virtual CString GetInsts(CaplFinder_Impl *data, CString sAttrName, CaplAttr* attr = NULL);
		bool ToStr_Ora(CString &val, CaplFinder_Impl *data);
	};

	class CSubQueryExt : public CExt
	{
	public:
		CaplEntity *m_ent;
		CAttrGroup m_grp;
		CSubQueryExt(CaplEntity *ent, groupType grpType):m_grp(NULL, grpType)
		{
			m_ent = ent;
			m_grp.m_ext = this;
		}
		bool Print_Ora(CString &val, CaplFinder_Impl *data, CString sAttrName);
		bool Print(CString &val, CaplFinder_Impl *data);
		CAttrGroup *GetAGrp()
		{
			return &m_grp;
		}
		CSubQueryExt *GetSQ()
		{
			return this;
		}
		void FindLC(CaplStepData *data, aplExtent &ret);
		bool CheckItem(CaplStepData *data, CaplInstance *inst);
	};

	class CRetItem : public CElement
	{
	public:
		CExt *m_ext;
		CaplAttr *m_attr;
		CRetItem(CExt *ext, CaplAttr *attr):m_ext(ext), m_attr(attr)
		{
		}
		bool ToStr_Ora(CString &val, CaplFinder_Impl *data);
		bool ToStr(CString &val, CaplFinder_Impl *data);
		aplExtent *CalcRetExt(aplExtent &ret);
	};

	class CRetItemGroup : public CGroup
	{
	public:
		CRetItemGroup(CGroup *parent = NULL, groupType grt = CaplFinder::grpAND):CGroup(parent, grt)
		{
		}
		CRetItemGroup *GetRG()
		{
			return this;
		}
		bool PrintSk(int co);
		aplExtent *CalcRetExt(aplExtent &ret);
	};

	typedef std::multimap<int, CElement*, std::greater<int>>			mapCountElement;
	typedef std::multimap<int, CElement*, std::greater<int>>::iterator	itMapCountElement;

	//Если запрос большой и возможно его разбить на несколько подзапросов, то Функция возвращает true и пераметры pTargetGroupOut - группа для разбиения, iPartSizeOut - размер части
	bool NeedCutQueryGroup(CElement*& pTargetGroupOut, int& iPartSizeOut);
	int FillElementCount(CElement* pElem, mapCountElement& mapElemCntOut);

	void AddItemToRG(CRetItemGroup *pGrp, int ext, CaplAttr *attr);
	int AddGrpToRG(CRetItemGroup *pGrp, groupType grt);
	CExt *GetExtByExt(subQuery ext);
	CExtVals *GetValsExt(subQuery ext);
	CAttrGroup *GetAGrpByExt(subQuery ext);
	CRetItemGroup *GetRGByExt(retGroup ext);
	int GetNextId(CElement *el);
	void Init();
	void FillEntTableMap(CaplNetStepData* data);
	void SetData(CaplNetStepData* data);
	int GetTableByEntity(int iEnt);
	CString GetTableNameByEntity(CaplEntity* pEnt);
	CString GetEntWithChilds(CaplEntity* pEnt);
	listElements	m_valsExts; // список всех {#123} экстентов
	listElements	m_subExts;  // список всех именованных подзапросов
	vectElements	m_allElements; 
	CRetItemGroup	m_retGrp;
	CaplMagicCodes	m_mc;
	int m_rgi;
};

/** различные постоянные строки */
class AFX_EXT_CLASS CaplStrConst
{
public:
	// строковые постоянные
	class AFX_EXT_CLASS SProcStates 
	{public:
	CString initiated;
	CString running;
	CString suspended;
	CString completed;
	CString terminated;
	SProcStates():initiated(_T("initiated")),running(_T("running")),
		suspended(_T("suspended")),completed(_T("completed")),terminated(_T("terminated")){}
	};
	class AFX_EXT_CLASS SChngStates 
	{public:
	CString create;
	CString applied;
	CString approval;
	CString modification;
	CString canceled;
	CString not_applied;
	CString approving;
	SChngStates():create(_T("create")),applied(_T("applied")),approval(_T("approval")),
		modification(_T("modification")),canceled(_T("canceled")),not_applied(_T("not_applied")),approving(_T("approving")){}
	};
	class AFX_EXT_CLASS SPdfStates 
	{public:
	CString working;
	CString released;
	CString approved;
	CString approving;
	CString changing;
	CString approving_change;
	CString canceled;
	CString submitted;
	SPdfStates():working(_T("working")),released(_T("released")),approved(_T("approved")),
		approving(_T("approving")),changing(_T("changing")),approving_change(_T("approving_change")),
		canceled(_T("canceled")),submitted(_T("submitted")){}
	};
	class AFX_EXT_CLASS STaskStates 
	{public:
	CString inactive;
	CString send;
	CString active;
	CString suspend;
	CString complete;
	CString cancel;
	STaskStates():inactive(_T("inactive")),send(_T("send")),active(_T("active")),
		suspend(_T("suspend")),complete(_T("complete")),cancel(_T("cancel")){}
	};
	class AFX_EXT_CLASS SPdfTypes 
	{public:
	CString part;
	CString komplex;
	CString kit;
	CString material;
	CString assembly;
	CString zone;
	CString system;
	CString module;
	SPdfTypes():part(_T("part")),komplex(_T("komplex")),kit(_T("kit")),
		material(_T("material")),assembly(_T("assembly")),zone(_T("zone")),
		system(_T("system")),module(_T("module")){}
	};
	class AFX_EXT_CLASS SPdfSrcs 
	{public:
	CString made;
	CString not_known;
	CString coproduction;
	CString bought;
	SPdfSrcs():made(_T("made")),not_known(_T("not_known")),coproduction(_T("coproduction")),
		bought(_T("bought")){}
	};
};

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

/** Класс для установки ресурсов диалога */
class AFX_EXT_CLASS CaplResources
{
protected:
	HINSTANCE	hCurInst;
	HINSTANCE   hDllInst;
	bool bSet;
public:
	CaplResources(HINSTANCE hDll);
	virtual ~CaplResources();
	void Set();
	void Reset();
};

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

/** для временной установки admin-mode */
class CaplAdminMode
{
public:
	CaplAdminMode(CaplNetStepData *data, bool bSetAdminMode, LPCTSTR src) :
		m_provider(data, -1, -1, src)
	{		
	}

	CaplAdminMode(CaplNetStepData &data, bool bSetAdminMode, LPCTSTR src) :
		m_provider(&data, -1, -1, src)
	{		
	}

	~CaplAdminMode()
	{		
	}

	CaplAdminModeProvider m_provider;
};

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

/** для смены значения переменной и автоматического возврата его при выходе */
template <class T>
class CaplSavePrevValue
{
public:

	template <class T>
	CaplSavePrevValue(T &property, T newValue) : m_property(property)
	{
		m_oldValue = property;
		m_property = newValue;
	}

	~CaplSavePrevValue(void)
	{
		m_property = m_oldValue;
	}

protected:

	T &m_property;
	T m_oldValue;
};

#endif