/**
 * @file    iec103ttylink.h
 * @brief   IEC61850 与rdb 交互处理 的头文件
 *
 * @version $Revision: 1.18 $
 * @date    $Date: 2018/12/29 12:30:29 $
 * @author  $Author: lizhongming $
 * @state   $State: Exp $
 * @latest  $Id: rdb_client.h,v 1.18 2018/12/29 12:30:29 lizhongming Exp $
 */

#ifndef _RDB_CLIENT_H_XSDFSDFSEFS15156SFS
#define _RDB_CLIENT_H_XSDFSDFSEFS15156SFS

#include "interface.h"
#include "ied.h"
#include "node.h"

//lnk20250113添加包含台账定义的头文件
#include "../json/save2json.h"
#include <stdbool.h>

//文件有效时间的取值
#define FROM_FILE_NAME		(0)
#define FROM_SYSTEM			(1)

//通用文件存放的目录
#define GENERAL_PREFIX		"0_0"
#define GENERAL_PATH		"0_0\\19700101\\00"

//iec report 数据到达状态
#define  VALUE_REACHED      (0x01)  // 状态或遥测值已收到
#define  Q_REACHED      	(0x02)  // 数据质量已收到
#define  T_REACHED    		(0x04)  // 时标已收到
#define  REASON_REACHED    	(0x08)  // 发送原因已收到

//CHANNELSTATE macro defines
#define  CHANNEL_CONNECTING			(0x01)  // 
#define  CHANNEL_CONNECTED      	(0x02)  // 
#define  CHANNEL_DISCONNECTING    	(0x03)  // 
#define  CHANNEL_DISCONNECTED    	(0x04)  // 


#define  RELAY_SELECT			(0x01)  //
#define  RELAY_RUN				(0x02)  //
#define  RELAY_CANCEL			(0x03)  //

#define	MIN_INIT_NUM			(10)		//链路层完全初始化最少次数，作为可以进行召唤录波文件的条件。
#define NEXT_CONNECT_TIME		(10000) //一次链接失败后，下次链接时间间隔10*1000=10s

#define MAX_SAME_FCDNAME_OBJECTS (500)   // for 灿能PQ装置，改成64 2016-5-10 //最多一个FCD分成多个对象的个数 ，如一个 ACT对象，分成general，phsa，b，c等数个对象

/** ======================浙江渔都变顺控扩展同期功能============================ */
/*
16:按定值方式合闸
17:不检同期合闸
18:检同期合闸
19:检无压合闸
CHECK_BY_SETTING CHECK_U 对应顺控票同期遥控点的第一个遥控点
CHECK_NOTHING  CHECK_SYN 对应顺控票同期遥控点的第二个遥控点
*/
#define CHECK_START_QU		16
#define CHECK_BY_SETTING	0
#define	CHECK_NOTHING		1
#define	CHECK_SYN			2
#define CHECK_U				3

#define DEFAULT_EDIT_FXDAREANO					(0x80FE)	/**< 默认编辑区定值区号		*/
#define FIXED_AREA_GRP_DOT2_EDIT_AREA			(2)			/**< 定值区组->编辑定值区点 */

//lnk添加使能标志20250121
#define ENABLE 1
#define UNUSED 0

extern unsigned int	g_node_id;

typedef struct element_usr_t element_usr_t;
typedef struct rptinfo_t rptinfo_t;
typedef struct loginfo_t loginfo_t;
typedef struct LD_info_t LD_info_t;
typedef struct ied_usr_t ied_usr_t;
typedef struct chnl_usr_t chnl_usr_t;
typedef struct autorecall_t autorecall_t;

typedef struct ied_info_t ied_info_t;
//////////////////////////////////////////////////////////
struct autorecall_t {
	long long start;
	long long end;
	int need_steady;	//lnk20241030添加补招稳态暂态标志
	int	need_voltage;
};
//////////////////////////////////////////////////////////
struct ied_info_t{
	char time[50][20];
	unsigned char name[50][128];
	char value[50][20];
};
//lnk20250113添加台账更新结构///////////////////////////////
#define MAX_UPDATEA_NUM 10
typedef struct trigger_update_xml_t trigger_update_xml_t;
struct trigger_update_xml_t{
	int			work_update_num;
	int			new_update_num;
	int			delete_update_num;
	int			modify_update_num;
	terminal	work_updates[MAX_UPDATEA_NUM];
	terminal	new_updates[MAX_UPDATEA_NUM];
	terminal	delete_updates[MAX_UPDATEA_NUM];
	terminal	modify_updates[MAX_UPDATEA_NUM];
};

//////////////////////////////////////////////////////////
#define MAX_TRIGGER_NUM 300
typedef struct trigger_t trigger_t;
struct trigger_t{
	int dev_idx;
	int line_id;
	int real_data;
	int soe_data;
	int limit;
	int count;
};
typedef struct trigger_3s_xml_t trigger_3s_xml_t;
struct trigger_3s_xml_t{
	int			work_trigger_num;
	int			new_trigger_num;
	int			delete_trigger_num;
	int			modify_trigger_num;
	trigger_t	work_triggers[MAX_TRIGGER_NUM];
	trigger_t	new_triggers[MAX_TRIGGER_NUM];
	trigger_t	delete_triggers[MAX_TRIGGER_NUM];
	trigger_t	modify_triggers[MAX_TRIGGER_NUM];
};

/////////////////////////////////
#define MAX_RECALL_NUM 300
typedef struct recall_t recall_t;
struct recall_t{ 
	char* line_id;
	long long		start_time;	 //待召唤日志起始时间
	long long		end_time;	 //待召唤日志结束时间
	int need_steady;
	int need_voltage; 
};
typedef struct recall_xml_t recall_xml_t;
/*struct recall_xml_t{
	int			work_recall_num;
	int			new_recall_num; 
	recall_t	work_recalls[MAX_RECALL_NUM];
	recall_t	new_recalls[MAX_RECALL_NUM]; 
};*/
/* 动态数组 + 容量字段 lnk20250801*/
struct recall_xml_t{
    int       work_cnt, work_cap;
    int       new_cnt , new_cap;
    recall_t *work_recalls;
    recall_t *new_recalls;
};
/////////////////////////////////////////////////////////////
struct element_usr_t{
	char*	FCD_ref;
	char*	FCDA_ref;
	char*	Full_FCDA_ref;
	
	double		m_v;
	char		q[14];    //q use  13 bits
	systime_t	tm; 
	char		reason[7];	// reserve 1 bit, use 5 bits
	uint32_t	DataStatus;

	int			m_num_same_FCD_Objects;
//	element_t*  m_pSameFCDObjects[MAX_SAME_FCDNAME_OBJECTS];

	int			num_same_FCDA_Objects;
//	element_t*  pSame_FCDA_Objects[MAX_SAME_FCDNAME_OBJECTS];

	byte_t		is_phase_soe;
	byte_t		last_soe_status;
};

struct rptinfo_t{
	char*		rptID;
	byte_t		instanceNeedSuffix;			//实例名是否增加后缀
	byte_t		TrgOpt;
	byte_t		OptFlds [2];				/* 10 bit bitstring but only allow write of 9 bits*/
	uint32_t	IntgPd;						//完整性上送时间（秒）
	int			report_PQ_type;            //报告前置类型，统计、实时、soe、事件类型等

	LD_info_t*		LD_info;

	int				rpt_registered;				//是否注册成功
	byte_t 			chnl_id;					//如果未注册，下次试图注册报告的通道号 
												//如果已注册，则是本次注册报告的通道号

	RCB_INFO * 		m_rcb_info;
	double 			m_LastDataTime;				//上次收到数据的时间
	double			m_LastGITime;				//上次GI的时间
	double			m_LastRegisterFailedTime;	//上次注册失败的时间
	double			m_LastUnRegisterFailedTime;	//上次取消注册失败的时间
	byte_t			m_EntryID[8];
	int				m_curRptSuffix;
	int				count;						//收到报告数据的次数
	int             rptNo;//CZY 2023-08-17 WW 2022-11-14增加编号用于匹配数据收集
	int             flickerflag;//CZY 2023-08-17 WW 2022-11-14增加闪变标志

	int             pstflag;//CZY 2023-08-17 WW 2022-11-14增加短闪闪变标志

};

struct loginfo_t{
	char*			lcbName;
	char*			datasetName;
	char			logName[32];
	uint32_t		IntgPd;							//完整性上送时间（秒）
	byte_t			reasonCode;
	byte_t			TrgOpt;

	LD_info_t*		LD_info;
	//LCB_INFO * 		m_lcb_info;
	apr_time_t		start_time;						//待召唤日志起始时间
	apr_time_t		end_time;						//待召唤日志结束时间

	//double			last_checktime;
	int				need_steady;
	int				need_voltage; 
};

#define QVVR_NUM		(256)

#define QVVR_DATA_NOT_USED		(0)
#define QVVR_DATA_RECEIVED		(1)
#define QVVR_DATA_PAIRED		(2)

typedef struct QVVR_t QVVR_t;
struct QVVR_t{
	int					used_status;
	int					QVVR_start;
	int					QVVR_type;
	long long			QVVR_time;	
	double				QVVR_PerTime;
	double				QVVR_Amg;
	char                QVVR_Rptname[128];

	uint32_t			timestamp;
};
struct LD_info_t{
	char				name[256];
	ied_t				*ied;
	byte_t				cpuno;
	char				*LD_name;
	apr_hash_t			*ht_fcd;			/**< FCD object hash索引 到 element		*/
	apr_hash_t			*ht_full_fcda;		/**< 完整FCDA object hash索引 到 element		*/
    int					rptcount;			/**< report  个数              */
    rptinfo_t			**rptinfo;			/**< rptinfo_t* 数组				   */
	int                 read_flag ; //CZY 2023-02-28 判断是否将监测点是否有效

	//测点日志等级
	int log_level;	//0 ERROR 1 WARN 2 NORMAL 3 DEBUG

	char mp_id[256];//CZY 2023-08-20 监测点编码，例：8afaa
	char terminal_code[256];//CZY 2023-08-20 终端编码
	//int  ld_ins;//CZY 2023-08-20 逻辑设备实例号，例：1
	char voltage_level[256];//CZY 2023-08-20 电压等级，例：30
	char v_wiring_type[256];//CZY 2023-08-20 监测点电压接线方式，例：01-三相星型，02-三相角型
	long long time;          //CZY 2023-08-20 时间戳(秒) 台账更新时间，例：1691656669 
	int update_flag;//CZY 2023-08-20 台账更新标志 0:keep 2:delete 4:update 8:add
	char monitor_status[64];  //lnk20241031监测点状态
//报告
	int                 rptRecvFlag;//CZY 2023-08-17 WW 2022-11-14判断报告是否收齐,rptRecvFlag=有效报告序号相加
	int                 rptRecvCheckFlag;//CZY 2023-08-17 WW 2022-11-14判断报告是否收齐,每次收到报告相加与rptRecvFlag一起判断是否收完
	int                 rptPstRecvFlag;//CZY 2023-08-17 WW 2022-11-14判断报告是否收齐,rptRecvFlag=有效报告序号相加
	int                 rptPstRecvCheckFlag;//CZY 2023-08-17 WW 2022-11-14判断报告是否收齐,每次收到报告相加与rptRecvFlag一起判断是否收完
//报告

	int registcount;//lnk20250812
	bool has_logged_regist;//lnk20250812

	int                 iUnitOfTime;//CZY 2023-08-17 WW 2022年12月7日15:43:34 装置上送事件持续时间单位切换(0-ms; 1-s)
//不使用
	int                 iStatOfTime;//CZY 2023-08-17 WW 2022年12月7日15:48:33 统计数据时间 0-北京时间 1-UTC时间
	int                 iJournalTime;//CZY 2023-08-17 WW 2022年12月7日15:52:32 补招日志时间(0-UTC时间(日志、录波文件均为UTC时间); 1-北京时间(日志北京时间、录波文件UTC时间 注：仅四川地区+8小时读取补招日志))
//不使用
//日志
    int					logcount;			/**< log  个数              */
	loginfo_t			**loginfo;			/**< loginfo_t* 数组				   */
//日志
//补招
	int                 autorecallflag;
	int					autorecallcount;
	autorecall_t        **autorecall;
//补招
//不使用
	uint32_t            group;          //add by rzx
//不使用
//实时数据
	int					line_id;
//实时数据
//录波
	int					FltNum[256];
//录波
//实时数据
	int					real_data;
	int					soe_data;
	int					limit;
	int					count;
//实时数据
//不使用
	int					SubV_Index;
	int					Dev_Index;
	int					Sub_Index;
	int					GD_Index;
//不使用
	//process QVVR
	QVVR_t				qvvr[QVVR_NUM];
	int					qvvr_idx; 
	//暂态
	//process RDRE
	int					RDRE_FltNum;
	//录波
};

//装置控制初始化
typedef struct
{
    ST_BOOLEAN inited;

    ST_INT ledrs_oper_type_id;
    ST_INT reboot_oper_type_id;
	ST_INT reset_oper_type_id;

} MMS_OPER_TYPE_CACHE;

struct ied_usr_t{	
    LD_info_t  *LD_info;       /**< LD数组                     */
	int			dev_idx;		/**< 设备序号                     */
	char		dev_type[256];	/**< 设备类型                     */
	char		dev_key[256];	/**< 设备秘钥                     */
	char		dev_series[256]; /**< 设备识别码                     */
	char		com_type[32];	/**< 通讯类型 mms/pqdif             */
	int			dev_flag;		/**< 设备标志                     */
	void		*cookie;
	double		last_call_wavelist_time ; //上次召录波列表时间

	int log_level;	//0 ERROR 1 WARN 2 NORMAL 3 DEBUG

	char terminal_id[256];//CZY 2023-08-20 终端id，例：8afaa9a15707483a0157262f8e78077d
	char org_name[256];//CZY 2023-08-20 所属单位，例：南京供公司
	char maint_name[256];//CZY 2023-08-20 运维单位，例：南京供公司
	char station_name[256];//CZY 2023-08-20 所属变电站，例：220kV五台山变
	char tmnl_factory[256];//CZY 2023-08-20 终端厂家，例：南京自动化股份有限公司
	long long		time;          //CZY 2023-08-20 时间戳(秒) 台账更新时间，例：1691656669 
	char tmnl_status[256];//CZY 2023-08-30 运行状态
	char terminal_code[256];//CZY 2023-08-30 终端编码
	int update_flag;//CZY 2023-08-20 台账更新标志 0:keep 2:delete 4:update 8:add

	char processNo[64];//台账进程号

	bool lastconnectstat;//lnk20250704
	bool has_logged_disconnect;//lnk20250704

	MMS_OPER_TYPE_CACHE oper_type_cache;
};


struct chnl_usr_t{	
	byte_t 			chnl_id;	
	char			ip_str[20];
	channel_t		*chnl;       /**< 对应的channel 指针                     */
	MVL_NET_INFO	*net_info;	
	MVL_REQ_PEND	*m_reqCtrl; //MVL_REQ_PEND

	int m_state;
	double m_StartConnectingTime; //这次开始 connect 的时间
	double m_StartDisconnectingTime; //这次开始 disconnect 的时间
	double m_ClosedMsTime; //上次通道关闭时间	
	double m_LastPosRespTime; //上次肯定响应的时间
	int m_NegRespTimes; // 累计否定响应次数
};



typedef struct pt61850app_t pt61850app_t;
struct pt61850app_t
{	
//	rdb_t				*rdb;
	node_t				*node;
//	driver_t 			*driver;	
	//byte_t				IsMaster;				//当前的主备状态

	////////////////////////////
	uint32_t			mmsOpTimeout;  //mms操作，读写变量等的交互超时时间
	//uint32_t			relayTimeout;  //遥控等待遥信返回的超时时间
	uint32_t			giTime;			//总查询时间	
	int					rptSuffix[2][2];		//报告控制块后缀
	//char				ftp_srv_ip[16];
	//char				ftpsrv_path[64];
	//char				ftp_user[32];
	//char				ftp_password[32];
	char				accPath[65];			//装置录波文件路径	
	//char				RcdMadeAddStr[65];		//录波动作遥信地址
	//uint8_t				change_file_name;		//保存时，是否修改文件名
 	uint32_t			chnl_counts;
	chnl_usr_t			**chnl_usr;
	apr_pool_t			*tmp_pool;				// 临时pool
	//链路层完全初始化次数，作为可以进行召唤录波文件的条件。即确保所有装置初始化最少一次后才允许开始召唤文件
	uint8_t				initNum;				
	//召唤文件类型，为0则只召唤对应目录下的录波文件，为1则召唤对应目录下的所有文件，其余留待扩展
	//uint8_t				call_file_type;			
	//数字量入库前是否检查值有效
	uint8_t				check_dgtVal;//0不判，非0判
}; 

//为无锡西径变调档添加
extern uint8_t             set_mx_q;
         
#ifdef _OS_WIN32_
#pragma pack(push,1)   
#endif


#ifdef _OS_WIN32_
#pragma pack(pop)    
#endif



#ifdef __cplusplus
extern "C" {
#endif
 

char* str_trim_both(char* temp,const char* pattern) ;
 
element_usr_t* GET_DOTEXT_ADDR(element_t *elem);

ied_usr_t* GET_IEDEXT_ADDR(ied_t *ied);

ST_RET mms_jread (loginfo_t *loginfo,MVL_NET_INFO *clientNetInfo, ST_CHAR *dom_name,ST_CHAR *logName, apr_time_t start_time,apr_time_t end_time,ST_INT iTimeout, ST_CHAR* ip) ;

LD_info_t* find_LD_from_cpuId(ied_t* ied,byte_t cpuId);
LD_info_t* find_LD_from_IEDLDName(ied_t* ied, char *IEDLDName);
LD_info_t* find_LD_from_cpuCount_and_LEDRs(ied_t* ied, byte_t cpuCount);

LD_info_t* find_LD_from_IEDLDName_in_report(ied_t* ied, char *IEDLDName);

LD_info_t* find_LD_from_element(element_t* elem);

rptinfo_t* find_rptinfo_from_net_rcb_info(MVL_NET_INFO *net_info,RCB_INFO *rcb_info);

rptinfo_t* find_rptinfo_from_net_rpt_info_name(MVL_NET_INFO *net_info, RCB_INFO *rcb_info);

void get_rpt_inst_name(rptinfo_t	*rptinfo, char	* rpt_inst_name );
/** 
* @brief 初始化rdb库相关内容
* @return 如果创建成功，返回 APR_SUCCESS
*/
apr_status_t init_rdb();

/** 
* @brief 启动规约处理相关线程
* @return 如果成功，返回 APR_SUCCESS
*/
apr_status_t run_protocol();

void Set_val_from_61850rpt(element_t* elem,double v);
int Set_q_from_61850rpt(char* q); 

apr_status_t init_rem_dib_table();

void CheckNextNotConnectedChannel();
//WW 2023-08-22 
int HandleReceiveMessage(int socketClient, char buffer[256]); 
int ExecuteWebCommand(LD_info_t *LD_info, int iType);
int SendMessageToWeb(int socketClient, int iErrorCode); //向Web Socket客户端发送消息
//WW 2023-08-22 end
void CheckAllConnectedChannel()	;

void check_3s_config();
void create_recall_xml();
void check_disk_quota();

apr_status_t prepare_call_cn_wavelist(LD_info_t	*LD_info, int FltNum );

apr_status_t call_cn_wavelist(LD_info_t  *LD_info); 

void strip_file_name_tail_to_ms(char *fileName);

//////////for pq //////////////////////////////////////////

ied_t* find_ied_from_dev_idx(int dev_idx);
ied_t* find_ied_from_dev_code(char dev_idx[]);

LD_info_t* find_LD_info_from_line_id(ied_t* ied, int line_id);
LD_info_t* find_LD_info_only_from_line_id(int line_id);
LD_info_t* find_LD_info_from_mp_id(ied_t* ied, char* mp_id);
LD_info_t* find_LD_info_only_from_mp_id(char* mp_id);

////////////////////////////////lnk20250115
int parse_ledger_update_xml(trigger_update_xml_t* trigger_update_xml);
extern const int MAX_CPUNO;
int stringToInt(const char* str, int* result);
bool isCharPtrEmpty(const char* str);
int parse_ledger_update_xml(trigger_update_xml_t* trigger_update_xml);
int update_one_terminal_ledger(terminal* update, int i,ied_t* ied,int terminal_index,int ied_take);
void print_trigger_update_xml(const trigger_update_xml_t* trigger_update);
char* parse_model_cfg_web_one(ied_t* ied,char* out_model);
void Set_xml_nodeinfo_one(char* dev_type);
void create_ledger_log(trigger_update_xml_t* ledger_update_xml);
ied_t* find_ied_unused();
int parse_rpt_log_ini_one(ied_t* ied);
apr_status_t init_rem_dib_table_one(ied_t *ied);
void clearIed(ied_t *ied);
void clearIedUsr(ied_usr_t *ied_usr);


////////////////////////////////
int parse_3s_xml(trigger_3s_xml_t* trigger_3s_xml);
int create_3s_xml(trigger_3s_xml_t* trigger_3s_xml);
int get_real_report_count(LD_info_t	*LD_info);

int delete_recall_xml(char* id);
int parse_recall_xml(recall_xml_t* recall_xml,char *id);
void process_recall_config(recall_xml_t* recall_xml);

void recall_xml_free(recall_xml_t *rx);//lnk20250801
void recall_xml_init(recall_xml_t *rx);

int init_rptctrl_by_count(LD_info_t* LD_info,int rptcount);
int fill_rptctrl_by_cfg(LD_info_t* LD_info,int rptno,char *buf);
int init_logctrl_by_count(LD_info_t* LD_info,int logcount);
int fill_logctrl_by_cfg(LD_info_t* LD_info,int logno,char *buf,char* devtype);

//////////////////////////////////////////////////////////
void processQVVR_start(LD_info_t* LD_info);
void processQVVR_time(LD_info_t* LD_info, long long Time);
void processQVVR_data(LD_info_t* LD_info,char* FULL_FCDA_Name,double v);
void processQVVR_end(LD_info_t* LD_info);

void processRDRE_start(LD_info_t* LD_info); 
void processRDRE_data(LD_info_t* LD_info,char* FULL_FCDA_Name,double v);
void processRDRE_end(LD_info_t* LD_info);

int extract_timestamp_from_cfg_file(char *comtrade_fn,long long *start_tm,long long *trig_tm);

int parse_file_names_by_fltnum(int fltnum, char* domname, char** filenames, int filenum, int* cfg_idx, int* dat_idx, char* file_base_name, char* file_yyyymm);
QVVR_t*  find_qvvr_by_trig_tm(LD_info_t* LD_info,long long trig_tm);

void HandleFileDirReqForChannel(chnl_usr_t *chnl_usr);
void InitLedrsOperTypeForChannel(chnl_usr_t *chnl_usr);

//lnk20250508添加重启装置函数
//根据抓包显示oper的data结构有6个item
typedef struct
{
    ST_BOOLEAN ctlVal;

    struct
    {
        ST_INT16 orCat;

        struct
        {
            ST_INT16 len;
            ST_UINT8 data[64];
        } orIdent;

    } origin;

    ST_UINT32 ctlNum;

    MMS_UTC_TIME T;

    ST_BOOLEAN Test;

    ST_UCHAR Check[2];

} Control_Oper_t;

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

#ifdef __cplusplus
}
#endif

#endif /* _RDB_CLIENT_H_XSDFSDFSEFS15156SFS */
