/*****************************************************************\
            Author: Дещеревский И.
              Date: 
              
              File: sl_struct.h
   Version of file: 0.10
           Progect: AplNetTransportServTCP
Version of project: 3.0
              
             Notes: Этот файл описывает структуры, используемые при 
		передаче данных между промежуточным сервером ORACLE и сервером лицензий
              
\******************************************************************/
#ifndef APL_SL_STRUCT_H
#define APL_SL_STRUCT_H

#include "aplSocketTransport.h"

#define SPEC_LIC_TYPE _T("XXX-YYY-ZZZ")
#define SPEC_LIC_MESS APL_T("<Специальная>")

#define SL_VER_UNKNOWN 0xFFFFFFFF
#define SL_VER_OBSOLETE 0
// после отключения последнего клиента сервер лицензий обрабатывает еще столько запросов на обновление состояния и только потом удаляется
#define SL_DESCR_DEL_COUNTER 5

// версия 1100 - ReportConstructor и старые сервера
// версия 1102 - предыдущий сервер приложений (до 2024)
// версия 1104 - актуальная версия сервера приложений (с 2024)
#define VER_SL_DATA_OLD 1100
#define VER_SL_DATA_1102 1102
#define VER_SL_DATA 1104

enum eSLBufGeneration
{
	SLBufGen_0 = 0,
	SLBufGen_1 = 1,
	SLBufGen_2 = 2
};


#define LIC_MODE_DEFAULT	0x0

/////////////////////////////////////////////////////////////////////////////
// сообщения об ошибках и статусах
#define ERR_MESSAGE_SL_CONNECTING APL_T("Идет соединение с сервером лицензий...")
#define ERR_MESSAGE_SL_NOT_CONNECT APL_T("Нет соединения с сервером лицензий!")
//#define ERR_MESSAGE_SL_KEY_NOT_FOUND APL_T("Сервер лицензий не нашел ключ!")
#define ERR_MESSAGE_SL_MISSED_VERSION APL_T("Устаревшая версия сервера лицензий!")

// Тайм-ауты работы с СЛ
// если установить соединение с сервером лицензий не удается - то повторяем запрос не раньше чем через SL_CONNECT_ATTEMPT_TICK милисекунд
#define SL_CONNECT_ATTEMPT_TICK 5000
// если нет срочных вызовов (коннект, дисконнект) информация о статусе сервера лицензий запрашивается не чаще чем через SL_REQUEST_TIME милисекунд
#define SL_REQUEST_TIME 5000



/****************************************************************************/
/* СП -> СЛ
/****************************************************************************/
enum EaplSLCommand: UINT32
{
	apl_SL_ADD		= 0,	// блок запроса лицензии / добавления клиента
	apl_SL_DELETE	= 1,	// блок удаления клиента
	apl_SL_GET_LIC	= 2,	// блок с данными по одному типу лицензий
	apl_SL_GET_DATE	= 3,	// блок с запросом даты ближайшего окончания ключа
	apl_SL_RENEW	= 4,	// блок с обновлением информации о уже подключенном клиенте
	apl_SL_GET_VER	= 5,	// блок с запросом/ответом версии протокола
	apl_SL_REVOKES	= 6		// блок с информацией про отозванные ключи
};


struct SOCKET_TRANSPORT_API apl_SL_PS_DATA{
public:
	apl_SL_PS_DATA(){
		ver=VER_SL_DATA;	server_ip=0; server_port=0; client_id_m=0;client_id_s1=0;client_id_s2=0;client_ip=0;
		type_license=0xFFFFFFFF;data_1=0xFFFFFFFF;data_2=0xFFFFFFFF;data_3=0xFFFFFFFF;
	}
	long Get(){return ver;}
	void Set(long _ver){ver=_ver;}
	bool ReadFromIterator(CaplDataBufEx &dbuf, eSLBufGeneration mode);
	bool Add2Iterator(CaplDataBufEx &dbuf, eSLBufGeneration mode);
	bool Compare(apl_SL_PS_DATA *p_sl_data);
	EaplSLCommand command; // long action;
	UINT32 server_ip;	//Ip записывать с ОБРАТНОМ порядке байт (для совместимости СЛ с СП под win и lin)
	UINT32 server_port; 
	UINT32 client_id_m; // идентификатор клиента
	UINT32 client_id_s1; // идентификатор клиента дополнительный
	UINT32 client_id_s2; // идентификатор клиента дополнительный
	UINT32 client_ip;
	UINT32 type_license;
	UINT32 data_1;
	UINT32 data_2;
	UINT32 data_3;
protected:
	UINT32 ver;
};

// Супер числа
#define apl_NUMBER_0  0xB0B322F3
#define apl_NUMBER_1  0x18BE4EC6
#define apl_NUMBER_2  0x4AE0F28B  
#define apl_NUMBER_3  0x2CD645D8
#define apl_NUMBER_4  0x6951F63E
#define apl_NUMBER_5  0x164957A8
#define apl_NUMBER_6  0x5AF0E6CA
#define apl_NUMBER_7  0x12DB0261
#define apl_NUMBER_8  0x7E86BA85
#define apl_NUMBER_9  0x4D0600B1

#define HEADER_ACCESS_BUFER_N_V_001 _T("HEADER_ACCESS_BUFER_N_V_001")


struct SOCKET_TRANSPORT_API SLTransportData
{
	SLTransportData();
	SLTransportData(SLTransportData *src);
	void Set(SLTransportData *src, bool bAllData=false);
	void Get(apl_SL_PS_DATA *dest, CStringArray &types, CaplStrMap &indexes);
	bool Compare(SLTransportData *src);
	bool Read(CaplDataBufEx& dbuf);
	bool Write2Iterator(CaplDataBufEx& dbuf);
	// Параметры сервера лицензий
	UINT32 SL_ip;
	UINT32 SL_port;
	//////// Данные отправляемые на сервер лицензий
	// Команда
	EaplSLCommand command;
	// Параметры клиентского приложения
	UINT32 Client_ip;
	UINT32 client_id_m; // идентификатор клиента
	UINT32 client_id_s1; // идентификатор клиента дополнительный
	UINT32 client_id_s2; // идентификатор клиента дополнительный

	// Параметры текущего сервера. Для запроса от клиента без подключения равны нулю
	UINT32 server_ip;
	UINT32 server_port;
	// Тип лицензии
	CString Type_license;
	/////// Данные получаемые с сервера лицензий
	// Протухает ли какой-то ключ в ближайшее время и дата протухания
	UINT32 is_use_by_date;
	DATE dt;
	// Была ли ошибка чтения ключа
	UINT32 key_error;
	// 
	int aplError;
	// Статус сервера лицензий для вывода пользователю
	CString SL_status;
};



class SOCKET_TRANSPORT_API CServLicDescription
{
public:
	CServLicDescription(UINT32 sl_ip, UINT32 sl_port);
	~CServLicDescription();

public:
	/**
		Заносит команды из списка arr_transport_data во внутренний список на отправку серверу лицензий.
		Если в списке есть команды apl_SL_ADD (запросить лицензию) или apl_SL_DELETE то сразу отправляет 
			список на СЛ и заносит результаты обратно в команды.
		При каждой отправке запрашивает у СЛ текущий набор лицензий и дату ближайшего окончания ключа и
			записывает во внутренний объект m_transport_data.
		Если команд "добавить" и "удалить нет", то проверяет время последней отправки и по его истечению 
			запрашивает СЛ чтобы обновить список лицензий
	*/
	bool ProcessRequest(CaplTAggr<SLTransportData*, SLTransportData*, APLAGGR_AUTOKILLREF> &arr_transport_data);
	// Запросить текущий статус СЛ.
	inline bool ProcessRequest(){CaplTAggr<SLTransportData*, SLTransportData*, APLAGGR_AUTOKILLREF> arr; return ProcessRequest(arr);}

	bool RemoveClient(int client_id);
	void AddClient(UINT32 client_id)
	{
		CaplEnterCriticalSection ecs(&m_data_protect);
		m_list_clients_users.Add(client_id, 0);
		m_live_counter = SL_DESCR_DEL_COUNTER;
	}

	inline UINT32 GetSLPort(){return m_sl_data.SL_port;};
	inline UINT32 GetSLIp(){return m_sl_data.SL_ip;};
	inline CString GetStatus(){return m_sl_data.SL_status;}
	inline CString GetErrDescr(){return m_ErrDescr;}

	// Надо ли выводить в лог статистику времени операций с лицензиями; 0- не надо; число больше 0 - 
	// интервал времени в минутах для выводжа статистики (минимум 15), -1 - выводить статистику только при завершении работы
	static void SetTimeLogStatLicense(int _TimeLogStatLicense);

	int m_TimeLogStatLicense;
	inline void LogStatistic(){if(m_TimeLogStatLicense != 0 && m_num_request != 0){LogStatisticB();}}
	void LogStatisticB();

	CaplMap m_list_clients_users;

	int m_live_counter;
	DWORD m_SL_ver;

	// сбор статистики времени выполнения запросов
	DWORD m_time_request_max;
	DWORD m_time_request_all;
	DWORD m_num_pakets_max;
	DWORD64 m_num_pakets_all;
	DWORD64 m_num_request;
	COleDateTime m_odt_stat_print;

	CAplCriticalSection m_data_protect;

protected:
	bool TestConnect();
	bool ProcessRequestData();
	bool ProcessRequestVer();

	CaplTimeMeter m_LastTick;
	DWORD m_last_bad_tick;

	bool m_old_ver;

	CaplSocketClient m_slSocket;

	bool m_messagin_err;
	bool m_after_halt;

	CaplTAggr<SLTransportData*, SLTransportData*, APLAGGR_LIST_OR_AUTOKILLREF> m_list_sl_queries;

	// информация о дате и ошибке ключа - для операций apl_SL_RENEW идущих "на потом"
	SLTransportData m_sl_data;

	CString m_class_info;
	CString m_ErrDescr;
};


bool SOCKET_TRANSPORT_API EnMaskSL_PS_DATA(apl_SL_PS_DATA *p_sl_data, const char* mask_data, int mask_size);

#endif // APL_SL_STRUCT_H

