// StepData.h

// 1.2.0.1
// 1.3.0.0  / 05.10.2000 Изменена схема работы с удаленными (избавились  от killed_instances)
// 1.4.0.0  / 26.11.2000 Добавлены функции в СaplAggr
//						 Добавлены функции в CaplStepData
// 1.5.0.0  / 03.01.2001 Новый формат словаря
//                       Проверка типов Instance ри их записи
// 1.6.0.0  / 30.04.2001 CaplFictiveStepData
//                       CaplQLQuery
// 1.7.0.0  / 27.09.2001 FreeInstancesAttr
//                       Переделка на постоянную сортировку Inst по ID
// 1.7.0.1  / 26.11.2002 Более точная диагностика ошибки откп\рытия файла

#pragma once

#ifndef STEPDATA_H
#define STEPDATA_H



#ifdef INHERIT_FROM_QOBJECT  // Это, если используется QML
	#include <QObject>
	#include <QThreadStorage>
    #define APL_DEF_Q_OBJECT Q_OBJECT
	#define APL_INHERIT_FROM_Q_OBJECT   : public QObject
#else
	#define APL_DEF_Q_OBJECT
	#define APL_INHERIT_FROM_Q_OBJECT 
#endif

#include <map>

#ifdef _MFC_VER
	#ifndef APL_STEPDATA_NOAUTOLIB
	#ifdef _DEBUG
	#ifdef _UNICODE
	#pragma comment (lib,"CaplData_ud.lib")
	#else
	#pragma comment (lib,"CaplDataD.lib")
	#endif
	#else
	#ifdef _UNICODE
	#pragma comment (lib,"CaplData_u.lib")
	#else
	#pragma comment (lib,"CaplData.lib")
	#endif
	#endif
	#endif
#endif
/** \mainpage PSS API Документация

<h2>&nbsp;&nbsp;Базовый класс API для Visual C++</h2>
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CaplAPI - класс объединяющий всю обработку данных<br>
<h2>&nbsp;&nbsp;Основные классы API для Visual C++</h2>
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CaplStepData - класс работы с данными<p>
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CaplNetStepData - класс работы с данными по сети<p>
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CaplStepManager	- менеджеры информации<p><br>

	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CaplInstance - класс представляющий Instance<p>
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CaplValue - класс представляющий значение любого тиа (аналог VARIANT)<br>
<h2>&nbsp;&nbsp;Вспомогательные классы API для Visual C++</h2>
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CaplLoadData - класс для загрузки в кэш цепочек данных<p>
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CaplTAggr - шаблон для работы со списками (аналог CArray)<br> 
<h2>&nbsp;&nbsp;Служебные классы API для Visual C++</h2>
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CaplMap - класс работы с картами int-int<p>
	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CaplStrMap - класс работы с картами string-int<p><br>

	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CaplStrStrMap - класс работы с картами string-string<p><br>

	&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CaplCSV - Класс для чтения файлов csv<p>
*/

#include "StdAfx.h"
#include <aplAggr.h>
#include "aplValue.h"

#define APLAPIERR_NOERROR 0
//#define APLAPIERR_BADINPUTDATA 1
#define APLAPIERR_NODATA 2
#define APLAPIERR_BADTYPE 3
#define APLAPIERR_FILE_IO 4
#define APLAPIERR_BADDICTIONARY 5
#define APLAPIERR_BADENT 6
#define APLAPIERR_BADATTR 7
#define APLAPIERR_BADDATA 8
#define APLAPIERR_ATTRNSET 9
#define APLAPIERR_BADFILENAME 10
#define APLAPIERR_BADINSTANCE 11
#define APLAPIERR_BADINSTANCETYPE 12
#define APLAPIERR_BADSCHEMANAME 13
#define APLAPIERR_NOACCESSRIGHT 14
#define APLAPIERR_BADDICTVERSION 15
#define APLAPIERR_INVALIDDATAFORMAT 16
#define APLAPIERR_INCOMPATIBLEDICT 17
#define APLAPIERR_FICTIVE_DATA 18
#define APLAPIERR_QUERY_ERROR 19
#define APLAPIERR_DICT_FILE_NOT_OPEN 20
#define APLAPIERR_BADDATA_INVALID_ENTINY_ID 21
#define APLAPIERR_BADDATA_INVALID_ATTR_ID 22
#define APLAPIERR_FILE_BD_NOT_FOUND 23
#define APLAPIERR_FILE_BD_READ_ONLY 24
#define APLAPIERR_MODE_READ_ONLY 25
#define APLAPIERR_INCOMPATIBLDATAFORMAT 26
#define APLAPIERR_OUT_OF_MEMORY 27
#define APLAPIERR_UNKNOWN_EXEPTION 28
#define APLAPIERR_UNCORRECT_STATE 29

/** Размерность хеша по умолчанию для функций расчета по алгоритму «Стрибог» по ГОСТ 34.11—2012*/
#define DEFAULT_HASH_SIZE 512


/** формат файла */
enum aplFileSaveMode{	aplBIN, /**<  двоичный*/
						aplTEXT,/**<  текстовый*/
						aplSTEP /**<  обменный (ISO 10303-21)*/
};

/** формат привязки строк в поиске */
enum aplStringBindMode{	aplSBLeft, /**<  строка должна быть слева*/
						aplSBMiddle, /**<  строка может быть в любом месте*/
						aplSBRight /**<  строка должна быть справа*/
};

class CaplInstance;
class CaplEntity;
class CaplAttr;
class CaplAttrValue;
class CaplValue;
class aplP21Header;
class CaplStepData;

typedef std::map<CaplInstance*, UINT32>	TInstIntMap;
typedef TInstIntMap::iterator			TInstIntMap_it;

typedef CaplTAggr <apl_id,   apl_id*,    APLAGGR_UNIQUE|APLAGGR_LIST> TUListId;
typedef CaplTAggr <CaplEntity*,   CaplEntity*,    APLAGGR_UNIQUE|APLAGGR_LIST> TUListPEntity;
typedef CaplTAggr <CaplAttr*,     CaplAttr*,      APLAGGR_UNIQUE|APLAGGR_LIST> TUListPAttr;
typedef CaplTAggr <CaplInstance*, CaplInstance*,  APLAGGR_UNIQUE|APLAGGR_LIST> TUListPInst;
//typedef CaplTAggr <CaplAttrValue*,CaplAttrValue*,APLAGGR_UNIQUE|APLAGGR_LIST|APLAGGR_AUTOKILLREF> TUListPAttrVal;

typedef CaplTAggr <CaplEntity*,   CaplEntity*,    APLAGGR_UNIQUE|APLAGGR_LIST|APLAGGR_AUTOKILLREF> TUAKListPEntity;
typedef CaplTAggr <CaplAttr*,     CaplAttr*,      APLAGGR_UNIQUE|APLAGGR_LIST|APLAGGR_AUTOKILLREF> TUAKListPAttr;
typedef CaplTAggr <CaplInstance*, CaplInstance*,  APLAGGR_UNIQUE|APLAGGR_LIST|APLAGGR_AUTOKILLREF> TUAKListPInst;

#define SetLastErrorWithFileInfo(ErrCode) SetLastErrorEx(ErrCode,false,_T(__FILE__),__LINE__);
#define SetLastErrorWithFileInfoExtText(ErrCode,ExtText) SetLastErrorEx(ErrCode,false,_T(__FILE__),__LINE__,(CaplInstance*)-2,(CaplAttr *)-2,(CaplEntity *)-2,(CaplEntity *)-2,ExtText);
#define SetLastErrorWithInstFileInfo(ErrCode,Inst) SetLastErrorEx(ErrCode,false,_T(__FILE__),__LINE__,Inst);
#define SetLastErrorWithInstEnttFileInfo(ErrCode,Inst,Entt) SetLastErrorEx(ErrCode,false,_T(__FILE__),__LINE__,Inst,(CaplAttr*) -2,Entt);
#define SetLastErrorWithEnttEnttFileInfo(ErrCode,Entt1,Entt2) SetLastErrorEx(ErrCode,false,_T(__FILE__),__LINE__,(CaplInstance*)-2,(CaplAttr*) -2,Entt1,Entt2);
#define SetLastErrorWithEnttFileInfo(ErrCode,Entt1) SetLastErrorEx(ErrCode,false,_T(__FILE__),__LINE__,(CaplInstance*)-2,(CaplAttr*) -2,Entt1);
#define SetLastErrorWithInstAttrFileInfo(ErrCode,Inst,Attr) SetLastErrorEx(ErrCode,false,_T(__FILE__),__LINE__,Inst, Attr);
#define SetLastWarningWithFileInfo(ErrCode) SetLastErrorEx(ErrCode,true,_T(__FILE__),__LINE__);


//************************************************************************
//************************************************************************
//************************************************************************
#define MIN_SORTED_ATTR_SIZE 6
/** Описывает  entity как элемент словаря*/
class AFX_EXT_CLASS CaplEntity APL_INHERIT_FROM_Q_OBJECT
{
	APL_DEF_Q_OBJECT
public:

	apl_id id;		/**< Уникальный идентификатор */
	CString name ;	/**< Имя */
	bool complex;	/**< Является ли комплексным */

	/** Супертипы (родители) (кроме наследуемых)*/
	TUListPEntity supertypes;
	TUListId supertypes_id; // Список id родителей (Используется только при загрузке словаря)
	
	// inverse
	/** Подтипы (потомки)(кроме наследуемых) */
	TUListPEntity subtypes;
	/** Атрибуты (кроме наследуемых) */
	TUListPAttr attrs;
	
	// Derived
	/** Супертипы (родители) (включая наследуемые)*/
	TUListPEntity all_supertypes;
	/** Подтипы (потомки)(включая наследуемые) */
	TUListPEntity all_subtypes;
	/** Атрибуты (включая наследуемые) */
	TUListPAttr all_attrs;

	// Instances
	TUListPInst instances;
	// Methods
	CaplEntity(apl_id def_id=0, TCHAR *def_name=0){id=def_id; name=def_name;complex=false;m_table_id=-1;}
	CaplEntity(apl_id def_id, CString &def_name){id=def_id; name=def_name;complex=false;m_table_id=-1;}

	// для NetStepData, соединенного с oracle здесь будет храниться номер таблицы в которой лежат атрибуты entity
	int m_table_id;

};



//************************************************************************
//************************************************************************
//************************************************************************
/** Описывает  определение атрибута как элемент словаря*/
class AFX_EXT_CLASS CaplAttr APL_INHERIT_FROM_Q_OBJECT
{
	APL_DEF_Q_OBJECT
public:
	
	apl_id id;			/**< Уникальный идентификатор*/
	CaplEntity *entity;	/**< entity - владелец*/
	apl_id entity_id;	// ID entity. Используется только при загрузке словаря
	CString name;		/**< Имя*/
	aplValueType type;	/**< Тип*/
	aplValueType add_types[8];
	CaplEntity *inst_type;
	apl_id  inst_type_id; // ID entity на который ссылается. Используется только при загрузке словаря
	int index;			/**< № атрибута в таблице значений, если <0, то индекс неоднозначен*/ 

	/** Обязательность*/
	bool optional;
	CaplAttr *redeclaring;
	int redeclaring_id;
	TCHAR vid;
	bool bCanDerived;
	
	// Methods
	CaplAttr(apl_id def_id=0, CaplEntity *def_entity=0, TCHAR* def_name=0, aplValueType def_type=aplNOTYPE)
		{id=def_id; entity=def_entity; entity_id=0; name=def_name; type=def_type;
			add_types[0]=add_types[1]=add_types[2]=add_types[3]=add_types[4]=add_types[5]=add_types[6]=add_types[7]=aplNOTYPE;
			inst_type=0; inst_type_id=0; optional=false;redeclaring=0; redeclaring_id=0; vid=_T('e');bCanDerived=false;
			index=-2;}

	CaplAttr(apl_id def_id, CaplEntity *def_entity, CString &def_name,aplValueType def_type=aplNOTYPE)
		{id=def_id; entity=def_entity; entity_id=0; name=def_name; type=def_type;
			add_types[0]=add_types[1]=add_types[2]=add_types[3]=add_types[4]=add_types[5]=add_types[6]=add_types[7]=aplNOTYPE;
			inst_type=0; inst_type_id=0; optional=false;redeclaring=0; redeclaring_id=0; vid=_T('e');bCanDerived=false;
			index=-2;}
};
//************************************************************************
//************************************************************************
//************************************************************************
///** Связка атрибуто со значением
class AFX_EXT_CLASS CaplAttrValue
{
	public:
	CaplAttr *attr;		/**< Атрибут*/
	CaplValue value;	/**< Значение*/
	bool is_substring;	/**< Учитывать в поиске по like(true) - строка ищется слева либо по =(false); пока используется только в FindInstancesWithAttrValuesInLocalCache*/

	CaplAttrValue(){attr=0; is_substring=false;}
	CaplAttrValue(CaplAttr *attr_in){attr=attr_in; is_substring=false;}
	CaplAttrValue(const CaplAttrValue& item) { *this = item; }
	virtual ~CaplAttrValue(){}

	virtual void operator=(const CaplAttrValue& item)
	{
		if(this==&item)return;
		attr = item.attr;
		value = item.value;
		is_substring = item.is_substring;
	}
};



//************************************************************************
//************************************************************************
//************************************************************************
/** Описывает  instance*/
class AFX_EXT_CLASS CaplInstance APL_INHERIT_FROM_Q_OBJECT
{
	APL_DEF_Q_OBJECT
// 	friend class CaplStepData;
// 	friend class CaplNetStepData;
// 	friend class CaplQLQuery;
// 	friend class CaplStepDataWithFile;
// 	friend class CAplTransport;
// 	friend class COraStepData;
// 	friend struct SLongLifeCursorInfo;
// 	friend class CaplBaseInfo;
// 	friend class CLiteStepData;

public:
	/** Описывает  значение атрибута */
	class AFX_EXT_CLASS CaplValueDefinition
	{
	public:
		CaplValueDefinition(){changed=false; ArhiveAggr=0;}
		virtual ~CaplValueDefinition(){if(ArhiveAggr!=0) delete ArhiveAggr;}
		void Clear();

		// Attributes
		CaplValue value;	/**< Значение*/
		bool changed;		/**< Флаг измененности в текущей сессии*/
		
		CaplAggr *ArhiveAggr;
	};
	
protected:
	apl_id m_id;						/**<  Идентификатор в БД*/
	CaplEntity *m_type;				/**<  Тип instance*/
	aplAccessModeType m_accessmode;	/**<  Текущий уровень доступа*/
	bool m_is_user_access;			/**<  Проверять ли индивидуальный доступ пользователей к instance. Используется только на сервере!  */
	CaplInstance *m_access_pattern; /**< Указатель на шаблон доступа к инстансу. Используется только на сервере!  */
	bool m_temporary;				/**<  Является ли instance временной*/
	bool m_deleted;
	DATE m_create_date;				/**<  дата создания в БД*/
	CaplInstance* m_create_user;	/**<  указатель на пользователя создавшего объект в БД*/
	DATE m_update_date;				/**<  дата изменения в БД*/
	CaplInstance* m_update_user;	/**<  указатель на пользователя изменившего объект в БД*/
	CaplStepData* m_data;

public:
	inline apl_id GetId() const			{ return m_id; }
	inline CaplEntity *GetType() const	{ return m_type; }
	aplAccessModeType GetAccessmode(bool check_admin_mode=true) const;
	inline bool GetIsUserAccess() const {return m_is_user_access;}
	inline CaplInstance* GetAccessPattern() const {return m_access_pattern;}
	inline bool GetTemporary() const	{return m_temporary;}
	inline bool IsDeleted(){return m_deleted;}
	inline DATE GetCreateDate() {return m_create_date;}
	inline CaplInstance* GetCreateUser() const {return m_create_user;}
	inline DATE GetUpdateDate() {return m_update_date;}
	inline CaplInstance* GetUpdateUser() const {return m_update_user;}

	inline void SetId(apl_id id){m_id=id;}
	// функция предназначена исключительно для служебных целей. Запрещается использовать ее в клиентских приложениях.
	inline void SetServiceParam(CaplEntity *type){m_type=type;}
	void SetServiceParamFull(CaplEntity *type);
	inline void SetTemporary(bool temporary){m_temporary=temporary;}
	inline void SetAccessmode(aplAccessModeType accessmode){m_accessmode=accessmode;}
	inline void SetAccessPattern(CaplInstance* access_pattern){m_access_pattern=access_pattern;}
	inline void SetIsUserAccess(bool is_user_access){m_is_user_access=is_user_access;}
	inline void SetDeleted(bool param=true){m_deleted=param;}
	inline void SetCreateDate(DATE create_date) {m_create_date = create_date;}
	inline void SetCreateUser(CaplInstance* create_user) {m_create_user = create_user;}
	inline void SetUpdateDate(DATE update_date) {m_update_date = update_date;}
	inline void SetUpdateUser(CaplInstance* update_user) {m_update_user = update_user;}

	/** Значения атрибутов*/
	//TUListPAttrVal attrs;
	CaplValueDefinition *attrs;

	/** Конструктор*/
	CaplInstance(CaplStepData* data,CaplEntity *def_type, apl_id def_id=0,bool create_attrs=true);
	virtual ~CaplInstance();

	// Очищает атрибуты, освобождает память
	void ClearAttrs();
	bool IsChanged() const;
	inline CaplStepData* GetMyData() const { return m_data; }
	DATE m_dt_changed_attr;

};


struct SThreadContext
{
	SThreadContext():m_LastErrorCode(0), m_ErrorDescription(_T("")), m_ErrorAnnotation(_T("")){}
	void Set(SThreadContext* ctx)
	{
		if(ctx==0) return;
		m_LastErrorCode=ctx->m_LastErrorCode;
		m_ErrorDescription=ctx->m_ErrorDescription;
		m_ErrorAnnotation=ctx->m_ErrorAnnotation;
	}
	int m_LastErrorCode;
	CString m_ErrorDescription;
	CString m_ErrorAnnotation;
};

//************************************************************************
//************************************************************************
//************************************************************************
/** Основной класс работы с данными*/
class AFX_EXT_CLASS CaplStepData
{
public:
	CaplStepData();

	virtual ~CaplStepData();


	/**@name Функции работы со словарем */
	//@{

	/** Читает словарь по имени схемы 
		@param schema имя схемы
		@return <b>true</b> при удачном выполнении и false в случае ошибки */
	bool LoadDictionary(LPCTSTR schema);
	
	/** Читает словарь из файла 
		@param file_name имя файла словаря. 
		@param find_ex если true и словарь не найден по пути указанному в file_name - 
			то словарь ищется в каталоге, откуда было запущено текущее приложение (если имя 
			файла указано с путем - то имя файла словаря выделяется из пути). Если false и словарь
			не найден по пути указанному в file_name - возвращает false
		@param bApend если true - догружает к текущему словарю дополнительный
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool LoadDictionaryFromFile(LPCTSTR file_name, bool find_ex=true, bool bApend=false);

	/** Читает словарь из буфера в памяти
		@param dbuf буфер со словарем. 
		@param bApend если true - догружает к текущему словарю дополнительный
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool LoadDictionaryFromMemory(CaplDataBuf &dict_dbuf, bool bApend=false);

	bool LoadDictionaryAddition(int id);// Догружает словарь определяемый по Entity ID. Используется при открытии файла

	/** Догружает словари из списка. Список словарей dicts в процессе работы может изменяться!
		Используется при импорте из json. На будущее - надо проверять версии словарей
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool LoadDictionaryAddition(CaplStrMap &dicts);


	/** Записывет текущий словарь в файл 
		@param file имя файла словаря. Если имя указано без пути, то файл создается в текущем рабочем каталоге
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool SaveDictionaryToFile(LPCTSTR file);

	/** Записывет текущий словарь в память 
		@param dbuf буффер в который пишется
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool SaveDictionaryToMemory(CaplDataBuf &dbuf);

/** Записывет текущий словарь в CString 
		@param sString буффер в который пишется
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool SaveDictionaryToString(CString &sString);

	/** Устанавливает папку, из которой по умолчанию берется словарь 
		@param folder путь к папке
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	void SetDictionaryFolder(LPCTSTR folder);

	/** Удаляет словарь из памяти*/
	virtual void ClearDict();


	/** Возвращает ссылку на <b>entity</b> по ее имени
		@param type_name имя <b>entity</b>
		@return указатель на <b>entity</b> при удачном выполнении и 0 в случае ошибки */
	CaplEntity *GetEntityBN(LPCTSTR type_name);

	/** Возвращает ссылку на entity по ее идентификатору
		@param _id идентификатор <b>entity</b>
		@return указатель на <b>entity</b> при удачном выполнении и 0 в случае ошибки */
	CaplEntity *GetEntityById(apl_id id);
	
	/** Возвращает ссылку на комплексную entity по  именам ее составляющих*/
	CaplEntity *GetComplexEntityBN(CStringArray &names);
	/** Возвращает ссылку на комплексную entity по  именам ее составляющих в стиле обменного файла*/
	CaplEntity *GetComplexEntityBNP21(CStringArray &names);

	/** Возвращает ссылку на определение атрибута по имени его и имени его <b>entity</b>
		@param entity_name имя <b>entity</b>
		@param attr_name имя атрибута
		@return указатель на атрибут при удачном выполнении и 0 в случае ошибки */
	CaplAttr *GetAttrDefinitionBN(LPCTSTR entity_name, LPCTSTR attr_name);

	/** Возвращает ссылку на определение атрибута по его имени  и ссылке на его <b>entity</b>
		@param entity ссылка на <b>entity</b>
		@param attr_name имя атрибута
		@return указатель на атрибут при удачном выполнении и 0 в случае ошибки */
	CaplAttr *GetAttrDefinition(CaplEntity *entity, LPCTSTR attr_name) const;

	/** Возвращает ссылку не атрибут по его идентификатору
		@param id идентификатор атрибута
		@return указатель на атрибут при удачном выполнении и 0 в случае ошибки */
	CaplAttr* GetAttrDefinitionById(apl_id id);
	//@}

	

	/**@name  Функции работы с данными*/
	//@{

	/** Очистка данных из памяти*/
	virtual void ClearData();
	/** Удаление из памяти атрибутов  у instances*/
	void FreeInstancesAttr(aplExtent &instances);

	/** Создает instance по ссылке на entity*/
	CaplInstance  *CreateInstance(CaplEntity *entity, bool is_temporary=false, bool create_attrs=true);
	/** Создает instance по имени entity*/
	CaplInstance  *CreateInstanceBN(LPCTSTR type_name, bool is_temporary=false, bool create_attrs=true);

	/** Удаляет instance. Функция удаляет из памяти все атрибуты instance,
	а саму instance помечает как удаленную
		@param inst указатель на instance
		@param bChekReference если надо удалять ли ссылки на данную instance - <b>true</b>,
			если оставлять ссылки - <b>false</b>
		@param bNoSetChanged если <b>true</b> - то удаляется только в локальном кеше
			если <b>false</b> - удаляется и на сервере
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool DeleteInstance(CaplInstance *inst, bool bChekReference=true, bool bNoSetChanged=false);
	bool DeleteInstanceForced(CaplInstance *inst);
	
	/// Возвращает указатель на инстанс с указанным id
	CaplInstance* GetInstById(apl_id id);

	/** Получить список instance указанного типа (по ссылке на тип)
		@param entity тип искомых instance.
		@param extent в эту переменную будет помещен список найденных instance
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	virtual bool GetEntityExtent(CaplEntity *entity,aplExtent &extent);
	/** Получить список instance указанного типа (по имени типа)
		@param ent_name имя типа искомых instance.
		@param extent в эту переменную будет помещен список найденных instance
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	virtual bool GetEntityExtentBN(LPCTSTR ent_name, aplExtent &extent);


	/** Возвращает ссылку на значение атрибута для указанной instance по ссылке на атрибут
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param bAutoCreate создавать или нет такой атрибут, если его не было
		@return указатель на значение атрибута при удачном выполнении и 0 в случае ошибки */
	CaplInstance::CaplValueDefinition *GetAttrValue(CaplInstance *inst,CaplAttr *attr, bool bAutoCreate=false) const;
		
	/** Возвращает ссылку на значение атрибута для указанной instance по ссылке на атрибут
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param bAutoCreate создавать или нет такой атрибут, если его не было
		@return указатель на значение атрибута при удачном выполнении и 0 в случае ошибки */
	CaplInstance::CaplValueDefinition *GetAttrValueBN(CaplInstance *inst, LPCTSTR attr_name, bool bAutoCreate=false);
	
	// ДСП Возвращает ссылку на значение атрибута по индексу. При необходимости выделяет память под атрибуты
	CaplInstance::CaplValueDefinition *GetAttrValueByIndex(CaplInstance *inst,int real_indx);
	
	/** Получает указатель на значение атрибута instance по указателю на атрибут (для атрибутов любого типа)
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value в эту переменную будет помещен адрес объекта, хранящего значение атрибута в указанной instance
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	virtual	bool GetAttr(CaplInstance *inst, CaplAttr *attr, CaplValue **value) const;
	/** Получает значение атрибута instance по указателю на атрибут (для атрибутов любого типа)
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value в указанный объект будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, CaplValue &value) const;
	/** Получает указатель на значение атрибута instance по имени атрибута (для атрибутов любого типа)
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value в эту переменную будет помещен адрес объекта, хранящего значение атрибута в указанной instance
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttrBN(CaplInstance *inst, LPCTSTR attr_name, CaplValue **value) const;
	/** Получает значение атрибута instance по имени атрибута (для атрибутов любого типа)
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value в указанный объект будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttrBN(CaplInstance *inst, LPCTSTR attr_name, CaplValue &value) const;

	/** Получает значение атрибута instance по указателю на атрибут (для целочисленных атрибутов)
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value в указанный объект будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, int &value) const;
	/** Получает значение атрибута instance по имени атрибута (для целочисленных атрибутов)
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value переменная, в которую будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttrBN(CaplInstance *inst, LPCTSTR attr_name, int &value) const;
	/** Получает значение атрибута instance по указателю на атрибут (для дробных атрибутов)
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value переменная, в которую будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, double &value) const;
	/** Получает значение атрибута instance по имени атрибута (для дробных атрибутов)
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value переменная, в которую будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttrBN(CaplInstance *inst, LPCTSTR attr_name, double &value) const;
	/** Получает значение атрибута instance по указателю на атрибут (для строковых атрибутов)
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value переменная, в которую будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, CString &value) const;
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, _std_string &value) const;
	/** Получает значение атрибута instance по имени атрибута (для строковых атрибутов)
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value переменная, в которую будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttrBN(CaplInstance *inst, LPCTSTR attr_name, CString &value) const;
	bool GetAttrBN(CaplInstance *inst, LPCTSTR attr_name, _std_string &value) const;
	/** Получает значение атрибута instance по указателю на атрибут (для атрибутов типа instance)
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value переменная, в которую будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, pCaplInstance &value) const;
	/** Получает значение атрибута instance по имени атрибута (для атрибутов типа instance)
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value переменная, в которую будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttrBN(CaplInstance *inst, LPCTSTR attr_name, pCaplInstance &value) const;
	/** Получает значение атрибута instance по указателю на атрибут (для атрибутов типа bool)
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value переменная, в которую будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, bool &value) const;
	/** Получает значение атрибута instance по имени атрибута (для атрибутов типа bool)
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value переменная, в которую будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttrBN(CaplInstance *inst, LPCTSTR attr_name, bool &value) const;
	/** Получает значение атрибута instance по указателю на атрибут (для атрибутов типа aggr)
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value переменная, в которую будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, CaplAggr &value) const;
	/** Получает значение атрибута instance по имени атрибута (для атрибутов типа aggr)
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value переменная, в которую будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttrBN(CaplInstance *inst, LPCTSTR attr_name, CaplAggr &value) const;

	/** Получает значение атрибута instance по указателю на атрибут (для атрибутов типа aggr) и записывает все Instance из него в value 
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value переменная, в которую будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, aplExtent &value) const;
	/** Получает значение атрибута instance по имени атрибута (для атрибутов типа aggr) и записывает все Instance из него в value 
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value переменная, в которую будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool GetAttrBN(CaplInstance *inst, LPCTSTR attr_name, aplExtent &value) const;

	/** Устанавливает значение атрибута instance по указателю на атрибут (для атрибутов любого типа)
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttr(CaplInstance *inst, CaplAttr *attr, CaplValue &value);
	/** Получает значение атрибута instance по имени атрибута (для атрибутов любого типа)
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttrBN(CaplInstance *inst, LPCTSTR attr_name, CaplValue &value);

	/** Устанавливает значение атрибута instance по указателю на атрибут (для целочисленных атрибутов)
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttr(CaplInstance *inst, CaplAttr *attr,  int value);
	/** Устанавливает значение атрибута instance по имени атрибута (для целочисленных атрибутов)
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttrBN(CaplInstance *inst, LPCTSTR attr_name,  int value);
	/** Устанавливает значение атрибута instance по указателю на атрибут (для дробных атрибутов)
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttr(CaplInstance *inst, CaplAttr *attr,  double value);
	/** Устанавливает значение атрибута instance по имени атрибута (для дробных атрибутов)
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttrBN(CaplInstance *inst, LPCTSTR attr_name,  double value);
	/** Устанавливает значение атрибута instance по указателю на атрибут (для строковых атрибутов)
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttr(CaplInstance *inst, CaplAttr *attr, LPCTSTR value);
	/** Устанавливает значение атрибута instance по имени атрибута (для строковых атрибутов)
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttrBN(CaplInstance *inst, LPCTSTR attr_name, LPCTSTR value);
	/** Устанавливает значение атрибута instance по указателю на атрибут (для атрибутов типа bool)
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttr(CaplInstance *inst, CaplAttr *attr, bool value);
	/** Устанавливает значение атрибута instance по имени атрибута (для атрибутов типа bool)
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttrBN(CaplInstance *inst, LPCTSTR attr_name,  bool value);
	/** Устанавливает значение атрибута instance по указателю на атрибут (для атрибутов типа instance)
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttr(CaplInstance *inst, CaplAttr *attr, CaplInstance *value);
	/** Устанавливает значение атрибута instance по имени атрибута (для атрибутов типа instance)
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttrBN(CaplInstance *inst, LPCTSTR attr_name,  CaplInstance *value);
	/** Устанавливает значение атрибута instance по указателю на атрибут (для атрибутов типа aggr)
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttr(CaplInstance *inst, CaplAttr *attr, const CaplAggr &value);
	/** Устанавливает значение атрибута instance по имени атрибута (для атрибутов типа aggr)
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttrBN(CaplInstance *inst, LPCTSTR attr_name,  const CaplAggr &value);
	/** Устанавливает значение атрибута instance по указателю на атрибут (для атрибутов типа aggr) как массив Instance
		@param inst указатель на instance
		@param attr указатель на атрибут
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttr(CaplInstance *inst, CaplAttr *attr, const aplExtent &value);
	/** Устанавливает значение атрибута instance по имени атрибута (для атрибутов типа aggr) как массив Instance
		@param inst указатель на instance
		@param attr_name имя атрибута
		@param value переменная, из которой будет скопировано значение атрибута
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PutAttrBN(CaplInstance *inst, LPCTSTR attr_name,  const aplExtent &value);

	#ifdef QSTRING_H

		 #ifdef _UNICODE
			#define CS2QS(s) QString::fromWCharArray(LPCWSTR(s))
			#define QS2CS(s) (s.toStdWString()).c_str()
		#else
			#define CS2QS(s) QString((LPCSTR)s) 
			#define QS2CS(s) (s.toStdString()).c_str()
		#endif

		// Обёртки для использования c Qt

		inline bool GetAttr(CaplInstance *inst, CaplAttr *attr, QString &value)
		{
			CString s;
			if(!GetAttr(inst, attr, s)) {value=""; return false;}
			value=CS2QS(s);
			return true;
		}

		inline bool GetAttrBN(CaplInstance *inst, LPCTSTR attr_name, QString &value)
		{
			CString s;
			if(!GetAttrBN(inst, attr_name, s)) {value=""; return false;}
			value=CS2QS(s);
			return true;
		}

		inline bool PutAttrBN(CaplInstance *inst, LPCTSTR attr_name, QString &value) {return PutAttrBN(inst, attr_name, QS2CS(value));}

		inline bool PutAttr(CaplInstance *inst, CaplAttr *attr, QString &value) { return PutAttr(inst, attr, QS2CS(value));}

	#endif

	/** Рекурсивно составляет список всех instance, на которые ссылается указанная instance
		@param inst исходная instance
		@param instances список, в который будут помещены используемые instance*/
	void aplGetAllInstanceRef(CaplInstance *inst, aplExtent &instances);
	
	/** Копирует массив instances в другой экземпляр класса работы с данными с сохранением перекрестных ссылок
		@param instances список instance для копирования. Копируются только те instance, которые входят
			в данный список
		@param out_data объектный кеш, в который будут скопированы instance. Перед копированием
			предыдущие данные, создержащиеся в out_data будут удалены.*/
	void aplFarCopyInstances(aplExtent &instances, CaplStepData &out_data, bool clear_data = true);

	/** Ищет все instance указанного типа, которые ссылаются на указанную instance указанным атрибутом
	(по ссылке на атрибут)
		@param inst используемая instance
		@param ent тип искомых instance.
		@param attr атрибут, которым искомые instance ссылаются на используемую instance
		@param extent в эту переменную будет помещен список найденных instance
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool FindInstanceUsers(CaplInstance *inst, CaplEntity *ent, CaplAttr* attr, aplExtent &extent);
	/** Ищет все instance указанного типа, которые ссылаются на указанную instance указанным атрибутом
	(по имени атрибута)
		@param inst используемая instance
		@param ent_name тип искомых instance.
		@param attr_name имя атрибута, которым искомые instance ссылаются на используемую instance
		@param extent в эту переменную будет помещен список найденных instance
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool FindInstanceUsersBN(CaplInstance *inst, LPCTSTR ent_name, LPCTSTR attr_name, aplExtent &extent);


	/** Проверить, является ли instance экземпляром указанного типа (по указателю на тип) 
	с учетом наследования типов
		@param inst проверяемая instance
		@param entity указатель на тип
		@return <b>true</b> если inst является экземпляром указанного типа или его потомков и
			<b>false</b>, если inst является экземпляром другого типа*/
	bool IsKindOf(CaplInstance *inst, CaplEntity *entity);
	/** Проверить, является ли instance экземпляром указанного типа (по имени типа) 
	с учетом наследования типов
		@param inst проверяемая instance
		@param type_name имя типа
		@return <b>true</b> если inst является экземпляром указанного типа или его потомков и
			<b>false</b>, если inst является экземпляром другого типа*/
	bool IsKindOfBN(CaplInstance *inst, LPCTSTR type_name);
	bool IsKindOfEntity(CaplEntity *entity_tested, CaplEntity *entity_parent);

	bool ChekAttrType(CaplInstance *inst, CaplAttr *attr, aplValueType type, CaplInstance *inst_val=0);
	bool ChekAttrType(CaplInstance *inst, CaplAttr *attr, CaplValue &value);

	//@}


	/**@name  Функции работы с файлами*/
	//@{
	/** Сохраняет все данные в текстовом файле специального формата
		@param file_name имя файла
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	virtual bool SaveToTextFile(LPCTSTR file_name, bool save_temporary=false);
	/** Сохраняет данные в бинарном файле специального формата
		@param file_name имя файла
		@param changes_only если необходимо сохранить все данные, то <b>false</b>; если 
			необходимо сохранить в файл только данные, измененные с момента последнего сохранения, то <b>true</b> 
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	virtual bool SaveToFile(LPCTSTR file_name, bool changes_only=false);
	/** Сохраняет данные в текстовом файле в формате, определенным протоколом 21 стандарта STEP
		@param file_name имя файла
		@param header экземпляр класса, описывающий заголовок текстового файла в соответствии с протоколом 21 стандарта STEP
		@param mode определяет способ кодирования русских букв
		@param bSaveRealId если false instance нумеруются по порядку, если true идентификатор в файле равен идентификатору в БД
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool SaveP21(LPCTSTR file_name, aplP21Header &header, aplRusSaveMode mode = aplWIN, bool bSaveRealId=false);

	/** Сохраняет данные в текстовом файле в формате, определенным протоколом 21 стандарта STEP в буффер памяти
		@param filename - имя файла, которое записывается в заголовок*/
	bool SaveP21ToDataBuf(CString &sDataBuf, aplP21Header &header, aplRusSaveMode mode, bool bSaveRealId, LPCTSTR filename=0);
	
	/** Читает данные из бинарного файла специального формата
		@param file_name имя файла
		@param appload_mode если перед загрузкой необходимо удалить данные, уже имеющиеся в 
			экземпляре класса, то <b>false</b>; если данные из файла нужно догрузить к уже 
			имеющимся данным, то <b>true</b> 
		@param check_ro если <b>true</b>, то запретить чтение файла c атрибутами только-чтение, сркытый, системный
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool LoadFromFile(LPCTSTR file_name, bool appload_mode=false, bool check_ro=true);
	/** Читает данные из текстового файла специального формата. Данные, уже имеющиеся в 
		экземпляре класса уничтожаются
		@param file_name имя файла
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool LoadFromTextFile(LPCTSTR file_name);
	/** Читает данные из текстового файла формата, определенного протоколом 21 стандарта STEP
		@param file_name имя файла
		@param header экземпляр класса, в который будет занесена информация из заголовка текстового файла
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool LoadP21(LPCTSTR file_name, aplP21Header &header);
	/** Сохраняет все данные в файле формата json
		@param file_name имя файла
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool SaveToJsonFile(LPCTSTR file_name, bool save_temporary=false);
	/** Читает данные из файла формата json. Данные, уже имеющиеся в 
		экземпляре класса уничтожаются
		@param file_name имя файла
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool LoadFromJsonFile(LPCTSTR file_name);

	//@}


	/**@name  Функции работы с данными в памяти*/
	//@{
	/** Сохраняет все данные в буфере специального формата
		@param dbuf экземпляр буфера, в который производится сохранение
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool SaveToDataBuf(CaplDataBuf &dbuf, int ver=0x0002);
	/** Сохраняет данные, измененные с момента последнего сохранения, в буфере специального формата
		@param dbuf экземпляр буфера, в который производится сохранение
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool SaveChangesToDataBuf(CaplDataBuf &dbuf);
	/** Читает данные из буфера специального формата; данные из буфера дополняют уже 
	имеющиеся данные
		@param dbuf экземпляр буфера, из которого производится чтение
		@param ext_inst указатель на экстент, в который будут занесены все instance, содержащиеся в буфере. Может быть равен нулю
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool ApploadFromDataBuf(CaplDataBuf &dbuf, aplExtent *ext_inst=0); 
	//@}

	/**@name  Функции проверки корректности*/
	//@{

	/** проверяет, включена ли указанная instance в список инстансов текущего класса
		@param inst проверяемая instance
		@return <b>true</b> если занесена и <b>false</b> если нет */
	bool IsMyInstance(CaplInstance *inst, bool SafeFind=false);

	/** проверяет, принадлежит ли указанные атрибут указанной entity
		@param entity проверяемая entity
		@param attr проверяемый атрибут
		@return <b>true</b> если занесена и <b>false</b> если нет */
	bool IsEntityAttr(CaplEntity *entity, CaplAttr *attr) const;


	/**  Проверяет наличие циклов среди значений инстансов
	@return <b>true</b> если цикл есть и <b>false</b> если нет */
	bool TestCycleInRelationBN(LPCTSTR entity, LPCTSTR in_attr, LPCTSTR out_attr, CaplInstance *in_val, CaplInstance *out_val);
	/**  Проверяет наличие циклов среди значений инстансов
	@return <b>false</b> если цикл будет и <b>true</b> если нет */
	virtual bool TestCycleInRelation(CaplEntity *ent, CaplAttr *in_attr, CaplAttr *out_attr, CaplInstance *in_val, CaplInstance *out_val);

	/** Ищет среди данных <B>instance</B> с заданным именем типа, с заданными атрибутами и отличную от заданной.
	Различия в регистре строковых атрибутов ингорируются.
		@param entity тип искомых <B>instance</B>
		@param tested_inst проверяемая <B>instance</B>; может быть равно 0
		@param count количество сравниваемых атрибутов
		@param values массив значений атрибутов
		@return <b>true</b> если нашли, <b>false</b> если ничего не найдено*/
	virtual bool TestUniqueAttrValuesBN(LPCTSTR entity, CaplInstance *tested_inst, int count, CaplAttrValue *values);
	/** Ищет среди данных <B>instance</B> с заданного типа, с заданными атрибутами и отличную от заданной.
	Различия в регистре строковых атрибутов ингорируются.
		@param entity тип искомых <B>instance</B>
		@param tested_inst проверяемая <B>instance</B>; может быть равно 0
		@param count количество сравниваемых атрибутов
		@param values массив значений атрибутов
		@param bIgnoreSpace не используется (используется при перегрузке)
		@return <b>true</b> если нашли, <b>false</b> если ничего не найдено*/
	virtual bool TestUniqueAttrValues(CaplEntity *entity, CaplInstance *tested_inst, int count, CaplAttrValue *values, bool bIgnoreSpace=false);
	//@}

	/**@name  Функции обработки ошибок*/
	//@{
public:
	/** Устанавливает код текущей ошибки или предупреждения и выводит сообщение об ошибке в
	стандартное стандартный поток вывода и в виде диалога (в соответствии с режимом вывода 
	сообщений об ошибках, заданных функциями Set...PrintMode и Set...MessageMode)
		@param ErrorCode код ошибки или предупреждения
		@param warning если устанавливается код ошибки, то <b>false</b>; 
			если код предупреждения, то <b>true</b> */
	void SetLastError(int ErrorCode, bool warning=false) const;

	/** Устанавливает код текущей ошибки или предупреждения и выводит сообщение об ошибке в
	стандартное стандартный поток вывода и в виде диалога (в соответствии с режимом вывода 
	сообщений об ошибках, заданных функциями Set...PrintMode и Set...MessageMode). Выводит в 
	окно Debug отладчика строчку с номером и описанием ошибки и ссылкой на место ошибки
	согласно параметрам file и line
		@param ErrorCode код ошибки или предупреждения
		@param warning если устанавливается код ошибки, то <b>false</b>; 
			если код предупреждения, то <b>true</b>
		@param file имя файла, в котором произошла ошибка
		@param line код строка, в которой произошла ошибка */
	void SetLastErrorEx(int ErrorCode, bool warning, LPCTSTR file, int line,
				CaplInstance* inst=(CaplInstance*)-2, CaplAttr *attr=(CaplAttr *)-2,
				CaplEntity *entt=(CaplEntity *)-2, CaplEntity *entt2=(CaplEntity *)-2, LPCTSTR add_text = NULL) const;
	void SetLastErrorEx(SaplErrorDescription &error);

	/** Возвращает описание ошибки или предупреждения по коду ошибки
		@param ErrorCode код ошибки или предупреждения
		@return строка с описанием ошибки*/
	static CString GetErrorDescription(int ErrorCode );
	
	/** Выводит сообщение об текущей ошибке или предупреждении (в соответствии с режимом вывода 
	сообщений об ошибках, заданных функциями Set...PrintMode и Set...MessageMode)
		@param warning если требуется вывести описание ошибки, то <b>false</b>; 
			если описание предупреждения, то <b>true</b> */
	virtual void PrintError(bool warning=false) const;

	/** Устанавливает режим вывода описания текущих ошибок
	в стандартный поток вывода и в окно "Debug" отладчика
		@param mode если требуется выводить описание ошибок, то <b>true</b>;
	если не требуется то <b>false</b> */
	void SetErorPrintMode(bool mode){m_ErrorPrintMode=mode;}
	
	/** Устанавливает режим вывода описания текущих ошибок
	в виде диалога
		@param mode если требуется выводить описание ошибок, то <b>true</b>;
		если не требуется то <b>false</b> */
	void SetErrorMessageMode(bool mode){m_ErrorMessageMode=mode;}

	/** Устанавливает режим вывода описания текущих предупреждений 
	в стандартный поток вывода и в окно "Debug" отладчика
		@param mode если требуется выводить описание предупреждений, то <b>true</b>;
		если не требуется то <b>false</b> */	
	void SetWarningPrintMode(bool mode){m_WarningPrintMode=mode;}
	
	/** Устанавливает режим вывода описания текущих предупреждений
	в виде диалога
		@param mode если требуется выводить описание предупреждений, то <b>true</b>;
		если не требуется то <b>false</b> */
	void SetWarningMessageMode(bool mode){m_WarningMessageMode=mode;}
#ifdef _MFC_VER
	/// Вернуть код текущей ошибки
	int GetLastError(){return m_LastErrorCode;}
	/** Вернуть текстовое описание текущей ошибки*/
	LPCTSTR GetLastErrorDescription(){return LPCTSTR(m_ErrorDescription);}

	inline void SetErrorAnnotation(LPCTSTR annotation){m_ErrorAnnotation = annotation;}
#else
	/// Вернуть код текущей ошибки
	int GetLastError();
	/** Вернуть текстовое описание текущей ошибки*/
	LPCTSTR GetLastErrorDescription() const;

	void SetErrorAnnotation(LPCTSTR annotation);
	void SetErrorDescription(LPCTSTR description);
#endif

	void SetBuferForErrMessage(CString *bufer_for_err_message){m_bufer_for_err_message = bufer_for_err_message;}

	//@}
	/// Возвращает состояние режима только-чтения
	bool IsReadOnly(){return m_is_readonly;}
	/// Возвращает состояние - загружен ли словарь
	bool IsDictLoad(){return m_CurSchema!=_T("");}
	
#ifdef _MFC_VER
	apl_id GetMaxInstNum(){return m_MaxInstNum;}
#else
	apl_id GetMaxInstNum(){CaplEnterCriticalSection ecs(&m_ThreadsProtect); return m_MaxInstNum;}
#endif

	//Удаляет из КЭШа указанные инстансы
	//Использовать осторожно. данная функция не проверяет используются ли данные инстансы в качестве атрибутов или нет!!!
	bool ClearInstances(aplExtent &ext);
	bool ClearInstances(CaplEntity* pEntyti);

	/// Удаляет из ext все instance, на которые ссылается хотя бы один из ext (оставляет только корневые)
	/// !!! Если в структуре значений есть циклы, то все элементы циклов в рещультат не попадают
	bool RemoveNonRootInstances(aplExtent &ext);  

	// При установке параметра is_process в false - во внутренних циклах и т.п. перестает обрабатывать
	// сообщения WM_PAINT. Флаг добавлен для ILS. Вызывается с уровня NetStepData.
	static bool SetGlobalProcessWmPaint(bool is_process);

public:
	
	CString m_CurDataFile;	/**< Имя последнего прочитанного файла данных*/
	CString m_CurSchema;	/**< Имя текущей схемы данных*/
	int m_CurSchemaVersion;	/**< Версия текущей схемы данных*/
	
	//CString m_CurSchema2;	/**< Имя текущей схемы данных дополнительного словаря*/
	//int m_CurSchemaVersion2;	/**< Версия текущей схемы дополнительного словаря*/

	struct CAddScheme  // Информация о дополнительно загруденном словаре.
	{
		CString m_scheme; // имя схемы
		int m_version;    // версия

		CAddScheme(LPCTSTR scheme, int version){m_scheme=scheme; m_version=version;};
	};

	CString m_ListAddSchemes; /**< Список дополнительных схем для загрузки при чтении словарей*/

	CaplTAggr <CAddScheme*, CAddScheme*,  APLAGGR_UNIQUE|APLAGGR_LIST|APLAGGR_AUTOKILLREF> m_CurAddSchemes; /**< Список загруженных дополнительных схем*/ 

    CString GetDictionaryDescription(); /**< Возвращает список текущих схем и их версий для вывода в интерфейс*/
	bool GetDictionaryDescription(CaplStrMap &map); /**< Возвращает список текущих схем и их версий для вывода в json */

	bool m_auto_load_add_dict; /**< Автоматически искать и догружать словарь для новых типов объектов */
	
	//идет работа с базой или файлом ansi (true) или unicode (false)
	bool m_global_ansi_string;
	// В PutAttr проверять значения и если новое значение равно старому - не менять флаг changed.
	// Используется в Qt для передачи на сервер только реально измененных значений атрибутов
	bool m_check_val_in_putattr;

	bool m_SetErrorMode;		/** Используется для исключения записи в "общие" переменные, при использовании распаралеливания кода*/ //Добавлено Даровских

	CString *m_bufer_for_err_message;

	bool m_Default_TextFormat;
	bool m_MakeCopyAggr;

	TUAKListPEntity	entities;	/**< Список entity текущей схемы данных*/
	TUAKListPAttr	attrs;		/**< Список атрибутов текущей схемы данных*/
	aplExtent	instances;	/**< Список instance текущей схемы данных*/

	CString m_DictionatyFolder;
	
	inline bool GetAdminMode(){return m_admin_mode;}

protected:
	bool m_append_all_chemas;

	apl_id m_MaxInstNum;
	bool m_is_readonly;
#ifdef _MFC_VER
	bool m_non_admin_readonly;
	mutable int m_LastErrorCode;
	bool m_TestAccessMode;
	bool m_ErrorPrintMode;
	bool m_ErrorMessageMode;
	bool m_WarningPrintMode;
	bool m_WarningMessageMode;
	mutable CString m_ErrorDescription;
	mutable CString m_ErrorAnnotation;
#else
	CAplAtomicLong m_lock_readonly;
	CAplAtomicLong m_non_admin_readonly;
	CAplAtomicLong m_TestAccessMode;
	CAplAtomicLong m_ErrorPrintMode;
	CAplAtomicLong m_ErrorMessageMode;
	CAplAtomicLong m_WarningPrintMode;
	CAplAtomicLong m_WarningMessageMode;

	mutable CAplCriticalSection m_ThreadsProtect;
	CAplAtomicLong m_MultyThreads;
	// Переменные с кодами ошибок для каждой нити в режиме m_MultyThreads==true
	mutable QThreadStorage<SThreadContext*> m_Errors;
	// Переменные с кодами ошибок для всех нитей в режиме m_MultyThreads==false
	mutable int m_LastErrorCode;
	mutable CString m_ErrorDescription;
	mutable CString m_ErrorAnnotation;

	inline SThreadContext* GetErrContext() const
	{
		SThreadContext* pErr = m_Errors.localData();
		if(pErr == 0)
		{
			pErr = new SThreadContext();
			m_Errors.setLocalData(pErr);
		}
		return pErr;
	}
#endif

	inline void ErrWrite2Ctx(SThreadContext* context)
	{
		if(context==0) return;
#ifndef _MFC_VER
		if(m_MultyThreads)
		{
			SThreadContext* pErr = m_Errors.localData();
			if(pErr == 0) return;
			context->Set(pErr);
			return;
		}
#endif
		context->m_LastErrorCode = m_LastErrorCode;
		context->m_ErrorDescription = m_ErrorDescription;
		context->m_ErrorAnnotation = m_ErrorAnnotation;
	}

	inline void ErrReadFromCtx(SThreadContext* context)
	{
		if(context==0) return;
#ifndef _MFC_VER
		if(m_MultyThreads)
		{
			SThreadContext* pErr = m_Errors.localData();
			if(pErr == 0)
			{
				pErr = new SThreadContext();
				m_Errors.setLocalData(pErr);
			}
			pErr->Set(context);
			return;
		}
#endif
		m_LastErrorCode= context->m_LastErrorCode;
		m_ErrorDescription = context->m_ErrorDescription;
		m_ErrorAnnotation = context->m_ErrorAnnotation;
	}

	CaplAttr **m_AttrIndex;
	CaplAttr **m_AttrIndex2;
	CaplEntity **m_EntityIndex, **m_EntityIndex2;  // Индексы Entity  для прямого доступа по ID (для основногои дополнительных словарей)
	apl_id m_MaxEntId;  // Максимальный индекс в m_EntityIndex (размер памяти)
	apl_id m_MinEntId2, m_MaxEntId2;  // Минимальный и максимальный индекс в m_EntityIndex2 для дополнительного словаря (EntityID >cMinId4ExtSchema)
	apl_id m_MaxAttrId;
	apl_id m_MaxAttrId2, m_MinAttrId2;

	CaplStrMap m_EntytyNameMap; // Кэш для GetEntityBN

	bool m_ClearDataAfterError;
	void SetMaxDoubleVal(double _MaxDoubleVal);

	inline void SetAdminMode(bool mode){m_admin_mode=mode;};

	bool m_admin_mode;

	void GetAllSupertypes(CaplEntity *entity, CaplTAggr <CaplEntity*,CaplEntity*,APLAGGR_UNIQUE|APLAGGR_LIST> &all_st);
	void GetAllSubtypes(CaplEntity *entity, CaplTAggr <CaplEntity*,CaplEntity*,APLAGGR_UNIQUE|APLAGGR_LIST> &all_st);
	void GetAllEntityAttrs(CaplEntity *entity,CaplTAggr <CaplAttr*,CaplAttr*,APLAGGR_UNIQUE|APLAGGR_LIST> &all_a);

	DWORD m_dwLastPaintTickCount; // Время последней перерисовки для уменьшения кол-ва перерисовок
	
public:
	// Формирует имя пользователя для функций определения доступа
	CString UserNameDecode(CaplInstance* user, bool for_user, bool case_first=true);

	/** переводит шаблон доступа, заданный в виде строки, в таблицу доступа
	описание шаблона доступа см. функцию NET_SetAccessFromPattern
	@param str_pattern - строка с описанием доступа
	@param access_table - таблица доступа, в которую помещается разобранный шаблон
	@param err_mess - строка для размещения списка ошибок. Если указатель не задан - функция сама выводит сообщение об ошибке
	@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool ParseAccessStringPattern(const CString &str_pattern, aplUsers &access_table, CString *err_mess = 0, bool ignore_deleted_users = false, aplExtent *external_users = 0);

	/** переводит таблицу доступа в шаблон доступа, заданный в виде строки
	@param access_table - таблица доступа, которую необходимо перевести. В строку переводится 
	информация только для первого unstance в каждой группе!
	@param str_pattern - строка с описанием доступа.
	Формат строки см. функцию NET_SetAccessFromPattern
	@param is_rus - если true, то строка выводится в формате "для пользователя"
	@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PrintAccessStringPattern(aplUsers &access_table, CString &str_pattern, bool is_rus=false, bool *p_is_temp_users=0, bool def_access=true);


};

//************************************************************************
//************************************************************************
//************************************************************************
/** Класс позволяющий работать с фрагментом данных CaplStepData*/
class AFX_EXT_CLASS CaplFictiveStepData : public CaplStepData
{
public:
	CaplFictiveStepData(){
		entities.AutoKillReference=false;
		attrs.AutoKillReference=false;
		instances.AutoKillReference=false;
	};

	virtual ~CaplFictiveStepData();
	
	// Новая функция
	/** Инициализирует класс данными из другого экземпляра класса работы с данными с сохранением перекрестных ссылок
		@param data экземпляр класса, из которого берутся данные
		@param ext перечень instance, которые должны быть скопированы в текущий экземпляр класса
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool Initialize(CaplStepData *data, aplExtent *ext);
	
	// Перегрузка
	/**@name  Функции работы со словарем*/
	//@{

	bool LoadDictionary(LPCTSTR schema);		 /**<Чтение словаря*/
	bool LoadDictionaryFromFile(LPCTSTR schema); /**<Чтение словаря из файла*/
	void SetDictionaryFolder(LPCTSTR folder);	 /**<Установка каталога для словарей*/
	//@}

	/**@name  Функции работы с данными*/
	//@{
	CaplInstance  *CreateInstance(CaplEntity *entity);		/**<Создать Instance*/
	CaplInstance  *CreateInstanceBN(LPCTSTR type_name);	/**<Создать Instance по имени*/
	bool DeleteInstance(CaplInstance *inst);				/**<Удалить Instance*/

	bool GetEntityExtent(CaplEntity *entity,aplExtent &extent);		/**<Взять Extent*/
	bool GetEntityExtentBN(LPCTSTR ent_name,aplExtent &extent);	/**<Взять Extent по имени*/
	//@}

	/**@name  Функции работы с файлами*/
	//@{
	virtual bool LoadFromFile(LPCTSTR file_name,bool appload_mode=false);	/**<Прочитать файл*/
	virtual bool LoadFromTextFile(LPCTSTR file_name);						/**<Прочитать текстовый файл*/
	virtual	bool LoadP21(LPCTSTR file_name, aplP21Header &header);			/**<Прочитать обменный файл*/
	//@}
	
	/**@name  Функции работы с буффером данных*/
	//@{
	virtual bool ApploadFromDataBuf(CaplDataBuf &dbuf,aplExtent *ext_inst=0);	/**<Догрузить данные в dbuf*/ 
	bool SaveChangesToDataBuf(CaplDataBuf &dbuf);						/**<Сохранить изменения в dbuf*/
	//@}
};
//************************************************************************
//************************************************************************
//************************************************************************
/** Заголовок обменного файла (ISO-10303-21)*/
class aplP21Header
{
public:	
	CString name;
	CString time_stamp;
	CStringArray author;
	CStringArray organization;
	CString preprocessor_version;
	CString originating_system;
	CString authorisation;
};

#ifndef APL_NO_INSET_IN_DOC
void AFX_EXT_API aplAppendBufValue(CaplDataBuf &data, CaplMap &inst_map, CaplValue *value);
void AFX_EXT_API aplAppendBufValue(CaplDataBuf &data, TInstIntMap *inst_map, CaplValue *value);
bool AFX_EXT_API aplReadValueFromBuf(CaplDataBuf &dbuf, pCaplInstance *instmap,CaplValue *value, bool bUseExternalString = false);
void AFX_EXT_API aplAddInstValToExtent(aplExtent &ext, CaplValue *value);
void AFX_EXT_API GetNameType(aplValueType type, CString &name);
CString AFX_EXT_API GetNameType(aplValueType type);
CString AFX_EXT_API GetNameAccess(aplAccessModeType access, bool is_rus=true, bool print_not_def=true, bool case_first=true);
#endif

/**@name  Сортировка extent*/
//@{
/**Сортирует ext по возрастанию значений (CaplInstance *)*/
//void AFX_EXT_API qSortExtent(aplExtent &ext); рекомендуется заменить на CSortClass::SortExtentByInst
/**Сортирует ext по возрастанию системных обозначений*/
//void AFX_EXT_API qSortExtentById(aplExtent &ext); рекомендуется заменить на CSortClass::SortExtentById

#ifndef APL_NO_INSET_IN_DOC

/////////////////////////////////////////////////////////////////////////////
// CSortClass 
/** Функции сортировки экстентов и массива instances*/
class AFX_EXT_CLASS CSortClass{
public:
	int static CompareInstId( const void *p1, const void *p2);
	int static CompareInst( const void *p1, const void *p2);
	int static CompareInstType( const void *p1, const void *p2);
	void static SortExtentById(aplExtent &ext);
	void static SortExtentByInst(aplExtent &ext);
	// в будущем надо отовсюду вычистить SortInstBy.. и заменить на SortExtentBy..
	void static SortInstById(aplExtent &instances){return SortExtentById(instances);}
	void static SortInstByInst(aplExtent &instances){return SortExtentByInst(instances);}
	void static MakeExtUnique(aplExtent &ext, bool remove_zero=false);
	void static SortArrayById(pCaplInstance **instmap, int instmapsize);
	void static SortArrayByInst(pCaplInstance **instmap, int instmapsize);
	void static SortExtentByType(aplExtent &ext);
};

#endif



/////////////////////////////////////////////////////////////////////////////
// CRedirect 
/** Класс для запуска внешнего процесса с перехватом его потоков stderr и stdout */
#ifdef _MFC_VER

class AFX_EXT_CLASS CRedirect
{
	// Construction
public:
	CRedirect();
	~CRedirect();

	BOOL StartChildProcess(LPCTSTR _CmdLine, LPCTSTR _Parameters, BOOL bShowChildWindow = FALSE, bool wrap_in_bat = true);
	BOOL StartChildProcessEx(LPCTSTR _CmdLine, LPCTSTR _Parameters);	

	BOOL IsChildRunning() const;
	void TerminateChildProcess();
	void WriteChildStdIn(LPCTSTR lpszInput);

	bool SetApplicationLevelFunctions(bool (__cdecl *_ApplicationLevelInit)(),bool (__cdecl *_ApplicationLevelIsBreak)(),bool (__cdecl *_ApplicationLevelLogMessageDlg)(LPCTSTR message));

	bool m_convert_from_UTF8;
	// Child process exit code
	DWORD m_dwExitCode; 

	BOOL IsRunned();

protected:
	CaplDataBuf m_dbuf_portions;

	HANDLE m_hExitEvent;

	// Child input(stdin) & output(stdout, stderr) pipes
	HANDLE m_hStdIn, m_hStdOut, m_hStdErr;
	// Parent output(stdin) & input(stdout) pipe
	HANDLE m_hStdInWrite, m_hStdOutRead, m_hStdErrRead;
	// stdout, stderr write threads
	HANDLE m_hStdOutThread, m_hStdErrThread;
	// Monitoring thread
	HANDLE m_hProcessThread;
	// Child process handle
	HANDLE m_hChildProcess;
	// Child process main thread id
	DWORD dwThreadId; 

	bool (__cdecl *m_ApplicationLevelInit)();
	bool (__cdecl *m_ApplicationLevelIsBreak)();
	bool (__cdecl *m_ApplicationLevelLogMessage)(LPCTSTR message);


	HANDLE PrepAndLaunchRedirectedChild(LPCTSTR lpszCmdLine,
		HANDLE hStdOut, HANDLE hStdIn, HANDLE hStdErr,
		BOOL bShowChildWindow);

	static BOOL m_bRunThread;
	static int staticStdOutThread(CRedirect *pRedirect)
	{ return pRedirect->StdOutThread(); }
	static int staticStdErrThread(CRedirect *pRedirect)
	{ return pRedirect->StdErrThread(); }
	static int staticProcessThread(CRedirect *pRedirect)
	{ return pRedirect->ProcessThread(); }
	int StdOutThread();
	int StdErrThread();
	int ProcessThread();

	void ProcessOutPortions(char* lpszBuffer, DWORD nBytesRead);

public:
	virtual void OnChildStarted(LPCTSTR lpszCmdLine);
	virtual void OnChildStdOutWrite(LPCTSTR lpszOutput);
	virtual void OnChildStdErrWrite(LPCTSTR lpszOutput);
	virtual void OnChildTerminate();
};
#endif
//@}


////////////////////////////////////////////////////////////
// классы и структуры для работы с JSON
//
/** типы значений JSON*/
enum SJsonType
{
	SJT_NOTYPE = -1,
	SJT_NULL = 0,
	SJT_STRING = 1,
	SJT_INT = 2,
	SJT_REAL = 3,
	SJT_BOOL = 4,
	SJT_OBJECT = 5,
	SJT_ARRAY = 6
};


#define CASE_2_STRING(var) case var: str.Format(_T("") _T(#var) _T(" (%i)"), var); break;

inline CString GetSJsonTypeName(SJsonType type)
{
	CString str(_T("<Неизвестно>"));
	switch(type){
		CASE_2_STRING(SJT_NOTYPE);
		CASE_2_STRING(SJT_NULL);
		CASE_2_STRING(SJT_STRING);
		CASE_2_STRING(SJT_INT);
		CASE_2_STRING(SJT_REAL);
		CASE_2_STRING(SJT_BOOL);
		CASE_2_STRING(SJT_OBJECT);
		CASE_2_STRING(SJT_ARRAY);
	}
	return str;
}


/** структура нужна при выводе в JSON инстансов, чтобы определять - какие атрибуты типа инстанс раскрывать на следующем уровне */
struct AFX_EXT_CLASS SListAttrsNextLevel
{
	SListAttrsNextLevel(){all_attrs = true;}
	bool all_attrs;
	// для REST запросов выходной JSON строится по веткам. 
	// список !имен! атрибутов и описаний поведения при выводе в JSON указанных атрибутов
	// см комментарий к функции PrintInst2Json
	CaplStrMap map_child_attrs;

	virtual aplAccessModeType GetInstAccess(CaplInstance *inst)
	{
		if(inst==0) return aplNOT_DEFINED;
		return inst->GetAccessmode();
	}
};


struct SJsonEl;
typedef std::map<CaplInstance*, int> mapOfInst;

/** объект хранит значение одного поля JSON*/
struct AFX_EXT_CLASS SJsonVal
{
	SJsonVal();
	~SJsonVal();
	void Clear(bool with_arr=true);

	void Set(const CString &val);
	void Set(LPCTSTR val);
#ifdef QSTRING_H
    void Set(const QString &val);
#endif
	void Set(int val);
	void Set(unsigned long val);
	void Set(double val);
	void Set(bool val);
	void Set(SJsonEl* val);
	void Set(SJsonEl& val);
	void Set(SJsonVal& val);
	void SetNull();

	bool Get(SJsonVal &val);
	bool Get(CString &val);
#ifdef QSTRING_H
    bool Get(QString &val);
#endif
	bool Get(int &val);
	bool Get(double &val);
	bool Get(bool &val);
	bool Get(SJsonEl &val);
	SJsonEl* GetEl();

	void AddArrayEl(int val);
	void AddArrayEl(double val);
	void AddArrayEl(bool val);
	void AddArrayEl(const CString &val);
	void AddArrayEl(LPCTSTR val);
	void AddArrayEl(SJsonEl& val);
	void AddArrayEl(SJsonVal& val);
	// Внимание! Объект по указателю val будет удален в деструкторе этого класса!
	void AddArrayEl(SJsonEl* val);
	void AddZeroArrayEl();

	void InsertArrayEl(const CString &val);

	int GetArraySize();
	bool GetArrayEl(int index, int &val);
	bool GetArrayEl(int index, double &val);
	bool GetArrayEl(int index, bool &val);
	bool GetArrayEl(int index, CString &val);
	bool GetArrayEl(int index, SJsonEl &val);
	bool GetArrayEl(int index, SJsonVal &val);

    inline SJsonVal* GetArrayEl(int index){return array.GetAt(index);}
    inline SJsonVal* GetArrayVal(int index){return array.GetAt(index);}
    inline SJsonEl*  GetArrayEll(int index)
    {
        SJsonVal* val=GetArrayVal(index);
        if(val==0 || val->GetType()!=SJT_OBJECT)return 0;
        return val->GetEl();
    }

	CString Print(int &level);
	inline SJsonType GetType(){return type;}

	void SetPos(int _json_line, int _json_pos);
	CString GetPos();

	// Вспомогательная функция; сохраняет значение атрибута в элемент JSON
	// если определен QD_curr и в нем есть список - их атрибуты разворачивает в дереве, см комментарий к PrintInst2Json
	bool PrintAttrVal2Json(CaplValue &value, CaplAttr* attr,
							SListAttrsNextLevel* QD_curr=0, pCaplInstance *instmap=0, int instmapsize=0, mapOfInst* pExported=0);

	// Читает значение jsaon из строки из строки json начиная с позиции pos
	bool GetJsonVal(const CString &json, int &pos, CString &err_str, int &line, int &pos_str);

protected:

	SJsonType type;
	union
	{
		int ival;
		bool bval;
		double rval;
		TCHAR *sval;
		SJsonEl *object; 
	};
	CaplTAggr<SJsonVal*, SJsonVal*, APLAGGR_LIST_OR_AUTOKILLREF> array;
	// если значение было прочитано из текстового JSON - здесь хранится позиция начала значения в тексте
	int json_line;
	int json_pos;
};

/** объект хранит один элемент JSON, в т.ч. корневой элемент */
struct AFX_EXT_CLASS SJsonEl
{
	friend SJsonVal;
	SJsonEl();
	~SJsonEl();
	void Clear();
	void Set(SJsonEl& el);

	bool Print(CString &report);
    inline CString Print(){CString report(_T("")); Print(report); return report;}

	void AddHeader(CaplStepData* data, bool all_dict=false);

	void AddKeyVal(LPCTSTR key, int val);
	void AddKeyVal(LPCTSTR key, unsigned long val);

	void AddKeyVal(LPCTSTR key, double val);
	void AddKeyVal(LPCTSTR key, bool val);
	void AddKeyVal(LPCTSTR key, LPCTSTR val);
	void AddKeyVal(LPCTSTR key, const CString &val);
	void AddKeyVal(LPCTSTR key, SJsonEl& val);

	void AddKeyVal(LPCTSTR key, SJsonVal& val);
	// Внимание! Объект по указателю val будет удален в деструкторе этого класса!
	void AddKeyVal(LPCTSTR key, SJsonVal* val);

	bool GetKeyVal(LPCTSTR key, CString &val);
	bool GetKeyVal(LPCTSTR key, int val);
	bool GetKeyVal(LPCTSTR key, double val);
	bool GetKeyVal(LPCTSTR key, bool val);
	bool GetKeyVal(LPCTSTR key, SJsonEl& val);
	bool GetKeyVal(LPCTSTR key, SJsonVal &val);

	inline bool CheckKeyVal(LPCTSTR key){ return key_vals.GetP(key) != 0; }
	inline SJsonVal* GetKeyVal(LPCTSTR key){ return (SJsonVal*)key_vals.GetP(key); }
    inline SJsonEl* GetKeyEll(LPCTSTR key)
    {
        SJsonVal* val=GetKeyVal(key);
        if(val==0 || val->GetType()!=SJT_OBJECT)return 0;
        return val->GetEl();
    }

	// функции и переменные для корневого элемента 
	bool flag_warning;
	void SetErrDescr(LPCTSTR text, bool flag_err);
	CString GetErrDescr(){return m_ErrDescr;}

	bool m_bNoSaveEmptyAttr; // Если установлен, то пустые атрибуты не сохраняются в файл


	void SetPos(int _json_line, int _json_pos);
	CString GetPos();

	// Функция корневого элемента JSON.
	// Сохраняет инстанс в элемент JSON и добавляет его в массив instances
	//		*) если QD_curr не задан - выводится основная информация инстанса (id, тип, доступ) и все 
	//атрибуты; атрибуты типа инстанс выводятся в кратком виде (id, тип, доступ)
	//		*) если QD_curr задан, но в нем не заполнен массив map_child_attrs и флаг all_attrs == false - для 
	//текущей инстансы выводится только основная информация
	//		*) если QD_curr задан, в нем не заполнен массив map_child_attrs и флаг all_attrs == true - выводится
	//все с атрибутами как в случае QD_curr==0
	//		*) если QD_curr задан и коллекция map_child_attrs заполнена пАрами "имя атрибута" - 
	//"указатель на объект SListAttrsNextLevel следующего уровня" - то атрибуты, имена которых есть в map_child_attrs, 
	//попадают в выходной JSON вне зависимости от флага all_attrs. При обработке инстансов из таких атрибутов 
	//на следующем уровне используются параметры, указанные в объекте SListAttrsNextLevel, указатель на который 
	//помещен в поле значения map_child_attrs 
	bool AddInst2JsonRoot(CaplInstance* inst, SListAttrsNextLevel* QD_curr,
		aplAccessModeType access=aplNOT_DEFINED, pCaplInstance *instmap = 0, int instmapsize = 0);

	// Функция корневого элемента JSON.
	// Сохраняет инстанс в элемент JSON и добавляет его в массив instances
	// Заполняет только минимальную информацию об инстансе: id, тип, индекс 
	bool AddInst2JsonRoot(CaplInstance* inst, int index);

	// Парсит JSON из строки json в структуру; корневой элемент помещает в j_el. 
	// В случае успеха возвращает true; в случае ошибки - false; описание ошибки помещает в err_str
	bool ParseText2Json(const CString &json, CString &err_str);

	// Читает инстансы и их атрибуты из структуры начинающейся с корневого элемента root_el. 
	// Прочитанные инстансы (включая новые) помещает в ext_loaded; прочитанные из json атрибуты меняются и помечаются флагом changed=true
	// Инстансы, которые надо удалить помещает в ext_4del (но не удаляет)
	// Новые инстансы (которые были созданы на клиенте, и им еще не присвоены идентификаторы) помещаются в map_index2inst (in - id_tmp пришедший с кдиента, out - указатель на CaplInstance)
	// В случае успеха возвращает true; в случае ошибки - false; описание ошибки помещает в err_str
	bool LoadInstancesFromJson(CaplStepData *data, CaplMap &map_index2inst, CString &err_str, 
										aplExtent *ext_loaded=0, aplExtent *ext_change=0, aplExtent *ext_4del=0);

	// Очищает элемент и сохраняет в него данные о словаре CaplStepData и об инстансах из ext
	bool SaveExtent2Json(CaplStepData *data, aplExtent &ext, bool save_temporary=false);

	inline bool IsEmpty(){return key_vals.GetSize()==0;}
	inline void GetAllKeys(CStringArray &keys){ for(int i=0;i<key_vals.GetSize();i++) keys.Add(key_vals.GetAt(i)->str); }

	// Флаги, управляющие выгрузкой инстансов в Json
	// Не выгружать атрибуты инстансов
	static SListAttrsNextLevel* flag_QD_no_attrs;
	// Выгружать атрибуты инстансов только на текущем урорвне и не выгружать на следующих уровнях
	static SListAttrsNextLevel* flag_QD_single_level_attrs;
	// Выгружать все непустые атрибыт; инстансы выгружать в виде вложенного дерева
	static SListAttrsNextLevel* flag_QD_all_attrs_in_tree;

protected:

	struct JSNStrVal{
		JSNStrVal(LPCTSTR _str, SJsonVal* _val){str=_str;val=_val;}
		CString str;
		SJsonVal* val;
	};

	CaplStrMap key_vals;
	CaplTAggr<JSNStrVal*, JSNStrVal*, APLAGGR_UNIQUE_LIST_AUTOKILLREF> key_vals_order;

	CaplInstance* ReadAttrInst(CaplStepData *data, SJsonVal *p_val, CaplMap & map_index2inst, bool is_putattr, CString & err_str, 
											aplExtent *ext_loaded, aplExtent *ext_change, aplExtent *ext_4del);

	bool PrintInternal(CString &report, int &level);

	// Функция сохраняет инстанс в элемент/дерево JSON
	//		*) если QD_curr не задан - выводится основная информация инстанса (id, тип, доступ) и все 
	//атрибуты; атрибуты типа инстанс выводятся в кратком виде (id, тип, доступ)
	//		*) если QD_curr задан, но в нем не заполнен массив map_child_attrs и флаг all_attrs == false - для 
	//текущей инстансы выводится только основная информация
	//		*) если QD_curr задан, в нем не заполнен массив map_child_attrs и флаг all_attrs == true - выводится
	//все с атрибутами как в случае QD_curr==0
	//		*) если QD_curr задан и коллекция map_child_attrs заполнена пАрами "имя атрибута" - 
	//"указатель на объект SListAttrsNextLevel следующего уровня" - то атрибуты, имена которых есть в map_child_attrs, 
	//попадают в выходной JSON вне зависимости от флага all_attrs. При обработке инстансов из таких атрибутов 
	//на следующем уровне используются параметры, указанные в объекте SListAttrsNextLevel, указатель на который 
	//помещен в поле значения map_child_attrs 
	bool PrintInst2Json(CaplInstance* inst, SListAttrsNextLevel* QD_curr = SJsonEl::flag_QD_single_level_attrs,
		aplAccessModeType access=aplNOT_DEFINED, pCaplInstance *instmap = 0, int instmapsize = 0, mapOfInst* pExported = 0);

	bool ParseText2JsonInternal(const CString &json, int &pos, CString &err_str, int &line, int &pos_str);

	CaplInstance* LoadInstFromJsonInternal(CaplStepData *data, CaplMap &map_index2inst, bool putattr_inst, CString &err_str,
					aplExtent *ext_loaded, aplExtent *ext_change, aplExtent *ext_4del);

	// если элемент был прочитан из текстового JSON - здесь хранится позиция начала элемента в тексте
	int json_line;
	int json_pos;
	CString m_ErrDescr;
};


// Задает функцию создания инстанса при разборе JSON в сервере oracle/postgre
// Особая функция нужна для правильной индексации нового инстанса в оракловом/постгресном сервере
void AFX_EXT_API SetJsonCreateInst(CaplInstance* (*_ExtCreateInstance)(CaplStepData* data, CaplEntity *ent, apl_id id, CaplInstance* ext_inst));

//@}




/**@name  Функции расчета СRC32*/
//@{

/** Обновляет значение CRC32 для байта данных
	 алгоритм расчета :
	long crc32=-1; while() crc32=UpdateCRC32(BYTE[i],crc32); crc32=~crc32;*/
inline UINT32 AFX_EXT_API UpdateCRC32(char c, UINT32 crc);

/** Возращает значение CRC32 для блока данных data размером size или -1 при неверных входных данных */
UINT32 AFX_EXT_API GetCRC32(char *data, int size);

/** Возращает значение CRC32 для файла с именем file_name или -1 при неверных входных данных
	при bInteractive=true на время подсчета меняет состояние курсора на wait*/
UINT32 AFX_EXT_API GetFileCRC32(LPCTSTR file_name, bool bInteractive=true);

//@}

/**@name  Функции расчета хеш-суммы «Стрибог» по ГОСТ 34.11—2012
	Сделано на основе материалов и исходников статьи https://xakep.ru/2016/07/20/hash-gost-34-11-2012/
	с убыстрениями почерпнутыми из других источников
	*/
//@{

/** Вычисляет хеш-сумму по алгоритму «Стрибог» по ГОСТ 34.11—2012 для произвольного блока данных data длиной size.
 *	Возвращает строку с хеш-суммой
	В переменной hash_size задается размер хэш-суммы 512 (по умолчанию) или 256
	*/
CString AFX_EXT_API GetHashString_Stribog(const char *data, int size, int hash_size = DEFAULT_HASH_SIZE);

/** Вычисляет хеш-сумму по алгоритму «Стрибог» по ГОСТ 34.11—2012 для файла file_name.
	В случае успеха возвращает true и помещает хэш в переменную hash.
	В случае ошибки возвращает false и помещает описание ошибки в переменную hash
	В переменной hash_size задается размер хэш-суммы 512 (по умолчанию) или 256
*/
bool AFX_EXT_API GetHashFile_Stribog(LPCTSTR file_name, CString& hash, int hash_size = DEFAULT_HASH_SIZE);

// Вычисляет хеши файлов по алгоритму ГОСТ 34.11-2012 Стрибог и сохраняет их в строку в формате xml
// Параметры:
//		list_params - список шаблонов для определения имен файлов, в каждой строке - один шаблон. Шаблон может
//	быть оносительным или абсолютным (абсолюные пути начинаются с буквы диска для windows или с разделителя для
//	linux; остальные пути считаются относительными). Оносительные пути могут содержать пути к подкаталагам.
//	В шаблонах можно использовать символ * для обозначения любой группы символов. Для поиска файлов без расширения
//	можно использовать шаблон *.
//		out_xml - строка, в которую будет помещен xml с хешами файлов
//		hash_size - размер хеш суммы - 256 или 512 ьит. Если укзаано другое значение - используется значение по
//	умолчанию 512 бит.
//		version - строка с версией. Если задана - будет помещена в xml с хешами файлов
//		start_dir - каталог, в котором будут читаться файлы заданные в list_params и от которого будут вычисляться
//	относитиельне пути. Если не задан - используется текущий рабочий каталог
//		checkTime - если true, то для каждого хеша сохраняется время его вычисления;
bool AFX_EXT_API CalculateFilesHashes(CStringArray &list_params, CString &out_xml, int hash_size = DEFAULT_HASH_SIZE,
						LPCTSTR version = _T(""), LPCTSTR _start_dir = _T(""), bool checkTime = false, bool printInfo = true);


//@}

void AFX_EXT_API aplValue2String(aplValueType type, CString &str);
aplValueType AFX_EXT_API String2aplValueType(LPCTSTR type_name);

// Работа с датами
/** Преобразует дату в строку*/
bool AFX_EXT_API aplDate2String(COleDateTime &time, CString &buf);

// Функция преобразовывает макросы __DATE__ и __TIME__ в стандартный формат
COleDateTime AFX_EXT_API aplBuildDateTime2Odt(const char* __date__, const char* __time__);

#ifdef _MFC_VER
/** Преоброазование дат в строку для ILS(LSS3)*/
bool AFX_EXT_API aplDate2String(time_t &rawtime, CString &buf);
bool AFX_EXT_API aplDate2String64(INT64 &i64Time, CString &buf, bool NullifyTime = false);
/** Преобразование даты в формате ISO 8601 в текстовой вид */
bool AFX_EXT_API aplDateISO8601ToString(const CString& sISO, CString& res, bool bFormatLSS3 = false);
bool AFX_EXT_API aplDate2ISO8601(const CString& sDate, CString& sISO);
#endif

/** Преобразует строку в дату*/
bool AFX_EXT_API aplString2Date(CString &buf, COleDateTime &time);

#ifdef _MFC_VER
/** Преобразует строку в дату и потом в строку вида ДД.ММ.ГГГГ*/
bool AFX_EXT_API aplString2Date2String(CString &buf);
/** Преобразует строку в дату и потом в строку вида ДД.ММ.ГГГГ ЧЧ:ММ:СС*/
bool AFX_EXT_API aplString2DateTime2String(CString &buf);
/** Преоброазование строк в дату для ILS(LSS3)*/
bool AFX_EXT_API aplString2Date(CString &buf, time_t &time);	//Не понимает даты раньше 1.1.1970
bool AFX_EXT_API aplString2Date64(CString &buf, INT64 &i64Time);
#endif

#ifdef _MFC_VER
/** Функция для автоматического обновления - парсит файлы *.luf из каталога _folder_luf и выдает список соответствующих файлов из каталога _folder_files */
bool AFX_EXT_API aplReadFiles4AutoUpdate(LPCTSTR _folder_files, LPCTSTR _folder_luf, CStringArray &list_upd_files, bool bInteractive, CString &err_mes);
/** Функция для автоматического обновления - рекурсивно обходит директории и возвращает их список */
void AFX_EXT_API aplRecursiveGetDirs(LPCTSTR startdir, LPCTSTR mask, CStringArray &sArrayMasks);
#endif


/** Функция переводит сообщение об ошибке чтения словаря на русский язык*/
void AFX_EXT_API aplTranslateDictErrorMessages(CString &description, bool remove_line_break = true);

#endif
