#if !defined(AFX_aplNetStepData_H__53498523_74F0_11D3_B380_00C026EE2281__INCLUDED_)
#define AFX_aplNetStepData_H__53498523_74F0_11D3_B380_00C026EE2281__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// aplNetStepData.h : header file
//

// 1.0.1
// 1.1.0  5.10.2000 Изменение схемы работы с удаленными Inst

#include <afxwin.h>
#include <list>
#include <StepData.h>
#include "MiddleWare.h"
#include <aplStepQL.h>

// #include "TransportSocketClient.h"

#ifdef APL_NSD_IMPL
#define CLASS_DECL_APL_NSD  _declspec(dllexport)
#else
#define CLASS_DECL_APL_NSD  _declspec(dllimport)
#endif


#ifndef APL_NET_STEP_DATA_NOAUTOLIB
#ifdef _DEBUG
#ifdef UNICODE
#pragma comment (lib,"CaplData_ud.lib")
#pragma comment (lib,"AplTransportClient_ud.lib")
#else
#pragma comment (lib,"CaplDataD.lib")
#pragma comment (lib,"AplTransportClientD.lib")
#endif
#else
#ifdef UNICODE
#pragma comment (lib,"CaplData_u.lib")
#pragma comment (lib,"AplTransportClient_u.lib")
#else
#pragma comment (lib,"CaplData.lib")
#pragma comment (lib,"AplTransportClient.lib")

#endif
#endif
#endif

extern CString global_name_ini;

typedef CArray<int,int> TListInt;

class CaplNetStepData;
class aplUsers;
class aplAccessEl;
class aplAccessList;
class CTransportSocketClient;
class CaplQLQueryParse;

#ifndef APL_NO_INSET_IN_DOC

class CConnectInfo{
public:
	CConnectInfo(){Clear();}
	int id;
	CString name;
	CString comp_name;
	// 0 - наш проткол
	// 1 - http
	int protocol;
	int port;
	CString base_name;
	CString def_user_name;
	// если протокол http и прокси явно не задан - то используется системный прокси из настроек IE
	CString proxy;

	void Clear(){id=-1;port=7239; protocol = 0;proxy = _T("");def_user_name = _T("");}
	void Set(CConnectInfo *cif)
	{
		if(cif== 0){Clear();return;}
		id=cif->id;
		protocol=cif->protocol;
		port=cif->port;
		name=cif->name;
		comp_name=cif->comp_name;
		base_name=cif->base_name;
		def_user_name=cif->def_user_name;
		proxy=cif->proxy;
	};
	bool IsEqu(CConnectInfo *cif)
	{
		if(0==cif) return false;
		return (name==cif->name && comp_name==cif->comp_name && port==cif->port 
			&& base_name==cif->base_name && def_user_name==cif->def_user_name
			&& protocol==cif->protocol && proxy==cif->proxy);
	};
};

#endif

// поведение диалога при установке соединения
#define CONNECT_DLG_MODE__SUPRESS -1
#define CONNECT_DLG_MODE__ONLY_ERROR 0
#define CONNECT_DLG_MODE__SHOW_ALVAYS 1


/** Проверяет доступность указанного сервера*/
BOOL AFX_EXT_API ClientPing(LPCTSTR strHost);

/** Возвращает описание ошибки 
	@param res код ошибки
	@param buf буфер, в который записывается описание ошибки
	@return указатель на буфер buf*/
LPTSTR AFX_EXT_API HRESULT2char(HRESULT res, LPTSTR* buf);

/** Возвращает описание ошибки сервера или клиента PSS
	@param res код ошибки
	@return указатель на буфер buf*/
CString AFX_EXT_API APL_NET_ERROR2char(int error, CString add_text=_T(""));

// Выводит строчку в лог приложения - с именем совпадающим с именем exe-модуля и расширением log
void AFX_EXT_API APL_NET_LogMessage(LPCTSTR message);

/** Вызывает принудительную обработку сообщений от таймера и перерисовки
	*/
void AFX_EXT_API PumpTimerPaint();

/// 
bool AFX_EXT_API GetVersionClient(CString *version = 0);
/// имя приложения, из которого создан объект CaplNetStepData
CString AFX_EXT_API GetAppName();

/// Имя ini файла (с путем), из которого читаются настройки.
/// Заполняется при первом создании объекта CaplNetStepData
CString AFX_EXT_API GetIniFullName();

/// имя каталога, в котором хранятся настройки приложений (путь включает завершающюю косую черту)
/// путь к каталогу хранится в ini (группа Paths параметр ClientSettingsPath), по 
/// умолчанию - каталог из которого был запущен exe
CString AFX_EXT_API GetPathSetting();

/** Отображает диалог с таблицей всех шаблонов доступа (инстанс типа apl_access_pattern); позволяет выбрать шаблон доступа
@param data указатель на экземпляр класса для работы с БД
@param curr_pattern текущий выделенный шаблон доступа
@param bPressOk - была ли нажата кнопка OK. Без этого невозможно отличить нажатие Cancel от выбора "<Шаблон доступа не задан>"
@return выбранный шаблон доступа или 0 если шаблон не был выбран (нажата кнопка Cancel)*/
CaplInstance AFX_EXT_API *SelectAccessPatternC(CaplNetStepData *data, CaplInstance *curr_pattern = 0, bool *bPressOk = NULL);

/** Отображает диалог с таблицей всех шаблонов доступа (инстанс типа apl_access_pattern); позволяет создавать, изменять, удалять шаблоны доступа
@param lpParameter указатель на экземпляр класса для работы с БД, приведенный к типу LPVOID
@param IsUsed call-back функция, которая определяет, используется ли шаблон в системе назначения доступа (например, в опциях, специфичных
для приложения). Если шаблон используется и его нельзя удалять, функция должна возвращать true и записывать во второй параметр имя опции, в
которой используется шаблон; в таком случае диалог заблокирует удаление выделенного шаблона. Если функция вернет false - шаблон не используется
и его можно удалять.
Определение call-back функции:
bool IsUsed(CString &pattern_name, CString &option_used);
где pattern_name  - имя шаблона (значение атрибута name инстансы типа apl_access_pattern)
	option_used - имя опции, в которой используется шаблон
*/
void AFX_EXT_API EditAccessPatternC(LPVOID lpParameter, bool ( *IsUsed)(CString &, CString &) = 0, double add_param = 0);


// Режим записи лог функцией 
typedef enum {aplLogModeNo=0, aplLogModeError=1, aplLogModeWarning=2, aplLogModeInfo=3, aplLogModeVerbose=4, aplLogModeDebug=5, aplLogModeParanoid=6  } aplLogMode;


//Размер единицы информации при операциях с BLOB
#define SIZE_DOSE_BLOB 1024*1024
#define SIZE_DOSE_BLOB_HTTP 1024


typedef CaplTAggr <apl_NET_LoadQuery*, apl_NET_LoadQuery*, APLAGGR_AUTOKILLREF> TAKQueriesAggr;

CString AFX_EXT_API MakeSourceDescr(CString file, int line, CString date);

#define DEF_SOURCE MakeSourceDescr(_T(__FILE__), __LINE__, _T(__DATE__))

/** Вспомогательный класс, предназначен для входа в AdminMode и гарантированного выхода из него*/
class CLASS_DECL_APL_NSD CaplAdminModeProvider
{
public:
	/** Конструктор
	@param 
	@param _username имя пользователя находящегося в группе администраторов. 
	@param _pwd пароль пользователя
	$param _source строчка, описывающая место вызова запроса. В это поле рекомендуется стаимть макрос DEF_SOURCE
	*/
	CaplAdminModeProvider(CaplNetStepData *data, LPCTSTR _username, LPCTSTR _pwd, LPCTSTR _source);
	/** Конструктор
	@param 
	@param code1 код доступа, выдается клиенту по запросу
	@param code2 код доступа, выдается клиенту по запросу
	$param _source строчка, описывающая место вызова запроса. В это поле рекомендуется стаимть макрос DEF_SOURCE
	*/
	CaplAdminModeProvider(CaplNetStepData *data, int code1, int code2, LPCTSTR _source);

	/** Пустой конструктор, ничего не делает*/
	CaplAdminModeProvider(); 

	~CaplAdminModeProvider();

	/** Переводит соединение в режим администратора 
	@param _username имя пользователя находящегося в группе администраторов. 
	@param _pwd пароль пользователя
	@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool StartAdminMode(LPCTSTR _username, LPCTSTR _pwd, LPCTSTR _source);


	/** Переводит соединение в режим администратора 
	@param code1 код доступа, выдается клиенту по запросу
	@param code2 код доступа, выдается клиенту по запросу
	@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool StartAdminMode(int code1, int code2, LPCTSTR _source);
	
	/** Переводит соединение из режима администратора в нормальный режим
	*/
	bool ExitAdminMode();	

	void SetData(CaplNetStepData *data){m_data=data;};

protected:
	/** Иcточник данных*/
	CaplNetStepData* m_data;
	CString m_source;
	bool m_my_admin;
};

/** Структура для компактной записи цепочек запросов типа 'd' и 'r' 
    (см комментарий к функции NET_LoadExtAttrPaths)
*/
struct AttrPath
{
    /**
     * @brief AttrPath Создает элемент цепочки. Допустимы подзапросы типов 'd' и 'r'.
     * @param _attr Для подзапроса типа 'd' прямой атрибут. Для 'r' обратный атрибут
     * @param _ent Для подзапроса типа 'd' не используется. Для 'r' энтити, которая ссылается атрибутом attr
     * на инстансы предыдущего запроса
     * @param _type Тип подзапроса. Допустимы подзапросы типов 'd' и 'r'.
     * @param _next_step Набор элементов следующего шага цепочки. Если _next_step пустой, и текущий атрибут
     * типа aplINSTANCE, то будут загружены значения всех атрибутов. Для остальных типов атрибутов
     * будет загружено только само значение атрибута.
     */
	AttrPath(CaplAttr* _attr, CaplEntity* _ent=0, TCHAR _type=_T('d'), std::list<AttrPath> _next_step=std::list<AttrPath>())
	{
		attr=_attr, ent=_ent, type=_type, next_step=_next_step;
	}

#ifdef _UNICODE
	/** Перегруженная функция, чтобы в юникодных проектах не писать каждый раз макроc _T() в типе запроса  */
	AttrPath(CaplAttr* _attr, CaplEntity* _ent, char _type, std::list<AttrPath> _next_step=std::list<AttrPath>())
	{
		attr=_attr, ent=_ent, type=static_cast<TCHAR>(_type), next_step=_next_step;
	}
#endif // #ifdef _UNICODE

	CaplAttr* attr;
	CaplEntity* ent;
	TCHAR type;
	std::list<AttrPath> next_step;
};



/** Вспомогательный класс, предназначеный для создания, проверки корректности и передачи на выполнение запросов, загружающих информацию в кеш базы данных*/
class CLASS_DECL_APL_NSD CaplLoadData 
{
/**@name Типы запросов
	<B>"a"</B> - добавление самого <B>instance</B> в список результатов
	<B>"e"</B> - вернуть список всех <B>instance</B> заданного типа (запрос экстента) <BR>
	<B>"i"</B> - вернуть значение аттрибута у известной <B>instance</B> (прямой запрос) <BR>
	<B>"b"</B> - вернуть список <B>instance</B>, ссылающихся указанным атрибутом на заданный <B>instance</B> (обратный запрос) <BR>
	<B>"d"</B> - вернуть список значений аттрибута у <B>instance</B>, определенных предыдущим запросом (прямой запрос по предыдущему запросу) <BR>
	<B>"r"</B> - вернуть список <B>instance</B>, ссылающихся указанным атрибутом на все <B>instance</B>, определенные предыдущим запросом (обратный запрос по предыдущему запросу) <BR>
	<B>"u"</B> - добавить подзапрос к виртуальной группе подзапросов
	Подробнее см. документ "Общие сведения о PSS API" ("Программы\PDM STEP Suite\Документация по API") раздел "Использование CaplLoadData"
*/

public:
	/** Конструктор 
	@param  data  указатель на класс кеша базы данных
	$param _source строчка, описывающая место вызова запроса. В это поле рекомендуется стаимть макрос DEF_SOURCE
	*/
	CaplLoadData(CaplNetStepData *data);
	CaplLoadData(CaplNetStepData *data, CString _source);
	virtual ~CaplLoadData();

	/** Иcточник данных*/
	CaplNetStepData* m_data;
	/** массив запросов для LoadEx*/
	TAKQueriesAggr m_queries;
	CaplNetStepData* m_placement;
	//
	CString source;

	bool IsQueryNotEmpty(){return m_queries.GetSize()>0;}

	//Расширенные функции работы с запросами
	/**	Очищает  массив запросов*/
	bool ClearQuery();
	/** добавление запроса произвольного типа по идентификаторам объектов
		@param _type тип запроса
		@param _inst_or_id идентификатор <B>instance</B> или номер предыдущего запроса
		@param _ent_id идентификатор <B>entity</B>
		@param _attr_id идентификатор атрибута
		@param _in_result передавать ли результат выполнения запроса на клиента
		@param load_all_attrs загрузить все аттрибуты всех полученных в результате запроса <B>instance</B>
		@return номер запроса в списке запросов*/

	int AddQuery(TCHAR _type, long _inst_or_id, long _ent_id, long _attr_id, bool _in_result, bool _load_all_attrs = false);
	/** добавление запроса произвольного типа по именам объектов
		@param _type тип запроса
		@param _inst_or_id идентификатор <B>instance</B> или номер предыдущего запроса
		@param ent_name имя <B>entity</B>
		@param attr_name имя атрибута
		@param _in_result передавать ли результат выполнения запроса на клиента
		@param load_all_attrs загрузить все аттрибуты всех полученных в результате запроса <B>instance</B>
		@return номер запроса в списке запросов*/
	int AddQuery(TCHAR _type, long _inst_or_id, LPCTSTR ent_name, LPCTSTR attr_name, bool _in_result, bool _load_all_attrs = false);

	/** добавление запроса произвольного типа по указателям на объекты
		@param _type тип запроса
		@param _inst_or_id идентификатор <B>instance</B> или номер предыдущего запроса
		@param ent указатель на класс <B>entity</B>
		@param attr указатель на класс атрибута
		@param _in_result передавать ли результат выполнения запроса на клиента
		@param load_all_attrs загрузить все аттрибуты всех полученных в результате запроса <B>instance</B>
		@return номер запроса в списке запросов*/
	int AddQuery(TCHAR _type, long _inst_or_id, CaplEntity *ent, CaplAttr *attr, bool _in_result, bool _load_all_attrs = false);

	/** добавление запроса произвольного типа с произвольным номером запроса по указателям на объекты
		@param id номер запроса
		@param _type тип запроса
		@param _inst_or_id идентификатор <B>instance</B> или номер предыдущего запроса
		@param ent указатель на класс <B>entity</B>
		@param attr указатель на класс атрибута
		@param _in_result передавать ли результат выполнения запроса на клиента
		@param load_all_attrs загрузить все аттрибуты всех полученных в результате запроса <B>instance</B>
		@return номер запроса в списке запросов*/
	int AddQuery(int  id, TCHAR _type, long _inst_or_id, CaplEntity *ent, CaplAttr *attr, bool _in_result, bool _load_all_attrs = false);

	/** добавление запроса типа "a"
		@param inst указатель на <B>instance</B>
		@return номер запроса в списке запросов*/
	/* ЯАИ: убрано из=за неочевидности квивизны при исполь
	int AddQuery(CaplInstance *inst,bool load_all_attr = false);

	** добавление запроса типа "a" с произвольным номером запроса
		@param id номер запроса
		@param inst указатель на <B>instance</B>
		@return номер запроса в списке запросов*/
	int AddQuery(int  id, CaplInstance *inst, bool load_all_attr = false);

	/** выполнение текущего массива запросов
		@param clear_query очищать ли массив запросов
		@param ext_out указатель на список, в который будут помещены все  <B>instance</B>, найденные при выполнении текущего массива запросовю Может быть равен 0
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@param hide_error при true скрывает все сообщения об ошибках, возникшие в ходе выполнения
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool LoadEx(bool clear_query=true, aplExtent *ext_out = 0, LPCTSTR wait_text = 0, bool hide_error = false);

    /** добавление запроса типа 'd' или 'r' рекурсивно по структуре attr_path
        @param attr_path структура с деревом атрибутов, по которому надо выполнять запрос
        @return номер запроса в списке запросов*/
    int AddQuery(int  prev_id, AttrPath attr_path);

	/**	выполнение текущего массива запросов(без загрузки в CAplInstance дополнительных служебных данных: время создания/изменения, пользователь)
		@param clear_query очищать ли массив запросов
		@param ext_out указатель на список, в который будут помещены все  <B>instance</B>, найденные при выполнении текущего массива запросовю Может быть равен 0
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@param hide_error при true скрывает все сообщения об ошибках, возникшие в ходе выполнения
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool LoadExNoInstUserDataTimeInfo(bool clear_query=true, aplExtent *ext_out = 0, LPCTSTR wait_text = 0, bool hide_error = false);

	LPCTSTR GetLastErrorDescription(){return m_err_string_quer;}

	/**	Указывает стартовое значение номера запроса при его автоматическом определении*/
	void SetStartedQueryIndex(int iStartIndex = 0);
protected:
	bool TestFindId(int &id, TCHAR type, int prev_id);

	CString m_err_string_quer;
	bool m_critical_err;
	CaplMap m_used_id;

	int		m_iStartQueryIndex;
};


// Структура поля данных. Назначение: передать серверу тип поля данных и вернуть обратно клиенту полученные данные по полю
struct SaplSQLResult
{
	SaplSQLResult() : field(_T("")), type(aplNOTYPE) {}
	SaplSQLResult(const SaplSQLResult& item) 
	{ 
		field = item.field;
		type = item.type;
		values.Append(item.values);
	}
	CString field; // имя поля. Служит для отладочно-вспомогательных целей
	aplValueType type; // тип поля (IN)
	CaplTAggr<CaplValue*, CaplValue*,APLAGGR_LIST_OR_AUTOKILLREF> values; // таблица результатов (OUT)
};

// Структура описание файла с сервера для автообновления
struct SaplFileDescr
{
	SaplFileDescr(){name = _T(""); crc32 = 0;}
	CString name; 
	CFileStatus fstatus;
	UINT32 crc32;
};

// Только для версии под Oracle и PostgreSQL!
// Структура-описатель ошибки ORACLE
struct SaplSQLError
{
	SaplSQLError(){Clear();}
	void Clear(){m_LastErrDescr = _T(""); m_err_offset = 0; m_err_code = 0; m_missed_field=-1;}
	CString m_LastErrDescr; // описание ошибки
	int m_err_offset;	// позиция ошибки в SQL
	int m_err_code;		// идентификатор ошибки (номер ошибки ORACLE)
	int m_missed_field;	// номер поля, при привязке которого возникла ошибка или -1 если ошибка не связана с каким-то полем
};
 
typedef CArray<__int64,__int64> C__int64Array;

class CDlgLogin;
class CDlg4Log;
class CDlgTuneListConnections;
class CDlgTuneConnection;
class CaplParentWndProcesser;
class CaplQLQueryParse;
/////////////////////////////////////////////////////////////////////////////
// CaplNetStepData 
class CLASS_DECL_APL_NSD CaplNetStepData : public CaplStepData
{
	friend CDlgLogin;
	friend CDlg4Log;
	friend CDlgTuneListConnections;
	friend CDlgTuneConnection;
	friend CaplLoadData;
	friend CaplAdminModeProvider;
	friend CaplParentWndProcesser;
	friend CaplQLQueryParse;
	friend CTransportSocketClient;
// Construction
public:

	// структура фильтра, используемого для запроса истории коннекта пользователей
	struct QUL_Filter
	{
		QUL_Filter()
		{
			AUSId = 0;
			user_id = 0;
			admin_user_id = 0;
			date_beg_1 = _T("");
			date_beg_2 = _T("");
			date_end_1 = _T("");
			date_end_2 = _T("");
			status=100;
			ip_cli =  _T("");
			ip_srv =  _T("");	
			ver_cli = _T("");
			ver_srv = _T("");		
			module_name = _T("");
			time_connect = _T("");
		}

		int AUSId;
		int user_id;
		int admin_user_id;
		CString date_beg_1;
		CString date_beg_2;
		CString date_end_1;
		CString date_end_2;
		//exit_status: -1 else work; 0 successful; 1 crash of client; 2 crash of server; 3 stopping server
		// если не надо искать по этому полю - 100
		int status;
		CString ip_cli;
		CString ip_srv;	
		CString ver_cli;
		CString ver_srv;		
		CString time_connect;
		CString module_name;
	};

	/// Конструктор
	CaplNetStepData();
	virtual ~CaplNetStepData();

	CString m_class_info;

	static aplLogMode g_CurLogMode;

	CTransportSocketClient* m_AplTransport;
	bool m_IsWaitDlg;
	// не сверять доступ с БД при установке доступа и т.п.
	bool m_check_access_from_server;
	// если true - загружать информацию о apl_access_agent каждый раз с сервера
	bool m_load_access_agent_from_serv;
	//определение ip адреса машины клиента (только если установлено соединение с сервером!)
	UINT32 GetCompIp();
	//определение имени машины клиента (только если установлено соединение с сервером!)
	bool GetCompName(CString &name);
	/** Возвращает версию, тип сервера и идентификатор сессии в БД
		@param version в эту переменную записывается версия сервера приложений (читается из pss*.ver)
		@param type в эту переменную записывается тип сервера приложений. Возможные варианты: _T("LITE"), _T("ORACLE"), _T("POSTGRES")
		@param ServerAUSessionId в эту переменную записывается идентификатор текущей сессии PSS
		@param ClassSrv в строку записывается класс сервера приложений: MSVC|QT, win|linux, dev|stable
		@return всегда true*/
	bool GetVersionServer(CString &version, CString &type, long *ServerAUSessionId = 0, CString *ClassSrv=0);

	bool m_AutoStartSrv;

	// Таймер не дает слишком часто запрашивать с сервера список пользователей и групп
	CaplTimeMeter m_last_read_users_timer;
	// Переменные для оптимизации приложений. Показывают количество вызовов функций чтения и сохранения данных
	DWORD m_num_load; // количество вызовов NET_Load
	DWORD m_num_save; // количество вызовов NET_SaveChanges
	DWORD m_num_find; // количество вызовов NET_FindInstancesWithAttrValues
	DWORD m_num_find_local_cache; // количество вызовов FindInstancesWithAttrValuesInLocalCache
	DWORD m_num_query; // количество вызовов NET_QueryExecute и NET_QueryExecuteEx
	DWORD m_num_run_sql; // количество вызовов NET_RunSql
	DWORD m_num_run_sql_re; // количество вызовов NET_RunSqlReturnExtent

	// Только для версии под Oracle и PostgreSQL!
	// Возвращает номер таблицы в которой хранятся атрибуты entity.
	int GetTable4Entity(CaplEntity* entity);
	
	// перегружаем родительскую функцию - чтобы в админ моде собирать экстенты
	bool ApploadFromDataBuf(CaplDataBuf &dbuf, aplExtent *ext_inst = 0);

	// Перегружаем создание и удаление инстансов - чтобы контролировать типы
	/** Создает instance по ссылке на entity*/
	virtual CaplInstance  *CreateInstance(CaplEntity *entity, bool is_temporary = false, bool create_attrs = true);
	/** Создает instance по имени entity*/
	virtual 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> в случае ошибки */
	virtual bool DeleteInstance(CaplInstance *inst, bool bChekReference = true, bool bNoSetChanged = false);
	virtual bool DeleteInstanceForced(CaplInstance *inst);


	CaplEntity* m_ent_apl_workgroup;
	CaplEntity* m_ent_apl_access_agent;
	CaplEntity* m_ent_apl_user;

	CaplAttr *m_attr_apl_user__name;
	CaplAttr *m_attr_apl_user__pass;
	CaplAttr *m_attr_apl_user__grop;
	CaplAttr *m_attr_apl_user__pers;

	CaplEntity* m_ent_apl_access_pattern;

	CaplAttr* m_attr_apl_acc_pat__name;
	CaplAttr* m_attr_apl_acc_pat__pattern;


	CaplEntity* m_ent_person_and_org;
	CaplAttr *m_attr_person_and_org__pers;

	CaplEntity* m_ent_person;
	CaplAttr *m_attr_person__last_name;
	CaplAttr *m_attr_person__first_name;
	CaplAttr *m_attr_person__middle_names;

	CaplEntity* m_ent_apl_GUID_access;
	CaplAttr *m_attr_apl_GUID_access__GUID;
	CaplAttr *m_attr_apl_GUID_access__access_def;
	CaplAttr *m_attr_apl_GUID_access__access_ind;
	CaplAttr *m_attr_apl_GUID_access__pattern;

	bool GetAplUserName(CaplInstance *user, CString &buf);

	CWnd* GetParentWnd() {return m_parent_wnd;};
	HWND GetParentHWND() 
	{
		CWnd* pWnd = GetParentWnd();
		if(pWnd != NULL)
		{
			return pWnd->m_hWnd;
		}
		return NULL;
	};

protected:
	CString m_NameCurrBase;
	CString m_NameCurrConnection;
	CString m_NameCurrUser;
	CString m_NameDomain;
	CaplInstance* m_CurrUser;
	CaplInstance* m_CurrAdminUser;
	CString m_FullDictName;

	CWnd* m_parent_wnd;
	void SetParentWnd(CWnd* parent_wnd);

	// указатель на окно для MessageBox-ов
	HWND m_hwnd;

	
	bool m_IsLoadedTable4Entity;

	//До 2011 года доступ уходил на сервер по пользователям. Чтобы назначить доступ пяти пользователям на одну иснтансу
	// надо было сформировать пять корневых структур у каждой из которых была структура с инстансом
	//В 2011 году был добавлен доступ поинстансово - конгевая структура инстанса и в ней пять подструктур для юзеров
	// Флаг m_IsAccessBI был нуже для совместимостью со старыми серверами
	// Флаг убран в 2019 году 
	// bool m_IsAccessBI;

	aplExtent m_SavedDeleted;
	
	CString m_VerSrv;
	CString m_TypeSrv;
	CString m_ClassSrv;
	CString m_BuildSrv;
	UINT32 m_ServerAUSessionId;

	void ZeroBDParams();

	/************************************************************************/
	/* Служебная функция.  Возвращает буфер со строкой и размер строки для передачи на сервер
	/* Если кодировка сервера сопадает с кодировкой клиента - возвращает ту же строку, что и на входе
	/* Если кодировка сервера ansi а клиента unicode - конвертирует строку в буфер temporary_buf и
	/* возвращает ссылку на него. В size_buf возвращается размер буфера в байтах
	/************************************************************************/
	inline BYTE* ConvertString2ServerEnc(LPCTSTR source, BYTE* temporary_buf, UINT32 &size_buf);
	// перекодирует сроку из кодировки сервера. При необходимости перекодировки - использует temporary_buf
	// если перекодировать не надо - возвращает указатель на исходную строку с правильным приведением типа
	inline LPCTSTR ConvertStringFromServerEnc(BYTE* source, BYTE* temporary_buf);

	int m_LoadTimeOut;
	CaplTimeMeter m_last_load_time_meter;
	apl_NET_LoadQuery *m_last_load_queries;
	int m_last_load_queries_count;
	aplExtent m_last_load_result;

	bool m_IsConnected;
	int m_Protocol; 
	bool m_NetErrorMessageMode;
	
	inline bool CanProcessed(bool check_connect, bool check_processed, LPCTSTR _add_text, LPCTSTR file, int line, LPCTSTR funct_name);

	bool ActualizeChangedAggr(CaplLoadData &ld, aplExtent &ext);

	bool CheckInstState(aplExtent *extent);

	bool m_AutoDownloadAttr;
	// Флаг указывает нужно ли считывать дополнительную служебную информацию: редактирующий пользователь и время создания/изменения instance (по умолчанию flase)
	bool m_bCanLoadInstUserDataTimeInfo;

	CString GetClassDescription();
	//Работа над ошибками
public:
	void SetAPLError(AplNetErrors res, CString add_text=_T(""), LPCTSTR file = 0, int line = 0, LPCTSTR funct_name = 0, LPCTSTR context = 0);
	void SetAPLError(SaplErrorDescription &err, LPCTSTR context = 0);
protected:
	AplNetErrors m_LastAplErrorCode;
	// в выдающихся наших менеджерах ошибки NetStepData вообще не обрабатываются, и 
	// последующие действия со StepData описание ошибки в ее m_ErrorDescription сбрасывают. Поэтому 
	// для hide-mode приложений нужно хранить именно описание APL_-ной ошибки
	CString m_AplErrorDescription;
	// размер порции для сохранения
	int m_SizePortionSavedInst;
	bool m_can_find_in_blob;

	// параметры диалога коннекта
	// bool m_lang_england; - убрано по просьбе Лобанова. Перевод будет выполняться новым механизмом через CaplTranslate.


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


	void SetUserAPLError(LPCTSTR user_error_description);

	// см описание у закоментаренного флага m_IsAccessBI
	// устарело void SetAccessBI(bool IsAccessBI){m_IsAccessBI = IsAccessBI;}

	__int64 m_loadcount_all;
	__int64 m_loadcount_unique;

	bool CanFindInBLOB();
	void SetConnectDlgLang(bool lang_england = false);

	
	typedef CaplTAggr<CString*,CString*,APLAGGR_AUTOKILLREF|APLAGGR_LIST> CStrArr;
	
	/**@name <b>Функции работы над ошибками</b> */
	//@{

	/// возвращает код последней ошибки, произошедшей при взаимодействии клиента и сервера
	AplNetErrors GetLastAplError();

	/// возвращает текстовое описание последней ошибки, произошедшей при работе StepData
	CString GetLastErrorDescription();
	/// возвращает текстовое описание последней ошибки, произошедшей при взаимодействии клиента и сервера
	CString GetLastAplErrorDescription();
	//@}


	/** Получает с сервера список баз данных
		@param comp_name имя компьютера, на котором запущен сервер
		@param port порт на котором запущен сервер
		@param protocol протокол работы. 0 - наш протокол, 1 - http
		@param proxy если протокол http - прокси, через который устанавливается соединение. Если прокси явно не задан - то используется системный прокси из настроек IE
		@param list_Db массив, в котором возвращается список БД
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_GetListDb(LPCTSTR comp_name, int port, int protocol, LPCTSTR proxy, CStringArray &BaseList);


	/**@name Функции управления соединением */
	//@{

	// Methods
	/** @brief Устанавливает соединение с сервером/БД, указанным в подключении, для указанного пользователя 
		@param _username имя пользователя. Если параметр не указан, выводится диалог с предложением ввести недостающие параметры 
		@param _pwd пароль пользователя
		@param _name_connect имя подключения, с которым устанавливается соединение. Если параметр не 
			указан, выводится диалог с предложением ввести недостающие параметры 
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При 
			пустом значении выводится сообщение по умолчанию
		@param license имя основного типа лицензии, который требуется для работы приложения. Если 
			строка не задана, используется тип лицензии "PSS"
		@param supress_dig подавляет стандартный диалог устьановки соединения.<br>
		@param load_titul_bd - не используется, оставлен для обратной совместимости
		@param _domain имя домена, которое должно отображаться в диалоге подключения в поле "домен"

		@param bIsCurrDomainUser если true, то при запуске под доменным пользователем стандартный диалог установки соединения 
			будет показан только если не задано имя подключения. Ввод логина/пароля будет заблокирован; при 
			аутентификации будет использован текущий пользователь домена. Если false, то поведение 
			определяется предыдущими флагами. Если этот флаг установлен в программе, запущеной от локального 
			пользователя, то функция а зависимости от флага supress_dig или покажет стандартный диалог 
			установки соединения, или вернет ошибку.

		При возникновении ошибок, которые требуют повторного ввода имени пользователя и т.п
		прерывает выполнение функции и возвращает false. При прочих ошибках (нет лицензий и т.п.) -
		показывает стандартное сообщение об ошибке
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_Connect(LPCTSTR _username, LPCTSTR _pwd, LPCTSTR _name_connect, LPCTSTR license = _T(""),
							 LPCTSTR wait_text = 0, bool supress_dlg = false, bool load_titul_bd = true, LPCTSTR _domain = _T(""), bool bIsCurrDomainUser = false);

	/** @brief Устаревший вариант функции подключения к БД. Функция оставлена для обратной совместимости, 
		не рекомендуется к использованию. Устанавливает соединение с сервером/БД, указанным в подключении,
		для указанного пользователя. В отличии от основной функции, тип лицензии задается числом в параметре 
		type_license.
		@param type_license типы лицензий, которые может занять приложение. Может быть любой комбинацией флагов<br>
			0	Заменяется на строчный тип PSS
			1	Заменяется на строчный тип ILS
			Другие числа не принимаются, функция возвращает ошибку "неверный тип лицензии"
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_Connect(LPCTSTR _username, LPCTSTR _pwd, LPCTSTR _name_connect, DWORD connection_type,
		LPCTSTR wait_text = 0, bool supress_dlg = false, bool load_titul_bd = true, LPCTSTR _domain = _T(""), bool bIsCurrDomainUser = false);


	/** Если соединение с сервером разорвано -  востанавливает соединение. В режиме HideMode==true возвращает ошибку
		@param asked если true - выводит запрос о необходимости восстановленимя соединения. 
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool Reconnect(bool /*asked*/ = true);

	/** @brief Устанавливает список запрашиваемых типов лицензий, которые будут заниматься модулем при подключении 
		к серверу приложений.
		Если в функции NET_Connect параметр license равен пустой строке, то для подключения будет использован 
			тип лицензий, указанный параметром licenseTypeMain; при отсутствии лицензий указанного типа подключение 
			будет невозможно.
		Если в функции NET_Connect параметр license содержит строку с именеи типа, то для подключения будет 
			использован тип лицензий указанный в параметре license, а заданный параметро licenseTypeMain 
			будет проигнорирован. 
		После успешного подключения клиент попытается захвать лицензии из списка licenseTypesAdd.
		@param[in] licenseTypeMain главный тип лицензий
		@param[in] licenseTypesAdd список запрашиваемых дополнительных типов лицензий. Строки из списка заменяют 
			собой предыдущий список запрашиваемых лицензий.
		@return true если параметр licenseTypeMain является строкой и false если параметр пустой. */
	static bool NET_LIC_SetRequestedLicenseTypes(LPCTSTR licenseTypeMain, CStringArray &licenseTypesAdd);

	/** @brief Устанавливает главный запрашиваемый тип лицензий, которые будут заниматься модулем при подключении 
			к серверу приложений, и очищает список дополнительных запрашиваемых лицензий.
		@param[in] licenseTypeMain главный тип лицензий
		@return true если параметр licenseTypeMain является строкой и false если параметр пустой. */
	static bool NET_LIC_SetRequestedLicenseTypes(LPCTSTR licenseTypeMain);

	/** Возвращает основной запрашиваемый тип лицензии, и список дополнительных запрашиваемых типов
		@param[out] licenseTypeMain
		@param[out] licenseTypesAdd список типов лицензии */
	static void NET_LIC_GetRequestedLicenseTypes(CString &licenseTypeMain, CStringArray &licenseTypesAdd);

	/** Возвращает описание основной и дополнительных запрашиваемых типов лицензии */
	static CString NET_LIC_GetRequestedLicenseTypes();
	
	/** Возвращает список типов лицензий, которые заняты в настоящий момент экземпляром класса, работающим
		с БД. Первым элементом в списке идет основной тип лицензии, последующими - дополнительные типы.
		До соединения с БД возвращается пустой список.
		@param[out] licenseTypes список типов лицензии */
	void NET_LIC_GetUsedLicenseTypes(CStringArray &licenseTypes);

	/** Возвращает описание основной и дополнительных типов лицензии, захваченных в текущий момент */
	CString NET_LIC_GetUsedLicenseTypes();
	
	/** Вызывает  на сервере приложений проверку наличия лицензии указанного типа и ее захват, если 
		есть свободные лицензии.
		@param[in] licenseType имя типа лицензий
		@return true если лицензия захвачена или была захвачена ранее, false если свободных лицензий нет.
		*/
	bool NET_LIC_TestTakeLicense(LPCTSTR licenseType);

	/** Освобождает лицензию указанного типа. Освободить можно только лополнительный тип лицензий
		@param[in] licenseType имя типа лицензий
		@return true если лицензия указанного типа была захвачена ранее как дополнительная и была успешно освобождена;
			false если лицензий указанного типа была занята как основная или не была занята ранее. */
	bool NET_LIC_FreeLicense(LPCTSTR licenseType);

	/** Задает дополнительные параметры для лицензирования разных процесов в рамках одного IP или даже
		внутри одного процесса, например, сеансов веб-сервера
		@param[in] s1 дополнительный параметр 1
		@param[in] s2 дополнительный параметр 2
	*/
	void NET_LIC_SetSeansParams(UINT32 s1, UINT32 s2 = 0);

	
	/** Переводит соединение в режим администратора 
		@param _username имя пользователя находящегося в группе администраторов. 
		@param _pwd пароль пользователя
		@param _source описание источника кода (для занесения в лог на сервере). Рекомендуем подставлять макрос DEF_SOURCE
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_StartAdminMode2(LPCTSTR _username, LPCTSTR _pwd, LPCTSTR _source);
	bool NET_StartAdminMode2(int code1, int code2, LPCTSTR _source);
	
	/** Переводит соединение из режима администратора в нормальный режим
	*/
	bool NET_ExitAdminMode();

	/** Проверяет наличие на сервере таблиц и структур для работы с именованными частями сессий
		@return <b>true</b> если таблицы и структуры есть и <b>false</b> если надо обновить словарь БД свежим Администратором БД*/
	bool NET_SessionPartTest();

	/** Начинает именованную часть сессии. В сервере приложений для Oracle/Postgre именованная часть сессии записывается в 
			таблицу session_parts (для postgre base_service.session_parts), и при сохранении истории изменения атрибутов
			в таблицу ATTR_VAL_HISTORY будет записываться идентификатор именованной части.
			Именованная часть сессии заканчивается при вызове функции NET_SessionPartEnd или при вызове NET_SessionPartStart 
			или при завершении основной сессии
		@param PartName имя именованной части сессии.
		@param SessionPartId при успехе возвращается идентификатор именованной части сессии
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SessionPartStart(LPCTSTR PartName, UINT32 *SessionPartId=0);
	/** Заканчивает именованную часть сессии. 
		@param SessionPartId при успехе возвращается идентификатор закрытой именованной части сессии
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SessionPartEnd(UINT32 *SessionPartId=0);

protected:
	int m_count_admin;
public:
	/** Внимание: для корректной работы функции требуются сервера приложений 5.780 и новее!!
		Задает время, в течении которого клиент будет не в состоянии отвечать на статусные запросы сервера. 
	По умолчанию сервер запрашивает статус клиента каждые 2 минуты, и если клеинт выполняет длительную 
	операцию (пересчет данных, импорт из файла и т.п.) и длительноре время не отвечает на статусные запросы
	сервера, то сервер считает клиента умершим и со своей стороны разрывает соединение, что приводит к
	нестабильной работе.
		Для отмены режима регулярного опроса надо прередать на сервер время, в течении которого клиент считается
	априори живым.
		@param time_in_minuts время в минутах, в течении которого клиент не смодет отвечать, но будет считаться 
	живым. После окончание этого времени клиент гарантировано должен ответить на статусный запрос сервера. 
			Особые значения: 
				0 - клиент досрочно завершил длительную обработку, выходит из режима молчания и
			готов отвечать на статусные запросы.
				-1 - время длинной операции предсказать невозможно, сервер не будет посылать статусные запросы
			до тех пор, пока клиент сам не выйдет из режима молчания.
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_BeginLongOperation(int time_in_minuts);


	bool NET_GetOraAlias(int code1, int code2, CString &alias, CString &username, CString &password);


	
	/** Разрывает соединение с сервером
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_Disconnect();

	/** Очистка данных из памяти; после очистки восстанавливает системные переменные (текущего пользователя и пр.)*/
	void ClearData();
	
	/** Удаляет словарь из памяти*/
	virtual void ClearDict();

	/** Определяет, установлено ли соединение с базой данных 
		@return <b>true</b> если соединение установлено, <b>false</b> если соединения нет*/
    bool IsConnected();
	

	/** Определяет, является ли текущий пользователь администратором и входи ли он в группу администраторов 
		@return <b>true</b> если администратор, <b>false</b> если нет*/
	inline bool IsAdmin();
  
	/** Определяет, были ли изменения данных с момента последнего сохранения 
		@return <b>true</b> если данные были изменены, <b>false</b> если изменений нет*/
	bool CheckModified();
	
	/** Определяет, была ли связь с сервером разорвана некорректно. Считается, что сеанс связи
		был разорван некорректно, если связь прервалась или сервер остановился и при этом 
		остались несохраненные данные
		@return <b>true</b> если связь разорвана некорректно, <b>false</b> если связь установлена или выход осуществлен корректно*/
	bool TestNeedRestore();

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

	/* Устарело. Надо использовать пару функций SaveDictionaryToMemory(dBuf) - LoadDictionaryFromMemory(dBuf);
	void GetFullDictName(CString &FullDictName);*/
	
	/** Возвращает название базы, с которой установлено соединение 
		@return название базы или пустая строка, если соединение не установлено*/
    CString GetNameCurrBase();

	/** Возвращает название подключения, по которому установлено соединение 
		@return название подключения или пустая строка, если соединение не установлено*/
    CString GetNameCurrConnection();

		/** При установленном подключении с БД возвращает true, если сервер находится на текущем компьютере
		@return true если соединение установлено и сервер находится на текущем компьютере; false в остальных случаях*/
	bool IsCurrConnectionLocal();

	/** Возвращает имя пользователя-владельца текущего сеанса 
		@return имя пользователя или пустая строка, если соединение не установлено*/
	CString GetNameCurrUser();

	/** Возвращает имя домена текущего сеанса, если используется доменная авторизация
		@return имя домена или пустая строка, если соединение не установлено или используется традиционная авторизация*/
	CString GetNameCurrDomain();

	/** Возвращает <B>instance</B>, представляюшую пользователя-владельца текущего сеанса 
		@return имя пользователя или 0, если соединение не установлено*/
	CaplInstance* GetCurrUser();
	//bool SetCurrUser(CaplInstance* user);

	/** Возвращает строку, описывающую текущее подключение к БД и предназначенную для 
		помещения в заголовок приложения (используйте перегруженную функцию CDoc::SetTitle(...)).
		@param name_bd включать в строку имя активной БД
		@param name_connect включать в строку название подключения
		@param name_user включать в строку имя пользователя
		@param name_person включать в строку имя сотрудника (не загружает его с сервера!)
		@param pid включать в строку идентификатор процесса
		@return строка для заголовка*/
	CString GetTitulCurrBD(bool name_bd = true, bool name_connect = false,
						bool name_user = true, bool name_person = true, bool pid = false);

	/** Вызывает диалог настройки свойств подключений 
		@return номер подключения, которое было выделено при завершении диалога*/
	int NET_TuningConnections(int last_selected);
	
	// Соединение с сервером. Еслим сервер локальный - пытается запустить его
	bool ConnectWithTestLocal(CConnectInfo* cif, bool foreground_main_wnd = true, bool bDlgMode = true);

	// Чтение и запись в ini информации о подключениях
	bool ReadConnectionsInfo();
	bool WriteConnectionsInfo();

	/// Возвращает список доступных подключений
	void GetListConnections(CStrArr &list);


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

protected:
	// экстент загруженных (созданных?) в режиме админа. После выхода из AdminMode надо перечитать доступ на них
	aplExtent m_loaded_in_admin;
	CString m_LocalServerPath;
	// Список подключений
	CaplTAggr<CConnectInfo*,CConnectInfo*,APLAGGR_AUTOKILLREF|APLAGGR_LIST> m_list_connection;
	int m_max_connection_num;

	// Название активного метода хеширования паролей. Запрашивается с сервера перед коннектом.
	CString m_ServerHashMethod;

public:
	//@}
	
	/**@name Функции обмена данными с сервером */
	//@{

	/** Сохраняет изменения в базе данных
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SaveChanges( LPCTSTR wait_text = 0);
	/** Сохраняет в БД изменения указанных инстансов и тех, на кого ссылаются указанные
		@param ext - список сохраняемых инстасов
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SaveExtent(aplExtent &ext_saved, LPCTSTR wait_text = 0);
	bool NET_SaveExtent(CaplInstance* inst_saved, LPCTSTR wait_text = 0);

	/** Функция загрузки данных с сервера в соответствии с массивом запросов. Рекомендуется использовать класс <b>CaplLoadData</b> для упрощения работы с запросами
		@param obsolette устаревшая переменная; должна быть равна 0
		@param Count размер массива запросов (в байтах!)
		@param Queries массив запросов
		@param ext_out указатель на список, в который будут помещены все  <B>instance</B>, найденные при выполнении массива запросов. Может быть равен 0
		@param placement указатель на класс кеша базы данных, в который следует поместить результаты выполнения запросов. Может быть равен 0
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@param source описание источника кода (для занесения в лог на сервере). Рекомендуем подставлять макрос DEF_SOURCE
		@param forced если false - проверяется последний выполненный запрос, если совпадает с 
		текущим, предыдущий был успешно выполнен, после выполнения последнего прошло меньше
		тайм-аута для запросов - реально запрос не выполняется, возвращаются 
		результат последнего выполнения. Если true - запрос выполняется всегда)
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_Load(apl_NET_LoadQuery *queries, int count, aplExtent* ext_out = 0,
				CaplNetStepData* placement = 0, LPCTSTR wait_text = 0, CString source = _T(""), bool forced = false);


    /** Загружает с сервера информацию об атрибутах инстансов из экстента ext. Если в списке указаны
     *  атрибуты, то загружает значения только указанных атрибутов. Если список
     *  атрибутов пустой - загружает значения всех атрибутов. В варианте std::list<AttrPath>
     *  можно указывать цепочки атрибутов.
     *  Например: надо у объекта person_and_organization загрузить
     *  атрибут the_person, у полученного объекта person загрузить атрибуты id и code, обратным
     *  запросом найти пользователя и загрузить на клиента его атрибуты personality и name. Тогда
     *  записываем в ext нужный person_and_organization, и передаем такой параметре attr_paths:
     *  (a_persorg_the_person, {{a_pers_id}, {a_pers_code}, {a_user_person,e_user,'r',{a_user_name, a_user_person}}})
        @param ext экстент инстансов, атрибуты которых надо загрузить на клиента
        @param attr_paths цепочки атрибутов для загрузки
        @param attrs список атрибутов для загрузки
        @param ext_out указатель на список, в который будут помещены все  <B>instance</B>, найденные при выполнении массива запросов. Может быть равен 0
     */
    bool NET_LoadExtAttrPaths(aplExtent &ext, std::list<AttrPath> attr_paths, aplExtent *ext_out = 0);
    bool NET_LoadExtAttrs(aplExtent &ext, std::list<CaplAttr*> attrs = std::list<CaplAttr*>(), aplExtent *ext_out = 0);
    bool NET_LoadInstAttrs(CaplInstance *inst, std::list<CaplAttr*> attrs = std::list<CaplAttr*>(), aplExtent *ext_out = 0);

private:
	// Проверка, что сервер приложений поддерживает ветвистые запросы 'd' необходимые для NET_LoadExtAttrPaths
	bool m_is_correct_d_branch;
public:

	/**
		@brief SetLoafForced Устанавливает или отключает формированный режим чтения данных из БД (см
			параметр forced в функции NET_Load). При форсированном режиме NetStepData всегда читает данные из БД,
			даже если запрос дблирует предыдущий и между запросами прошло время меньше установленного тайм-аута
		@param forced если true - установить формированный режим. Если false - отключить
		@return предыдущее значение режима
	*/
	static bool SetLoadForced(bool forced);

	/** Очищает массив запросов и экстент результатов, оставшийся от предыдущего запроса*/
	void ClearLastQuery();

	/** Устанавливает задержку в секундах повторного выполнения запросов*/
	void SetLoadTimeOut(int time_out);

	/** Устанавливает флаг возможности загрузки дополнительных служебных данных для instance: время создания/изменения, пользователь*/
	void SetLoadInstUserDataTimeInfo(bool bCanLoad) {m_bCanLoadInstUserDataTimeInfo = bCanLoad;}
	bool CanLoadInstUserDataTimeInfo() const {return m_bCanLoadInstUserDataTimeInfo;}

	/** Устанавливает время ожидания ответа от сервера в режиме без диалога ожидания (в секундах). 
		Если 0 - то клиент ждет ответа сервера бесконечно (а точнее, неделю)
	*/
	void SetWaitTimeOutWithoutDlg(int time_out);
	UINT RenewClientStateOnServer();

	/** Загружает список <B>instance</B>, удаленных другими пользователями
		@param ext указатель на список
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_LoadDelInst(aplExtent &ext, LPCTSTR wait_text = 0);

	/** Загружает с сервера информацию о дате создания/изменения и пользователе, 
		создавшем/изменившем указанные <B>instance</B>
		@param data массив структур, содержащий инстансы для которых запрашивается информация, и в
			в который помещаются результаты
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_LoadInstUserDataTimeInfo(CaplTAggr<SInstInfo*,SInstInfo*,APLAGGR_AUTOKILLREF> &data, LPCTSTR wait_text = 0);
	
	/** Загружает с сервера и отображает информацию о дате создания/изменения и пользователе, 
		создавшем/изменившем указанные <B>instance</B>
		@param ext_in список <B>instance</B>, для которых запрашивается информация
		@param comments массив комментариев (любая текстовая информация) к каждому instance. 
					Массив может быть меньше размера экстента или параметр может быть равен 0
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_ViewInstUserDataTimeInfo(aplExtent &ext_in, CArray<CString,CString> *comments = 0, LPCTSTR wait_text = 0);
	//@}
	
	/// Возвращает указатель на инстанс с указанным id. Если инстансы нет в кеше и параметр auto_load == true, запрашивает ее с сервера
	CaplInstance* GetInstById(int id, bool auto_load = true, bool load_attr = false);
	
	/**@name Функции поиска и проверки уникальности*/
	//@{

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

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

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

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

	//@}
	/**@name Поиск по атрибутам*/
	//@{
	
	/** Ищет в кеше и на сервере список <B>instance</B> указанного типа, имеющих значения атрибутов,
	указанные массивом значений
		@param entity тип искомых <B>instance</B>
		@param count количество сравниваемых атрибутов
		@param values массив значений атрибутов
		@param extent_out результирующий список
		@param is_substring учитывать при сравнении строк  подстроки или нет.
			<b>true</b> - в результат будут включены <B>instance</B>, 
			строковые атрибуты которых включают подстроки, указанные в массиве атрибутов.
			<b>false</b> атрибуты искомых <B>instance</B> должны быть равны указанным
		@param match_case: учитывать при сравнении строк разницу в регистре символов или нет.
			<b>true</b> - учитывать ("Id"!="id"), <b>false</b> - не учитывать ("Id"=="id"=="iD")
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@param string_bind_mode где должна находиться искомая строка. Работает только при is_substring==true
		@return Количество найденных <B>instance</B>*/
	int NET_FindInstancesWithAttrValues2(CaplEntity *entity, int count, CaplAttrValue *values,
		aplExtent &extent_out, bool is_substring, bool match_case = false, LPCTSTR wait_text = 0,
		aplStringBindMode string_bind_mode = aplSBMiddle, bool bIgnoreSpace = false, LPCTSTR _source = _T(""));
	   
	/** Ищет в локальном кэше список <B>instance</B> указанного типа, имеющих значения атрибутов, 
	указанные массивом значений
		@param entity тип искомых <B>instance</B>
		@param tested_inst Instance, который игнорируется
		@param count количество сравниваемых атрибутов
		@param values массив значений атрибутов
		@param extent_out результирующий список
		@param is_substring учитывать при сравнении строк  подстроки или нет.
			<b>true</b> - в результат будут включены <B>instance</B>, 
			строковые атрибуты которых включают подстроки, указанные в массиве атрибутов.
			<b>false</b> атрибуты искомых <B>instance</B> должны быть равны указанным
			@param match_case: учитывать при сравнении строк разницу в регистре символов или нет.
			<b>true</b> - учитывать ("Id"!="id"), <b>false</b> - не учитывать ("Id"=="id"=="iD")
		@param test_only управляет режимом поиска. <b>true</b> - при нахождении первого подходящего 
			<B>instance</B> поиск прервается и возвращается 1; <b>false</b> - поиск ведется по всему 
			локальному кешу; возвращается список найденных <B>instance</B>
		@param string_bind_mode где должна находиться искомая строка. Работает только при is_substring==true
		@param only_new - если true, то в extent_out возвращает только новые инстансы (с id== 0)
		@param bIgnoreSpace - если true, то при сравнении строк будут проигнорированы пробелы
		@return Количество найденных <B>instance</B>*/
	int FindInstancesWithAttrValuesInLocalCache(CaplEntity *entity, CaplInstance *tested_inst,
						int count, CaplAttrValue *values, aplExtent &extent_out, 
						bool is_substring, bool match_case, bool test_only,
						aplStringBindMode string_bind_mode = aplSBMiddle, bool only_new = false,
						 bool bIgnoreSpace = false);

	//@}
	/**@name Расширенный поиск в БД с использованием языка запросов*/
	//@{
	
	/** Осуществляет редактирование и разбор выражения, описанного на языке запросов STEP_QL.
		@param query_lng текст запроса
		@param is_dlg управляет режимом отображения диалога редактора.  <b>true</b> - диалог 
			отображается, в него заносится текст запроса из <b>query_lng</b>; <b>false</b> - диалог не отображается.
		@param errmsg если параметр указывает на строку, в нее заносится текстовое сообщение об ошибке
		@param is_dlg_ro если параметр указывает на переменную, то дталог редактора меняет поведедние: 
			1) если значение 0 то действует по умолчанию
			2) если значение 1, то поле ввода запроса и кнопка "загрузить" становятся ReadOnly
			зато становится доступна кнопка "Начать редактировать". Если была нажата кнопка 
			"начать редактировать", то в этой переменной возвращается 0
			3) все поля диалога (кроме "выпонить" и "сохранить") становятся ReadOnly
		@param name имя запроса (нужно при вызове из CaplAPI)
		@param save2bd сохранять запрос в БД (нужно при вызове из CaplAPI)
		@param make_table_result выводить результаты запроса в таблице (нужно при вызове из CaplAPI)
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_QueryEditParse(CString &query_lng, bool is_dlg = false, CString *errmsg = 0,
		int *is_dlg_ro = 0, CString *name = 0, bool *save2bd = 0, bool *make_table_result = 0);

	/** Отображает немодальный диалог для редактирования и разбора выражения, описанного на языке запросов STEP_QL.
		@param query_lng текст запроса
		@param end_of_edit call-back-овая функция, которая вызывается при окончании редактирования. Эта функция 
			принимает параметр типа DWORD - идентификатор объекта, из которого была вызвана функция NET_QueryEditParseNoModal.
			Функция может использоваться например для вызова функции исполнения запроса NET_QueryExecuteEx
		@param id_calling_object идентификатор вызывающего объекта, который будет передан call-back-овой функции
		@param query указатель на область памяти, куда должен быть помещен полученный объект запроса. После 
			выполнения запроса функцией NET_QueryExecuteEx объект запроса должен быть удален из памяти. Если 
			редактирование завершится нажатием кнопки "отмена", то в указатель заносится 0.
		@param errmsg если параметр указывает на строку, в нее заносится текстовое сообщение об ошибке
		@param is_dlg_ro если параметр указывает на переменную, то дталог редактора меняет поведедние: 
			1) если значение 0 то действует по умолчанию
			2) если значение 1, то поле ввода запроса и кнопка "загрузить" становятся ReadOnly
			зато становится доступна кнопка "Начать редактировать". Если была нажата кнопка 
			"начать редактировать", то в этой переменной возвращается 0
			3) все поля диалога (кроме "выпонить" и "сохранить") становятся ReadOnly
		@param name имя запроса (нужно при вызове из CaplAPI)
		@param save2bd сохранять запрос в БД (нужно при вызове из CaplAPI)
		@param make_table_result выводить результаты запроса в таблице (нужно при вызове из CaplAPI)
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_QueryEditParseNoModal(CString &query_lng,
		int (__cdecl *end_of_edit)(DWORD *), DWORD id_calling_object, CaplQLQueryParse **query, CString *errmsg = 0,
		int *is_dlg_ro = 0, CString *name = 0, bool *save2bd = 0, bool *make_table_result = 0);
	
	/** Ищет на сервере список <B>instance</B>, описанным запросом, введенным предыдущей функцией <b>NET_QueryEditParse</b>
		@param ext результирующий список
		@param count_res количество найденных инстансов. При использовании этой функции экстент на клиента не передается. Если следующим вызовом идет
		аналогичный запрос на языке запросов с параметром ext - повторное выполнение не производится, возвращается результат из кеша сервера
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_QueryExecute(aplExtent &ext, LPCTSTR wait_text = 0);
	bool NET_QueryExecute(aplExtent &ext, LPCTSTR wait_text, LPCTSTR source);
	bool NET_QueryExecute(DWORD &count_res, LPCTSTR wait_text, LPCTSTR source);

	/** Ищет на сервере список <B>instance</B>, описанным запросом query, введенным предыдущей функцией <b>NET_QueryEditParse</b>
		@param query запрос, полученный с помощью функции NET_QueryEditParseEx
		@param ext результирующий список
		@param count_res количество найденных инстансов. При использовании этой функции экстент на клиента не передается. Если следующим вызовом идет
		аналогичный запрос на языке запросов с параметром ext - повторное выполнение не производится, возвращается результат из кеша сервера
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_QueryExecuteEx(CaplQLQueryParse* query, aplExtent &ext, LPCTSTR wait_text);
	bool NET_QueryExecuteEx(CaplQLQueryParse* query, aplExtent &ext, LPCTSTR wait_text, LPCTSTR source);
	bool NET_QueryExecuteEx(CaplQLQueryParse* query, DWORD &count_res, LPCTSTR wait_text, LPCTSTR source);
	
	//@}


protected:
    //void aplAppendBufValueEx(CaplDataBuf &data, CaplValue *value);
	// заполняет буфер данных для поиска и тестирования
	bool FeelTestFindBuf(CaplDataBuf &dbuf, CaplEntity *ent, CaplInstance *test_inst,
		int count, CaplAttrValue *values, bool is_substring, bool match_case, aplStringBindMode string_bind_mode, bool *bIgnoreSpace = 0);

	bool m_processed_set_error;
public:

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

	/** Показывает диалог выбора пользователя и уровня доступа для операций с доступом. При работе от администратора позволяет редактировать
	информацию о пользователях.
		@param users в этот экстент записываются пользователи и группы пользовтаелей, выбранные в диалоге
		@param access в этой переменной возвращается уровень доступа, выбранный в диалоге
		@return true если диалог закрыт кнопкой Ok и false, если кнопкой Отмена
    */
	bool SelectAplUsers(aplExtent &users, aplAccessModeType &access);
	
	/** Выводит диалог, который позволяет задать доступ (индивидуальный, по шаблону и по умолчанию) к <B>instance</B>,
	 *	заданным списком <b>extent</b>.
		@param extent список pInstance для которых назначается доступ
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SetInstancesAccess(aplExtent* extent, LPCTSTR wait_text = 0);

	/** Устанавливает для пользователя <b>user</b> уровень доступа <b>access_def</b> к <B>instance</B>,
		заданным списком <b>extent</b>.
		Специальные комбинации параметров:
		<b>user</b>==-1 -- Установка доступа по умолчанию и сброс флага индивидуального доступа (типа "заморозить для всех")
		должен быть корректен параметр access
		<b>user</b>== 0 или <b>access_def</b>== -1 -- надо выводить диалог с уточнением
		поведение диалога:
		
		Если пользователь не трогает поле доступа по умолчанию (оставляет его пустым),
		но меняет индивидуальные настройки какого-нибудь пользователя - все Ок., в базе
		меняются только настройки для этого юзера и ставится галочка индивидуального доступа.
		Если меняются только доступ по умолчанию, а галочка индивидуального доступа 
		остается по умолчанию (нет индивидуального доступа), то меняется доступ 
		инстансы по умолчанию, а все индивидуальные настройки убиваются.
		если меняется и то, и то, то в базе меняется оба значения, и галочка индивидуального
		доступа ставится в положение "есть"
		  
		@param extent список pInstance для которых назначается доступ
		@param user пользователь для которого назначается доступ
		@param access_def назначаемый уровень доступа
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@param code1 зарезервировано
		@param code2 зарезервировано
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SetInstancesAccess(aplExtent* extent, CaplInstance* user, aplAccessModeType access_def, LPCTSTR wait_text = 0,
								CaplInstance *access_pattern_inst = (CaplInstance *)-1, bool only_show = false);
	bool NET_SetInstancesAccessBI(aplExtent* extent, CaplInstance* user, aplAccessModeType access_def, LPCTSTR wait_text = 0,
								CaplInstance *access_pattern_inst = (CaplInstance *)-1, bool only_show = false, int code1 = 0, int code2 = 0);
	// Назначает доступ аналогично предыдущим. Используется в основном в плагинах для ГРПЗ и КВЗ
	// Отличия:
	//  *) Если заданы спецпараметры code1 и code2 - не проверяет перед установкой доступ текущего пользователя.
	//  *) Всегда после изменения параметров отправляет изменения на сервер (в базовой функции если был показан диалог и
	//		ничего не изменилось - на сервер данные не отправляются
	bool NET_SetSpecialInstancesAccess(aplExtent* extent, CaplInstance* user, aplAccessModeType access_def, LPCTSTR wait_text = 0,
								int code1 = 0, int code2 = 0);

		
	/** Устанавливает для инстансов в <b>ext</b> доступ (включая доступ по умолчанию, шаблон доступа и индивидуального доступ), описанный
	 * строкой шаблона доступа <b>str_pattern</b><br>
		@param extent - список instance, на которые назначается доступ
		@param str_pattern - шаблон доступа<br>
	Формат шаблона: <id пользователя>:<уровень доступа>;<id пользователя>:<уровень доступа>;...<br>
		<id пользователя> - идентификатор instance типа "apl_workgroup" или "apl_user"<br>
		<уровень доступа> - обозначение уровня доступа:<p>
			OWN - полный доступ<br>
			RW - доступ на чтение-запись<br>
			RO - доступ только на чтение<br>
			NA - нет доступа<br>
		точка с запятой (';') после последней группы может отсутствовать<br>
		в строке не должно быть пробелов<br>
		если необходимо назначить доступ по умолчанию, то <id пользователя> указывается равным 0;
	рекомендуется помещать его первым в строке.<br>
		если необходимо назначить доступ текущему пользователю, то <id пользователя> указывается равным 1;
	рекомендуется помещать его в начале строки.<br>
		если необходимо назначить доступ группе текущего пользователя, то <id пользователя> указывается равным 2;
	рекомендуется помещать его в начале строки<br>
		<p>
		Примеры: доступ по умолчанию не менять; назначить доступ RO для двух пользователей (или групп пользователей)
		5176:RO;22809:RO;
		<br>назначить доступ по умолчанию "только чтение"; назначить полный доступ для одного пользователя (или группы пользователей)
		0:RO;11042:OWN
		<br>назначить доступ по умолчанию "только чтение"; назначить полный доступ текущему пользователю
		0:RO;1:OWN
		<br> Функции, которые возвращают описание строки доступа, могут работать в двух режимах. 
		При выводе информации по-умолчанию выводится строка аналогичная вышеописанной. В режиме 
		вывода информации для пользователя идентификаторы пользователей заменяются их именами, 
		обозначения уровня доступа так же выводятся по русски
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится
		сообщение по умолчанию
		@param code1 зарезервировано
		@param code2 зарезервировано
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SetAccessFromPattern(aplExtent* extent, CString &str_pattern,
												LPCTSTR wait_text = 0, int code1 = 0, int code2 = 0);
	bool NET_SetAccessFromPatternBI(aplExtent* extent, CString &str_pattern,
												LPCTSTR wait_text = 0, int code1 = 0, int code2 = 0);


	/** Устанавливает для инстансов в <b>extent</b> доступ (включая доступ по умолчанию, шаблон доступа и индивидуального доступ), описанный
	 * строкой шаблона доступа, заданной в предварительно созданном шаблоне <b>access_pattern_inst</b> Шаблон доступа это инстанс
	 * типа apl_access_pattern, у которой в атрибуте pattern хранится строка шаблона (см описанние функции NET_SetAccessFromPattern).<br>
        @param extent - список instance, на которые назначается доступ
		@param access_pattern_inst инстанс типа apl_access_pattern в которой хранится строка с шаблоном доступа.
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится
			сообщение по умолчанию
		@param code1 зарезервировано
		@param code2 зарезервировано
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SetAccessFromPatternInst(aplExtent* extent, CaplInstance *access_pattern_inst,
												LPCTSTR wait_text = 0, int code1 = 0, int code2 = 0);

	/** Устанавливает для инстансов в <b>extent</b> доступ (включая доступ по умолчанию, шаблон доступа и индивидуального доступ) согласно
	 *  предварительно созданному шаблону с именем <b>pattern_name</b><br>
		@param pattern_name - имя шаблона доступа, который был сохранен в БД. Шаблон доступа - это инстанс типа apl_access_pattern;
			имя шаблона хранится в атрибуте name
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится
			сообщение по умолчанию
		@param code1 зарезервировано
		@param code2 зарезервировано
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SetAccessFromPatternName(aplExtent* extent, CString &pattern_name,
												LPCTSTR wait_text = 0, int code1 = 0, int code2 = 0);

	/** Устанавливает для текущего пользователя индивидуальный уровень доступа "собственник" (aplOWNER) к <B>instance</B>,
		заданным списком <b>extent</b>. Для всех остальных пользователей устанавливает уровень
		  доступа "Только чтение" (aplRO)
		@param extent список pInstance для которых назначается доступ
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_BecomeInstancesOwner(aplExtent* extent, LPCTSTR wait_text = 0);
	
	/** Устанавливает уровень доступа для пользователей и <B>instance</B>, описанных классом 
		<b>main_table</b>
		@param main_table таблица массив структур вида: instance типа пользователь (apl_user)-таблица инстанс-доступ инстансы к указанному пользователю
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится
		сообщение по умолчанию
		@param code1 зарезервировано
		@param code2 зарезервировано
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SetGroupeAccess(aplUsers &main_table, LPCTSTR wait_text = 0, int code1 = 0, int code2 = 0);
protected:
	bool NET_SetGroupeAccessInternal(aplUsers &main_table, LPCTSTR wait_text = 0, int code1 = 0, int code2 = 0);
public:

	/** Копирует карту доступа инстансы pattern для всех инстансов входящих в destination
		@param pattern инстанс, с которого копируется доступ
		@param destination список инстансов, на которые копироуется доступ
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится
		сообщение по умолчанию
		@param code1 зарезервировано
		@param code2 зарезервировано
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_CopyGroupeAccess(CaplInstance* pattern, aplExtent &destinations, LPCTSTR wait_text = 0, int code1 = 0, int code2 = 0);	

	/** Попарно копирует карту доступа от инстансов входящих в экстент patterns для каждого инстанса входящего
		в destination. Доступ копируется от первого инстанса из списка patterns на первый инстанс из списка destination, из второго
		инстанса из списка patterns на второй инстанс из списка destination и т.п. Если количество элементов в списках отличается,
		возвращает ошибку.
		@param patterns список инстансов, с которых копируется доступ
		@param destination список инстансов, на которые копироуется доступ
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится
			сообщение по умолчанию
		@param code1 зарезервировано
		@param code2 зарезервировано
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_CopyAccessFromInst2Inst(aplExtent &patterns, aplExtent &destinations, LPCTSTR wait_text = 0, int code1 = 0, int code2 = 0);


	/** Определяет уровень доступа пользователей и <B>instance</B>, описанных классом <b>main_table</b>
		@param main_table массив структур вида: instance типа пользователь (apl_user)-таблица инстанс-доступ инстансы к указанному пользователю
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится
			сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_GetGroupeAccess(aplUsers &main_table, LPCTSTR wait_text = 0);

	/** Определяет уровень доступа <B>instance</B>, описанных классом <b>ListAccess</b>
		@param ListAccess массив структур вида: instance - доступ по умолчанию - шаблон доступа - таблица пар пользователь (apl_user)-доступ 
			пользователя к инстансе
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится
			сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_GetGroupeAccessBI(aplListAccess2Inst &ListAccess, LPCTSTR wait_text = 0);

	/** Назначает уровень доступа <B>instance</B>, описанных классом <b>ListAccess</b>
		@param ListAccess массив структур вида: instance - доступ по умолчанию - шаблон доступа - таблица пар пользователь (apl_user)-доступ 
			пользователя к инстансе
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится
			сообщение по умолчанию
		@param code1 зарезервировано
		@param code2 зарезервировано
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SetGroupeAccessBI(aplListAccess2Inst &ListAccess, LPCTSTR wait_text = 0, int code1 = 0, int code2 = 0);
protected:
	bool NET_SetGroupeAccessBIInternal(aplListAccess2Inst &ListAccess, LPCTSTR wait_text = 0, int code1 = 0, int code2 = 0);
public:

	/** Формирует массив строк, описывающих карту доступа для каждого instance из экстента 
		@param extent - список инстансов, для которых нужно получить доступ
		@param destination - выходной массив строк с описанием доступа
		описание строки доступа см. функцию NET_SetAccessFromPattern
		@param for_user - если false, формируется строка для машинной обработки; пользователи заданы идентификаторами, значения
			доступа заданы константами по-английски
						- если true, формируется строка для вывода пользователю на экран; в ней выводятся имена пользователей,
			а описание уровня доступа выводится по-русски.
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_GetExtentAccess2String(aplExtent &extent, CStringArray &destination, bool for_user=true, LPCTSTR wait_text = 0);
	bool NET_GetExtentAccess2StringBI(aplExtent &extent, CStringArray &destination, bool for_user=true, LPCTSTR wait_text = 0);
	
	/** Формирует строку, описывающую доступ для указанного instance 
		@param inst - инстанс, для которого нужно получить доступ
		@param destination - выходная строка с описанием доступа
		описание строки доступа см. функцию NET_SetAccessFromPattern
		@param for_user - если false, формируется строка для машинной обработки; пользователи заданы идентификаторами, значения
			доступа заданы константами по-английски
						- если true, формируется строка для вывода пользователю на экран; в ней выводятся имена пользователей,
			а описание уровня доступа выводится по-русски.
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_GetExtentAccess2String(CaplInstance* inst, CString &destination, bool for_user=true, LPCTSTR wait_text = 0);

	/** Удаляет индивидуальный доступ пользователя (или группы пользователей) <b>access_agent</b> к инстансам, входящих в <B>extent</B>
		@param extent - массив инстансов для обработки
		@param access_agent - пользователь или группа пользователей, для которых надо убрать доступ
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_RemoveAccessAgent(aplExtent &extent, CaplInstance* access_agent, LPCTSTR wait_text = 0, int code1 = 0, int code2 = 0);

	/** Командует серверу приложений перечитать список шаблонов доступа
		*/
	bool NET_RefreshAccessPatterns();

	/** определяет, используется ли в назначении доступа к инстансам указанный шаблон доступа
		@param access_pattern_inst - проверяемый шаблон доступа
		@return <b>true</b> если шаблон используется и <b>false</b> если не используется */
	bool NET_IsUsedAccessPattern(CaplInstance* access_pattern_inst);

	/** определяет, используется ли в назначении доступа к инстансам шаблоны доступа из экстента ext_access_pattern_inst
		@param ext_access_pattern_inst Список шаблонов доступа (инстансов типа apl_access_pattern) на проверку
		@param used таблица целых чисел, размером с входной экстент ext_access_pattern_inst. В ней для каждого шаблона из входного
			экстента возвращается: 1 если шаблон с таким индексом используется, 0 - если не используется
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_IsUsedAccessPatterns(aplExtent &ext_access_pattern_inst, CUIntArray &used);

	/** У каких инстансов указанный шаблон указан в качестве шаблона доступа
		@param access_pattern_inst - проверяемый шаблон доступа
		@param users - список инстансов
		@return <b>true</b> если шаблон используется и <b>false</b> если не используется */
	bool NET_WherePatternUsed(CaplInstance* access_pattern_inst, CUIntArray &users);

	// Возвращает строку временного пароля для дублицирования сессии
	bool NET_GetString4DupSession(CString &spetial_string);

	/** Проверяет, не заблокированы ли заданные инстансы другими клиентами. Если нее заблокированы - устанавливает для них блокировку на запись и возвращает <b>true</b>.
	Если заблокированы - ждет в течение <b>iMilliseconds</b> миллисекунд, периодически пытаясь повторить блокировку. Если за это время инстанс(ы) не осовбодились - возвращает <b>false</b>
	Если какой-либо инстанс из списка не существует (или удален) - функция возвращает <b>false</b>
	Блокировка снимается автоматически в двух случаях: 1) при любом SaveChange 2) при достижении времени, указанного в  блокировке.
	Для lite сервера блокировка всегда снимается после перезапуска сервера.
		@param instance - инстанс для блокировки
		@param extent - массив инстансов для блокировки
		@param iMilliseconds - время в милисекундах, которое функция пытается повторить блокировку. Если задано время меньше 50 милисекунд - используется значение 50.
		@return <b>true</b> если инстанс(ы) удачно заблокированы и <b>false</b> если инстанс(ы) уже заблокированы другим клиентским сеансом или не сохранены или удалены*/
	bool NET_LockInstanceForChange(CaplInstance *instance, int iMilliseconds);
	bool NET_LockInstancesForChange(aplExtent &extent, int iMilliseconds);


	/** Вызывает диалог для редактирования шаблона доступа, заданного в виде строки
        @param str_pattern - редактируемый шаблон доступа. Может быть пустой строкой
			формат шаблона доступа см. функцию NET_SetAccessFromPattern. При успешном завершении функции в
			строку будет записан новый шаблон доступа
		@param definition - если указатель не пустой, возвращает описание шаблона на руском языке
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool PrepareAccessStringPattern(CString &str_pattern, CString *definition = 0);

	// проверяет, является ли текущий пользователь собственником указанных <B>instance</B>
	bool CheckOwner(aplExtent* extent, bool *is_RO = 0);
	// проверяет, сохранены ли указанные <B>instance</B>
	bool CheckSaved(aplExtent* extent);

	// Служебные операции сервера по запросу клиента
	bool NET_ServiceOp(BYTE command, CStringArray &list_strings, CaplDataBuf *dbuf_test = 0);


protected:
	bool CheckGUIDAccessDict();
	bool LoadGUIDAccess(CStringArray &GUIDs, CaplStrMap &GUID2inst);

public:
	// работа с назначением доступа для LSS-объектов по GUID 
	// вызывает диалог назначения доступа. Результаты заносит в массив объектов apl_GUID_access и сохраняет в БД
	bool SetGUIDAccess(CStringArray &GUIDs, bool read_only = false);
	// если у текущего пользователя есть полный доступ к перечисленным GUID, то назначает доступ согласно параметрам access_def (доступ 
	//	по умолчанию), access_pattern (шаблон доступа), individual_access (таблица индивидуального доступа; в in - указател на CaplInstance* типа 
	// apl_user, в out - доступ этого юзера или групы)
	// Если к одной/несокльким GUID  утекущего пользователя доступ меньше, чем aplOWN - показывает диалог с текущими значениями доступа
	// Фкунция в процессе разработки!
	bool SetGUIDAccess(CStringArray &GUIDs, aplAccessModeType access_def, CaplInstance* access_pattern, CaplMap &individual_access);
	// удаляет записи доступа для указанных GUID
	bool DelGUIDAccess(CStringArray &GUIDs);
	// для переданных в параметрах in GUID зачитывает из БД соответствующие apl_GUID_access; применяет 
	// доступ к текущему юзеру и возвращает в параметре out собственно доступ текущего юзера
	bool GetGUIDAccess(CaplStrMap &GUIDs);
	// проверяет, является ли текущий пользователь собственником указанных <B>GUID</B>
	bool CheckGUIDOwner(CStringArray &GUIDs, bool *is_RO = 0);
	// копирует доступ с инстанса на массив GUID-ов
	bool CopyAccessFromInst2GUIDs(CaplInstance* source, CStringArray &GUIDs);
	// копирует значения атрибутов от одного инстанса в другой
	bool CopyInstAttrs(CaplInstance *from, CaplInstance *to);

	// загружает с сервера список пользователей
	bool LoadAllUsers(aplExtent &users);
	CaplInstance* IsUserCorrect(LPCTSTR username, LPCTSTR password);
	void FillConnectionList(CComboBox &SelectConnection, LPCTSTR def_value, int &cur_select_connection);
	void SetSingleAlias(LPCTSTR SingleAlias);
protected:
	// формирует экстент из стандартного буфера
	//bool MakeExtFromDbuf(CaplDataBuf &dbuf,aplExtent &ext); - достаточно экстьента, получаемого из apploadfromdb
	CString m_SingleAlias;
public:
	
	//@}

	//Перегруженные функции родителя - чтобы разрешить конфликт имен
	#define RETURN_GA_PARENT  const {return CaplStepData::GetAttr(inst,attr,value);}
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, CaplValue &value)RETURN_GA_PARENT;
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, int &value)RETURN_GA_PARENT;
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, double &value)RETURN_GA_PARENT;
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, CString &value)RETURN_GA_PARENT;
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, pCaplInstance &value)RETURN_GA_PARENT;
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, bool &value)RETURN_GA_PARENT;
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, CaplAggr &value)RETURN_GA_PARENT;
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, aplExtent &value)RETURN_GA_PARENT;
	bool GetAttr(CaplInstance *inst, CaplAttr *attr, _std_string &value)RETURN_GA_PARENT;

/*	Здесь конфликта нет - но пусть определения будут на всякий случай. хоть и закоментаренные
	bool GetAttrBN(CaplInstance *inst,LPCTSTR attr_name, CaplValue **value);
	bool GetAttrBN(CaplInstance *inst,LPCTSTR attr_name, CaplValue &value);
	bool GetAttrBN(CaplInstance *inst,LPCTSTR attr_name, int &value);
	bool GetAttrBN(CaplInstance *inst,LPCTSTR attr_name, double &value);
	bool GetAttrBN(CaplInstance *inst,LPCTSTR attr_name, CString &value);
	bool GetAttrBN(CaplInstance *inst,LPCTSTR attr_name, pCaplInstance &value);
	bool GetAttrBN(CaplInstance *inst,LPCTSTR attr_name, bool &value);
	bool GetAttrBN(CaplInstance *inst,LPCTSTR attr_name, CaplAggr &value);
*/
	
	/**@name Функции обмена файлами с сервером*/
	//@{
protected:
	// максимально возможный размер БЛОБа (для оракла он ограничен размером файла данных БД)
	__int64 m_MaxBlobSize;
public:

	/** Записывает файл на сервер в каталог с логами сервера
		@param file_source имя файла (с путем)
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	// 4del - убрано, так как никому не нужно много лет
	//bool NET_SaveFile2Spetial(LPCTSTR file_source, LPCTSTR wait_text = 0);

	/** Записывает файл в БЛОБ в БД и заносит его идентификатор в указанный атрибут указанной <B>instance</B>
		@param inst <B>instance</B>, для которой заносится файл
		@param attr_name имя атрибута, в который заносится идентификатор BLOB-а
		@param file_source имя файла (с путем)
		@param code в этой переменной возвращается постейшая чек-сумма содержимого буфера
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SaveBlobBN(CaplInstance *inst, LPCTSTR attr_name, LPCTSTR file_source, long &code, LPCTSTR file_name = 0, LPCTSTR wait_text = 0, int crc32 = 0);

	/** Записывает файл в БЛОБ в БД и заносит его идентификатор в указанный атрибут указанной <B>instance</B>
		@param inst <B>instance</B>, для которой заносится файл
		@param attr атрибут, в который заносится идентификатор BLOB-а
		@param file_source имя файла (с путем)
		@param file_name имя файла для записи в атрибут source объекта apl_stored_document. Если пустое - выделяется имя файла из file_source
		@param code в этой переменной возвращается постейшая чек-сумма содержимого буфера
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SaveBlob(CaplInstance *inst, CaplAttr *attr, LPCTSTR file_source, long &code, LPCTSTR file_name = 0, LPCTSTR wait_text = 0, int crc32 = 0);

	/** Записывает буфер из памяти в БЛОБ в БД и заносит его идентификатор в указанный атрибут указанной <B>instance</B>
		@param inst <B>instance</B>, для которой заносится файл
		@param attr атрибут, в который заносится идентификатор BLOB-а
		@param source указатель на исходный буфер
		@param size_source размер исходного буфера
		@param code в этой переменной возвращается постейшая чек-сумма содержимого буфера
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SaveFileFromMemory(CaplInstance *inst, CaplAttr *attr, BYTE* source, long size_source, long &code, LPCTSTR wait_text = 0, int crc32 = 0);	

	/** Читает BLOB с сервера из указанного аттрибута указанной <B>instance</B> в файл
		@param inst <B>instance</B>, в атрибуте которой хранится идентификатор BLOB-а
		@param attr_name имя атрибута, в котором хранится идентификатор BLOB-а
		@param file_dest имя создаваемого файла (с путем)
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_LoadBlobBN(CaplInstance *inst, LPCTSTR attr_name, LPCTSTR file_dest, LPCTSTR wait_text = 0);

	/** Читает BLOB с сервера из указанного аттрибута указанной <B>instance</B> в файл
		@param inst <B>instance</B>, в атрибуте которой хранится идентификатор BLOB-а
		@param attr атрибут, в котором хранится идентификатор BLOB-а
		@param file_dest имя создаваемого файла (с путем)
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_LoadBlob(CaplInstance *inst, CaplAttr *attr, LPCTSTR file_dest, LPCTSTR wait_text = 0);

	/** Читает BLOB из БД и записывает в файл на сервере приложений
		@param _ServNameBLOB идентификатор BLOB-а (в виде строки), из которого читается файл
		@param _ServNameFileDest имя создаваемого файла (с путем) на сервере приложений
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SaveBlob2Srv(LPCTSTR _ServNameBLOB, LPCTSTR _ServNameFileDest, LPCTSTR wait_text = 0);
	
	/** Читает BLOB из БД и записывает в файл на сервере приложений
		@param inst <B>instance</B>, в атрибуте которой хранится идентификатор BLOB-а
		@param attr атрибут, в котором хранится идентификатор BLOB-а
		@param global_file_dest имя создаваемого файла (с путем) на сервере приложений
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_SaveBlob2Srv(CaplInstance *inst, CaplAttr *attr, LPCTSTR _ServNameFileDest, LPCTSTR wait_text = 0);

	/** Читает файл на сервере приложений и создает из него BLOB в БД
		@param name_blob идентификатор BLOB-а (в виде строки), в который был записан файл
		@param global_file_src имя читаемого файла (с путем) на сервере приложений
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_CreateBlobFromSrv(LPCTSTR global_file_src, CString &name_blob, LPCTSTR wait_text = 0);

	/** Читает файл на сервере приложений и создает из него BLOB в БД
		@param inst <B>instance</B>, в атрибут которой будет записан идентификатор BLOB-а
		@param attr атрибут, в который будет записан  идентификатор BLOB-а
		@param global_file_src имя читаемого файла (с путем) на сервере приложений
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_CreateBlobFromSrv(CaplInstance *inst, CaplAttr *attr, LPCTSTR global_file_src, LPCTSTR wait_text = 0);
	
	/** Читает с сервера BLOB с указанным идентификатором в файл на клиенте
		@param _ServNameBLOB идентификатор BLOB-а (в виде строки), из которого читается файл
		@param file_dest имя создаваемого файла (с путем)
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_LoadFileFromSrv(LPCTSTR _ServNameBLOB, LPCTSTR file_dest, LPCTSTR wait_text = 0, LPCTSTR ext_info = 0);


	/** Читает с сервера пачку BLOB с указанными идентификаторами в указанную папку. Имена файлов создаются автоматически в формате 
	"blob_[идентификатор блоба].tmp". Если такой файл в указанной папке уже есть - он перезаписывается
		@param blob_ids список идентификаторов BLOB-ов
		@param folder_dest имя папки, в которую будут помещены файлы
		@param blob_names список имен файлов; порядок имен соответствует идентификтаорам БЛОБов
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_LoadMultiBlobsFromSrv(CUIntArray &blob_ids, LPCTSTR folder_dest, CStringArray &blob_names, LPCTSTR wait_text = 0);

	/** Читает с сервера из каталога, назначенном для автообновления для заданной системы, список имен файлов и список их статусов. 
		@param system имя системы для обновления
		@param mask маска имен файлов, список которых надо получить
		@param list_files массив строк именами файлов, соответствующие заданной маске, и их статусами
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_Autoupdate_LoadListNamesFiles(LPCTSTR system, CStringArray &list_masks,
									CaplTAggr<SaplFileDescr*,SaplFileDescr*,APLAGGR_LIST_OR_AUTOKILLREF> &list_files, LPCTSTR wait_text = 0);

	/** Загружает с сервера из каталога, назначенном для автообновления для заданной системы, список файлов в указанную папку
		@param system имя системы для обновления
		@param folder_dest имя папки, в которую будут помещены файлы
		@param list_files список имен файлов, которые надо загрузить. Имена даются относительно каталога автообновления
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_Autoupdate_LoadListFiles(LPCTSTR system, LPCTSTR folder_dest, CStringArray &list_files, LPCTSTR wait_text = 0);

	/** Читает с сервера размер BLOB-а из указанного аттрибута указанной <B>instance</B>
		@param inst <B>instance</B>, для которой определяется размер BLOB-а
		@param attr атрибут, в котором хранится идентификатор BLOB-а
		@param blob_size размер BLOB-а. При ошибке возвращается -1. При вызове функции с long для БЛОБа размером больше 2 гигабайт возвращает ошибку.
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_GetBlobSize(CaplInstance *inst, CaplAttr *attr, long &blob_size, LPCTSTR wait_text = 0);
	bool NET_GetBlobSize(CaplInstance *inst, CaplAttr *attr, __int64 &blob_size, LPCTSTR wait_text = 0);

	/** Читает с сервера размер файла BLOB-а
		@param _ServNameBLOB идентификатор BLOB-а из которого читается файл
		@param blob_size размер BLOB-а. При ошибке возвращается -1. При вызове функции с long для БЛОБа размером больше 2 гигабайт возвращает ошибку.
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_FileSrvSize(LPCTSTR _ServNameBLOB, long &blob_size, LPCTSTR wait_text = 0);
	bool NET_FileSrvSize(LPCTSTR _ServNameBLOB, __int64 &blob_size, LPCTSTR wait_text = 0);

	/** Читает с сервера размеры BLOB-ов из указанного аттрибута указанной <B>instance</B>
		@param extent список <B>instance</B>, для которых определяется размер BLOB-а
		@param attr атрибут, в котором хранится идентификатор BLOB-а
		@param blob_size размер BLOB-а. При вызове функции с CUIntArray для хотя бы одного БЛОБа размером больше 2 гигабайт возвращает ошибку.
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_GetBlobSize(aplExtent &extent, CaplAttr *attr, CUIntArray &blob_sizes, LPCTSTR wait_text = 0);
	bool NET_GetBlobSize(aplExtent &extent, CaplAttr *attr, C__int64Array &blob_sizes, LPCTSTR wait_text = 0);


	/** Читает BLOB с сервера из указанного аттрибута указанной <B>instance</B> в память
		@param inst <B>instance</B>, в атрибуте которой хранится идентификатор BLOB-а
		@param attr атрибут, в котором хранится идентификатор BLOB-а
		@param blob_dest буфер для помещения BLOB-а
		@param size_buf размер буфера
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_LoadBlob2Memory(CaplInstance *inst, CaplAttr *attr, BYTE* blob_dest, long &size_buf, LPCTSTR wait_text = 0);

	/** Читает BLOB с сервера из указанного аттрибута указанной <B>instance</B> в память
		@param inst <B>instance</B>, в атрибуте которой хранится идентификатор BLOB-а
		@param attr_name имя атрибута, в котором хранится идентификатор BLOB-а
		@param blob_dest буфер для помещения BLOB-а
		@param size_buf размер буфера
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_LoadBlob2MemoryBN(CaplInstance *inst, LPCTSTR attr_name, BYTE* blob_dest, long &size_buf, LPCTSTR wait_text = 0);
	
	/** Читает с сервера BLOB с указанным идентификатором в память
		@param _ServNameBLOB идентификатор BLOB-а из которого читается файл
		@param blob_dest буфер для помещения BLOB-а
		@param size_buf размер буфера
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_LoadFileFromSrv2Memory(LPCTSTR _ServNameBLOB, BYTE* blob_dest, long &size_buf, LPCTSTR wait_text = 0, LPCTSTR ext_info = 0);

	/** Удаляет BLOB на сервере из указанного аттрибута указанной <B>instance</B>
		@param inst <B>instance</B>, в атрибуте которой хранится идентификатор BLOB-а
		@param attr_name имя атрибута, в котором хранится идентификатор BLOB-а
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_DeleteBlobBN(CaplInstance *inst, LPCTSTR attr_name, LPCTSTR wait_text = 0);

	/** Удаляет файл с сервера из указанного аттрибута указанной <B>instance</B>
		@param inst <B>instance</B>, в атрибуте которой хранится идентификатор BLOB-а
		@param attr атрибут, в котором хранится идентификатор BLOB-а
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_DeleteBlob(CaplInstance *inst, CaplAttr *attr, LPCTSTR wait_text = 0);
	bool NET_DeleteBlob(LPCTSTR _ServNameBLOB, LPCTSTR wait_text = 0, int inst_id = 0, int attr_id = 0);

	/// Возвращает размер порции при чтении БЛОБ-а с сервера
	int GetBlobPortionDefSize();


	/** Создает на сервере итератор для BLOB с указанным идентификатором и читает в память первую порцию
		@param _ServNameBLOB идентификатор BLOB-а из которого читается файл
		@param blob_dest буфер для помещения порции BLOB-а
		@param size_buf размер буфера (должен быть не меньше размера стандартной порции)
		@param last возвращается true, если это последняя порция БЛОБ=а
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_ReadFirstPortionFileFromSrv2Memory(LPCTSTR _ServNameBLOB, BYTE* blob_dest, long &size_buf, bool &last, LPCTSTR wait_text = 0);

	/** Читает с сервера из итератора следующую порцию BLOB-а
		@param blob_dest буфер для помещения порции BLOB-а
		@param size_buf размер буфера (должен быть не меньше размера стандартной порции)
		@param last возвращается true, если это последняя порция БЛОБ=а
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_ReadNextPortionFileFromSrv2Memory(BYTE* blob_dest, long &size_buf, bool &last, LPCTSTR /*wait_text*/ = 0);

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

	/** Возвращает идентификатор атрибута <b>attr</b>
		@return идентификатор атрибута*/
    int GetAttrId(CaplAttr *attr);

	/** Возвращает идентификатор атрибута типа <b>entity</b> c именем <b>attr_name</b> 
		@return идентификатор атрибута*/
	int GetAttrIdBN(CaplEntity *entity, LPCTSTR attr_name);

	/** Возвращает идентификатор <b>entity</b>, заданной параметром <b>ent</b>
		@return идентификатор <b>entity</b>*/
	int GetEntId(CaplEntity *ent);

	/** Возвращает идентификатор <b>entity</b> по имени, заданном параметром <b>ent_name</b> 
		@return идентификатор <b>entity</b>*/
	int GetEntIdBN(LPCTSTR ent_name);

	/** Возвращает идентификатор <b>instance</b>, заданной параметром <b>inst</b>
		@return идентификатор <b>instance</b>*/
	int GetInstId(CaplInstance *inst);

	/** Если в указанном аттрибуте хранятся идентификаторы БЛОБов - возвращает true. Иначе - false
		@return значение*/
	bool IsAttrStoreBLOB(CaplAttr* attr);

	//@}

	// замещаемые
	virtual bool GetAttr(CaplInstance *inst, CaplAttr *attr, CaplValue **value);

protected:
	// Создание и удаление специальных временных пользователей для операций с шаблонами доступа
	int m_count_cur_users;
	CaplInstance *m_def_curr_user, *m_def_curr_user_group;
public:
	inline bool TemporaryCurrUsersCreate()
	{
		m_def_curr_user = GetInstById(1);
		m_def_curr_user_group = GetInstById(2);
		if(m_count_cur_users > 0 && (m_def_curr_user == 0 || m_def_curr_user_group == 0)){	return false;}
		if(m_def_curr_user == 0){m_def_curr_user = CaplStepData::CreateInstance(m_ent_apl_user, true);}
		if(m_def_curr_user_group == 0){m_def_curr_user_group = CaplStepData::CreateInstance(m_ent_apl_workgroup, true);}
		if(m_def_curr_user == 0) return false; 
		if(m_def_curr_user_group == 0) return false;
		if(m_count_cur_users == 0)
		{ 
			m_def_curr_user->SetId(1); 
			PutAttr(m_def_curr_user, m_attr_apl_user__name, CString(_T(" ")) + UserNameDecode(m_def_curr_user, true, true));
			m_def_curr_user_group->SetId(2); 
			PutAttr(m_def_curr_user_group, m_attr_apl_user__name,  CString(_T(" ")) + UserNameDecode(m_def_curr_user_group, true, true));
			aplExtent ext_def_curr_user; ext_def_curr_user.Add(m_def_curr_user_group);
			PutAttr(m_def_curr_user, m_attr_apl_user__grop, ext_def_curr_user);
		}
		m_count_cur_users++;
		return true;
	}
	inline void TemporaryCurrUsersDelete()
	{
		m_count_cur_users--;
		if(m_count_cur_users == 0)
		{
			CaplStepData::DeleteInstanceForced(m_def_curr_user);
			CaplStepData::DeleteInstanceForced(m_def_curr_user_group); 
			m_def_curr_user = 0; m_def_curr_user_group = 0; 
		}
	}


	/// Работа с INI
	/// проверяет, есть ли доступ на запись к ini
	bool CheckIniWrite(){return m_Ini.CheckWrite();}

	/// Читает параметр из ini файла, из которого читаются настройки NetStepData
	/// Если нужнs дополнительные возможности - используйте функцию GetIniFullName
	/// и сами читайте/пишите из/в ini
	bool GetIniParameter(LPCTSTR group_name, LPCTSTR key_name, CString &value, bool isExpandRelatedPath = false);
	int GetIniParameter(LPCTSTR group_name, LPCTSTR key_name);

	/// записывает параметр в ini файл, из которого читаются настройки
	/// Если нужнs дополнительные возможности - используйте функцию GetIniFullName
	/// и сами читайте/пишите из/в ini
	bool WriteIniParameter(LPCTSTR group_name, LPCTSTR key_name, LPCTSTR value);

protected:

	// буфер для хранения разобранного запроса
	CaplQLQueryParse* m_query;
	int m_PercentSCh;
	//Эта перегрузка возвращает экстент с со списком сохраняемых <B>instance</B>
	bool _SaveExtToDataBuf(CaplDataBuf &dbuf, aplExtent &inSavInst, aplExtent &outSavInst, aplExtent &ext4attr);

	// Помещает экстент в буфер без всяких проверок (и пока что без атрибутов)
	bool PutExtToDataBuf(aplExtent &ext, CaplDataBuf &dbuf);

	long m_changed_thread;
	long m_external_exit;

	// Работа с AplTransport.ini
	CaplINI m_Ini;

	// Заполнение глобальных переменных (имя и путь к exe, путь к ini  и т.п.)
	bool InitAppName();

	//Возвращает аттрибут по имени (в родной вариатне она protected
	//CaplAttr *FindAttr(CaplEntity *entity, LPCTSTR attr_name){
	//	return CaplStepData::FindAttr(entity, attr_name);
	//};


	//Вызов панельки с запросом базы, имени и пароля
	// далее пытается установить TCP соединение с сервером
	// Внимание! При ошибке генерит исключение!
	/* параметр dialog_mode: 
		CONNECT_DLG_MODE__SUPRESS не показывать диалог никогда, при любых неполадках - выходить из функции
		CONNECT_DLG_MODE__ONLY_ERROR показывать диалог только если переданы некорректные параметры (пустой username, некорректный name_connect и т.п.)
		CONNECT_DLG_MODE__SHOW_ALVAYS показывать диалог всегда
	*/
	bool ConnectWithParam(int dialog_mode);

	// Чтение и запись информации в реестр о последнем логинившемся
	bool ReadLastActive(CStringArray &reg_user_list, CString &reg_base, CStringArray &reg_domain_list);
	bool WriteLastActive(CStringArray &reg_user_list, CString name_base, CStringArray &reg_domain_list);

	// Добавляет строку в начало списка, и удаляет, если она она была в середине
	void AppendString2List(CStringArray &list, CString &new_string);

	// Чтение и запись информации в реестр о списке использованных прокси для протокола http
	bool ReadLastProxyList(CStringArray &proxy_list);
	bool WriteLastProxyList(CStringArray &proxy_list, bool clear = false);
	
	// Вспомогательная цапля - используется при актуализации аггров для загрузки текущего состояния дел БД
	CaplNetStepData* m_local_data;

	// список атрибутов, в которых живут идентификтаоры БЛОБов
	CaplMap m_list_attrs4blobs;

	// Основной тип лицении
	CString m_type_lic_current;
	// Дополнительные типы лицензий, занятые текущим сеансом
	CStringArray m_types_lic_adt;

	CStringArray m_reg_user_list;
	CStringArray m_reg_domain_list;
	bool m_ShowLastUser;
	int m_NumLastUsers;
	int m_NumLastDomains;

	// Если true то функции назначения доступа сохраняют данные о доступе в кеше и передают их на сервер только при вызове NET_SaveChanges
	bool m_SetAccessWithSave;
	CaplTAggr<aplUsers*,aplUsers*,APLAGGR_AUTOKILLREF> m_ListDelaedAccess;
	CaplTAggr<aplListAccess2Inst*,aplListAccess2Inst*,APLAGGR_AUTOKILLREF> m_ListDelaedAccessBI;

	// если true (значение по умолчанию) то при сохранении изменившихся аггров производится их синхронизация с актуальной версией с сервера
	bool m_IsActualizeChangedAggr;

	// Если в ini параметр [Options]SetAccessShowInst=1 то функция назначения доступа показывает сообщение со списком инстансов
	bool m_SetAccessShowInst;

	bool m_hide_mode;

	CaplStrStrMap m_bd_parameters;
	
	// массив пар инстансов/атрибутов для которых не вызывать сравнение аггров
	CaplMap m_not_compared_aggr;
	
	// Параметры определяют, надо ли проверять доступ текущего пользователя к экстенту
	// перед назначением доступа
	bool m_check_cur_access_befor_set_access;
	// после назначения доступа
	bool m_check_cur_access_after_set_access;


public:
	//Геттер и Сеттер для m_IsActualizeChangedAggr (	// если true (значение по умолчанию) то при сохранении изменившихся аггров производится их синхронизация с актуальной версией с сервера)
	bool NET_SetActualizeChangedAggr (bool bEnable) {bool bOld = m_IsActualizeChangedAggr ; m_IsActualizeChangedAggr = bEnable ; return bOld ;} ;
	bool NET_GetActualizeChangedAggr (bool /*bEnable*/) {return m_IsActualizeChangedAggr;} ;

	/**@name Вспомогательные функции */
	//@{
	/// возвращает строку про лицензию
	bool NET_GetLicenseStatus(CString &status, long &code);
	/// возвращает список пользователей, присоединенных к БД
	bool NET_GetActiveUserList(CaplTAggr <CaplInstance*, CaplInstance*, APLAGGR_LIST> &ext, LPCTSTR wait_text = 0, CUIntArray *array_ip = 0);
	bool NET_GetActiveUserList(CaplTAggr<SUserLogInfo*,SUserLogInfo*,APLAGGR_AUTOKILLREF> &ListConnects, bool only_me = false, LPCTSTR wait_text = 0);
		
	/** возвращает дату и время на сервере. Для lite/СХД это время ОС, для ORACLE / PostgreSQL это врмея на сервере СУБД*/
	bool NET_GetServerDateTime(COleDateTime &odt);
	CString NET_GetServerDateTime();

	/// отображает диалог с историей изменения атрибутов и поиском по параметрам
	bool ShowAttrsHistoryDlg();
	/// возвращает списки ентитей, которые сейчас отслеживаются, и инстансы которых храняться в истории изменения атрибутов
	bool NET_GetAttrsHistoryEntities(CArray<CaplEntity*,CaplEntity*> &list_active, CArray<CaplEntity*,CaplEntity*> &list_all, aplExtent &users, LPCTSTR wait_text = 0);

	/// запрашивает историю изменения значений атрибутов
	bool NET_GetAttrsHistory(SQAH_Filter &filter, CaplTAggr<SQAH_Info*,SQAH_Info*,APLAGGR_LIST_OR_AUTOKILLREF> &list_rez, LPCTSTR wait_text = 0);

	/** Возвращает в строковом массиве все значения одного атрибута всех иснтансов
		@param attr атрибут, значение которого будет возвращено
		@param count_in_result количество значений, которые надо вернуть на клиента
		@param values массив значений атрибута
		@param real_size количество инстансов указанного типа в БД
		@param source описание источника кода (для занесения в лог на сервере). Рекомендуем подставлять макрос DEF_SOURCE
		@param wait_text сообщение, которое будет выводиться в диалоге ожидания ответа сервера. При пустом значении выводится сообщение по умолчанию
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_GetAllAttrValues(CaplAttr* attr, DWORD count_in_result, CaplTAggr <CaplValue*,CaplValue*,APLAGGR_UNIQUE_LIST_AUTOKILLREF> &values, DWORD &real_size,
								LPCTSTR source = 0, LPCTSTR wait_text = 0);


	/// Получить список атрибутов, в которых живут идентификтаоры БЛОБов. Список отсортирован по id атрибута
	/// in - идентификатор атрибута, out - указатель на CaplAttr
	bool NET_GetAttrs4Blobs(CaplMap &list_attrs, LPCTSTR wait_text = 0);


	/// запрашивает историю коннекта пользователей
	bool NET_QueryUsersLog(CaplTAggr<SUserLogInfo*,SUserLogInfo*,APLAGGR_AUTOKILLREF> &array, LPCTSTR wait_text = 0, QUL_Filter* filter = 0);

	/** чистит историю коннекта пользователей
	@param mode режим очистки:
	0 - удаляются все записи (массив array может быть пустым)
	1 - удаляются записи, перечистенный в массиве array (фильлтрация идет по дате-времени подключения; остальные 
		поля структуры SUserLogInfo можно не заполнять)
	2 - удаляются записи, предшевствующие записи с индексом 0 в массиве array (фильтрация идет по 
		дате-времени подключения пользователя; остальные поля структуры SUserLogInfo можно не заполнять)*/
	bool NET_ClearUsersLog(CaplTAggr<SUserLogInfo*,SUserLogInfo*,APLAGGR_AUTOKILLREF> &array, int mode, LPCTSTR wait_text = 0);	

	/// загружает список переменных сервера
	bool NET_LoadBDInfo();
	/// По имени переменной возвращает предыдущее полученное с сервера значение. Если значения нет - пустую строку
	bool NET_GetBDStringInfo(LPCTSTR param_name, CString &param_value);
	CString NET_GetBDStringInfo(LPCTSTR param_name);
	/// Добавляет пару инстанс-атрибут, для которых не нужно призводить сравнение изменившихся АГГРов при ближайшем SaveChange
	void AppendNotComparedAggr(CaplInstance *inst, CaplAttr *attr);

/*
	CaplSQLResult myValues[5];
	myValues[0].field="sss";
	myValues[0].type=aplString;
	aplRunSql("", myValues ,5)
*/
	/// Только для версии под Oracle и PostgreSQL! Выполняет SQL и возвращает таблицу результатов в виде чисел-строк
	bool NET_RunSql(LPCTSTR sql, SaplSQLResult *result, int count, SaplSQLError* oracle_error,
				int code1 = 0, int code2 = 0, LPCTSTR wait_text = 0, LPCTSTR sql_prev = 0, LPCTSTR source = _T("")); 
	/// Только для версии под Oracle и PostgreSQL! Выполняет SQL и возвращает и возвращает экстент инстансов
	bool NET_RunSqlReturnExtent(LPCTSTR base_sql, aplExtent &result, SaplSQLError* oracle_error,
					LPCTSTR sql_get_result = 0, int code1 = 0, int code2 = 0, LPCTSTR wait_text = 0, bool load_all_attrs = false, LPCTSTR source = _T("")); 

	/** Записывает в лог на сервер сообщение от клиента. Для сервера ORACLE/PostgreSQL если is_oracle==true,
	то log_name может быть пустым
		@param log_name имя файла клиентского лога (располагается на сервере в каталоге с логом сервера)
		@param message сообщение
		@param is_oracle если true и сервер ORACLE/PostgreSQL - дублирует сообщение в таблицу Clients_log (сообщение обрезается до 3000 символов)
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_WriteLog(CString log_name, CString message, bool is_oracle = false);

	/** Только для версии под Oracle и PostgreSQL!
	 * Записывает в специальную таблицу и в файл журнала информацию о факте доступа текущего пользователя к документу. Читает из БД количество
	 * уникальных документов, прочитанных за время, указанное в опции "Протоколирование\\Документы\\Интервал времени для контроля", или
	 * за 60 минут, если опция не задана
        @param doc документ, который берется на чтение
		@param num_readed в этой переменной возвращается количество уникальных документов, прочитанных текущим пользователем за период контроля
		@param log_name имя файла журнала
		@param message дополнительное сообщение, например информация о клиенте или сеансе
		@param is_oracle если true, то информация записывается в таблицу Clients_log в БД. Если false, то не записывается
		@return <b>true</b> при удачном выполнении и <b>false</b> в случае ошибки */
	bool NET_ControlAccessDocAndWriteLog(CaplInstance *doc, long &num_readed, CString log_name, CString message, bool is_oracle = false);
	
	/// Зарезервировано
	bool NET_Test(LPCTSTR wait_text = 0, int id = 0, int id2 = 0);

	/// Зарезервировано
	bool NET_RunUpdateDictionary(CString new_dict_path = _T(""), bool autostart = false);
protected:
	bool NET_RunUpdateDictionaryInt(CString new_dict_path);

	SUserLogInfo* ReadUserLogInfoFromDataBuf(CaplDataBuf &dbuf, int i_ver_buf);
public:
	bool NET_RunApp(CString app_name, CString cmd_line, bool print2log);


	// включает принудительное восстановление соединения при обрыве вне зависимости от флага в iniшке
	void ForceAutoReconnect();

	/// Установка режима автоматической загрузки атрибутов
	void SetAutoDownloadMode(bool mode);

    /** Устанавливает режим отложенного назначения доступа. Важно! Если в ini задан параметр Options\SetAccessWithSave - то перед
	каждой установкой соединения флаг будет прочитан из ini и заменен на значение, прочитанное из ini.
		@param mode Если true - то функции назначения доступа сохраняют данные о доступе в буфере в кеше; данные о доступе  
				уходят на сервер только при вызове NET_SaveChanges после собственно сохранения данных
		@return возвращает предыдущее значение флага */
	bool SetModeSetAccessWithSave(bool mode);
	
	/// Возвращает текущий режим автоматической загрузки атрибутов
	bool GetAutoDownloadMode();
	
	/// Установка режима вывода сообщений об ошибках
	bool SetNetErrorMessageMode(bool mode);
	
	/// Установка режима полной невидимости (отключает все всплывающие сообщения)
	/// Возвращает предыдущее значение
	bool SetHideMode(bool mode = false);
	bool GetHideMode();

	/// установка размера порции при сохранении данных
	bool SetPortionSavedInst(int size);
	/// определение количества уже сохраненых данных при сохранени данных по проциям
	int GetPercentSCh();
	
	void Detach();
	void Attach();
	void SetHalt();

	// если есть temporary instance и у нее атрибут BLOB - то он хранится в этом массиве до сохранения
	// работа с этим массивом - пока на уровне менеджеров. Используют его запросы и сводная таблица
	CaplTAggr<CaplDataBuf*,CaplDataBuf*,APLAGGR_LIST_OR_AUTOKILLREF> m_query_temporary_data;

	// Параметры определяют, надо ли проверять доступ текущего пользователя к экстенту
	// перед назначением доступа
	// после назначения доступа
	void SetCheckCurAccess(bool befor_set_access, bool after_set_access);
	
	// если версия словаря БД меньше, чем требуемая, возвращает false
	// требуемая версия словаря читается из файла pss.ver в каталоге установки программы
	bool IsVersionOk();

	bool ReadFromBuferUserArray(CaplDataBuf &buf_out, aplAccessList *list, int start_in_portion, int size_in_user);
	bool AppendInBufUserArray(CaplDataBuf &buf_in, aplAccessList *list, int start_in_portion, int size_in_user, aplExtent* ext = 0, bool setaccess = false);

	bool WriteLocalLog(LPCTSTR message);
	bool WriteLocalLog(aplLogMode minLogMode, LPCTSTR message); // Записывает в лог только если текущий уровень больше или равен minLogMode

	bool SetApplicationCloseFunction(long (__cdecl *_application_close_funct)(LPVOID), LPCTSTR message = 0);

	// Отображает MessageBox c информацией для нескольких inst
	void ShowInstancesDebugInfo(CaplInstance *inst1, CaplInstance *inst2 = 0, CaplInstance *inst3 = 0, CaplInstance *inst4 = 0, CaplInstance *inst5 = 0);	
	void ShowExtentDebugInfo(aplExtent  *ext);				// Отображает MessageBox c информацией о ext
	void PrintInstanceDebugInfo(CaplInstance *inst, CString &str); //Формирует строку с информацией о inst
	bool PrintQuery(CString &query_lng_out);

	// Убираем восстановленный инстанс из массива удаленных
	bool RecoveryInst(CaplInstance* ciInst);

#ifdef _DEBUG
	CString m_csTestFileName;

#endif

};


#define NET_StartAdminMode(par1, par2) NET_StartAdminMode2(par1, par2, DEF_SOURCE)


/** Поиск в кеше и на сервере список <B>instance</B> указанного типа, имеющих значения атрибутов,
указанные массивом значений. При сравнении строк регистр не учитывается ("Id" и "id" - одно и то же).
Макрос предназначен для поиска для выдачи пользователю в интерфейсе
	@param entity тип искомых <B>instance</B>
	@param count количество сравниваемых атрибутов
	@param values массив значений атрибутов
	@param extent_out результирующий список
	@param is_substring учитывать при сравнении строк  подстроки или нет.
		<b>true</b> - в результат будут включены <B>instance</B>,
		строковые атрибуты которых включают подстроки, указанные в массиве атрибутов.
		<b>false</b> атрибуты искомых <B>instance</B> должны быть равны указанным
	@return Количество найденных <B>instance</B>*/
#define NET_FindInstancesWithAttrValues(entity ,count, values, extent_out, is_substring) \
			NET_FindInstancesWithAttrValues2(entity, count, values, extent_out, is_substring, false, 0, aplSBMiddle, false, DEF_SOURCE)

/** Ищет в кеше и на сервере список <B>instance</B> указанного типа, имеющих значения атрибутов,
указанные массивом значений. При сравнении строк регистр учитывается ("Id" и "id" - разные)
Макрос предназначен для поиска по уникальному id для кэширования
	@param entity тип искомых <B>instance</B>
	@param count количество сравниваемых атрибутов
	@param values массив значений атрибутов
	@param extent_out результирующий список
	@param is_substring учитывать при сравнении строк  подстроки или нет.
		<b>true</b> - в результат будут включены <B>instance</B>,
		строковые атрибуты которых включают подстроки, указанные в массиве атрибутов.
		<b>false</b> атрибуты искомых <B>instance</B> должны быть равны указанным
	@return Количество найденных <B>instance</B>*/
#define NET_FindInstancesWithAttrValuesMatchCase(entity ,count, values, extent_out, is_substring) \
			NET_FindInstancesWithAttrValues2(entity, count, values, extent_out, is_substring, true, 0, aplSBMiddle, false, DEF_SOURCE)



class CaplStr2InstMap:public CaplMap{
	// in - указатель на строку, out - instance
public:
	int Add(CString* str, CaplInstance* inst){return CaplMap::Add((long)str, (long)inst); }
	void SortStr(){qsort(Data, Size, sizeof(aplMap_element), CompareInstId); }
	int static CompareInstId( const void *p1, const void *p2)
	{
		aplMap_element *i1, *i2;
		i1 = ((aplMap_element*)p1);
		i2 = ((aplMap_element*)p2);
		return ((CString*)i1->in)->CompareNoCase(*(CString*)i2->in);
	}
	CaplInstance* GetInstByIndx(int indx){ return (CaplInstance*)Data[indx].out; }
	CString* GetStrByIndx(int indx){ return (CString*)Data[indx].in; }
	void Clear(){ for(int i = 0; i<Size; i++){ delete GetStrByIndx(i); }CaplMap::Clear(); }
	virtual ~CaplStr2InstMap(){ Clear(); }
};

class CLASS_DECL_APL_NSD CaplParentWndProcesser
{
public:
	CaplParentWndProcesser(CaplNetStepData* data=0, CWnd* parent=0)
	{
		m_setted = false;
		SetDataParentWnd(data, parent);
	}
	CaplParentWndProcesser(CaplNetStepData& data, CWnd* parent=0)
	{
		m_setted = false;
		SetDataParentWnd(&data, parent);
	}
	void SetDataParentWnd(CaplNetStepData* data, CWnd* parent)
	{
		m_data = data;
		m_oldParentWnd = NULL;
		// Защита от повторного вызова
		if(m_setted)
			return;
		if(m_data != 0)
		{
			m_oldParentWnd = m_data->GetParentWnd();
			m_data->SetParentWnd(parent);
			m_setted = true;
		}
	}
	~CaplParentWndProcesser()
	{
		if(m_data != 0) 
			m_data->SetParentWnd(m_oldParentWnd);
	}
protected:
	CaplNetStepData* m_data;
	CWnd* m_oldParentWnd;
	bool m_setted;
};

// Макрос предотвращает потерю модельности диалога при появлении Wait диалога при долгой реакции сервера
// Необходимо добавить его во все функции диалога, которые читают данные с сервера
// Параметр можно передавать и как указатель на CaplNetStepData, и по ссылке.
#define CORRECT_LOOSE_MODAL(CaplData) CaplParentWndProcesser pwp(CaplData,this);

// Макрос предотвращает потерю модельности диалога при появлении Wait диалога при долгой реакции сервера
// используется в паре с переменной класса CaplParentWndProcesser m_pwp
// Надо объявить в классе пермеенную CaplParentWndProcesser pwp и поместить макрос в OnInitDialig до первого обращения к серверу
#define CORRECT_LOOSE_MODAL_ON_CLASS(CaplData)  m_pwp.SetDataParentWnd(CaplData,this);

// Вспомогательный макрос
#define CORRECT_LOOSE_MODAL_WITH_WINDOW(CaplData, pWnd)  CaplParentWndProcesser pwp(CaplData,pWnd);

// заменяет в БД все ссылки на inst1 на ссылки на inst2.  Типы объектов берет по словарю.  Если bUseSelect====true - проверяются еще и все Select и Aggr
// bAutoRun==true - автоматически запускает замену (без нажатия кнопки)
// bAutoHide==true - автоматически закрывать окно после выполнения. Работает только если bAutoRun==true
bool AFX_EXT_API aplReplaceInstance(CaplNetStepData *data, CaplInstance *inst1, CaplInstance *inst2, bool bUseSelect, bool bAutoRun = false, bool bAutoHide = false);

// Ищет в БД все ссылки на inst1.  Типы объектов берет по словарю.  Если bUseSelect====true - проверяются еще и все Select и Aggr
// Если ext_with_ref !=- в нем возращает список ссылающихся inst.
// Если sReport  != 0 - в нем возвращается отчет о поиске
bool AFX_EXT_API aplFindAllInstanceRef(CaplNetStepData *data, CaplInstance *inst1, bool bUseSelect, aplExtent *ext_with_ref, CString *sReport);

// Проверяет, существует ли папка, указанная в filename
// Если папки нет - создает их, начиная с верхнего уровня
// Путь в filename должен быть абсолютным
bool AFX_EXT_API CheckAndCreateFolder(LPCTSTR filename);

// Отправляет email через почтовый сервер server 
// При успешной отправке функция возвращает true, в err_mess - ответы сервера
// При ошибке - false, в err_mess - описание ошибки.
bool AFX_EXT_API SendSimpleEMail(CString &err_mess, LPCTSTR server, LPCTSTR recipient_email,
								 LPCTSTR sender_email, LPCTSTR sublect, LPCTSTR message);


//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.


#endif // !defined(AFX_aplNetStepData_H__53498523_74F0_11D3_B380_00C026EE2281__INCLUDED_)
