#ifndef __PF_COMMON_H_
#define __PF_COMMON_H_ 1

/***************HEADER FILES****************/
#include <string.h>
#include <syslog.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdbool.h>
#include <semaphore.h>
#include "dy_utils/dy_common.h"
#include <sys/time.h>
#include <sys/timerfd.h>
#include <linux/serial.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/error.h>
#include <linux/can/raw.h>
#include <fcntl.h>
#include <time.h>
#include <stdatomic.h>
#include "cJSON.h"
#if defined(EN_OPCUA) || defined(EN_LC)
#include "open62541.h"
#endif

#define DEV_PORT_CFG_FILE "/app/config/port_config.json"

extern const char *show_log[];
extern const char *log_level_string[];
extern int g_proto_log_level;
extern int g_ems_log_level;
extern bool northcfg_change;
#ifndef EN_LC
extern void ems_log_Event(char *message,int Severity);
#else
#define ems_log_Event(a, b)
#endif
extern cJSON * json_parse_string_with_comments(const char *string);
extern int lnxall_syslog_uid(int level, int uid, const char *__format, ...);
#define DEFAULT_LOG_UID 0
#define EMS_LOG_UID 1
#define BUSINESS_LOG_UID 2
#define ABNORMAL_LOG_UID 3
#define MODBUS_LOG_UID 4
#define IEC104_LOG_UID 5

#define MAX_RACK_SUM_SUPPORT 10

#define proto_syslog_hex(level, bin_buff, bin_len, fmt, ...)                          \
    do                                                                                \
    {                                                                                 \
        if ((level) <= g_proto_log_level)                                             \
        {                                                                             \
            char __buff[4096] = {0};                                                  \
            uint8_t *__p = (uint8_t *)bin_buff;                                       \
            int32_t __str_len = snprintf(__buff, sizeof(__buff), fmt, ##__VA_ARGS__); \
            __buff[__str_len++] = ' ';                                               \
            int32_t __len = bin_len;                                                  \
            if (__len > (sizeof(__buff) - __str_len - 1) / 3)                         \
            {                                                                         \
                __len = (sizeof(__buff) - __str_len - 1) / 3;                         \
            }                                                                         \
            int32_t __line = __len >> 4;                                              \
            int32_t __remain = __len & 0x0f;                                          \
            for (int32_t i = 0; i < __line; i++)                                      \
            {                                                                         \
                for (int32_t k = 0; k < 16 - 1; k++)                                  \
                {                                                                     \
                    __str_len += snprintf(&__buff[__str_len], 4, "%02x ", *__p++);    \
                }                                                                     \
                __str_len += snprintf(&__buff[__str_len], 4, "%02x ", *__p++);       \
            }                                                                         \
            if (__remain > 0)                                                         \
            {                                                                         \
                for (int32_t i = 0; i < __remain - 1; i++)                            \
                {                                                                     \
                    __str_len += snprintf(&__buff[__str_len], 4, "%02x ", *__p++);    \
                }                                                                     \
                __str_len += snprintf(&__buff[__str_len], 4, "%02x ", *__p++);       \
            }                                                                         \
            lnxall_syslog_uid(LOG_USER | level, EMS_LOG_UID, "*%s:%d %s", __FILE__, __LINE__, __buff);        \
        }                                                                             \
    } while (0)
#define ems_syslog_hex(level, bin_buff, bin_len, fmt, ...)                          \
    do                                                                                \
    {                                                                                 \
        if ((level) <= g_ems_log_level)                                             \
        {                                                                             \
            char __buff[4096] = {0};                                                  \
            uint8_t *__p = (uint8_t *)bin_buff;                                       \
            int32_t __str_len = snprintf(__buff, sizeof(__buff), fmt, ##__VA_ARGS__); \
            __buff[__str_len++] = ' ';                                               \
            int32_t __len = bin_len;                                                  \
            if (__len > (sizeof(__buff) - __str_len - 1) / 3)                         \
            {                                                                         \
                __len = (sizeof(__buff) - __str_len - 1) / 3;                         \
            }                                                                         \
            int32_t __line = __len >> 4;                                              \
            int32_t __remain = __len & 0x0f;                                          \
            for (int32_t i = 0; i < __line; i++)                                      \
            {                                                                         \
                for (int32_t k = 0; k < 16 - 1; k++)                                  \
                {                                                                     \
                    __str_len += snprintf(&__buff[__str_len], 4, "%02x ", *__p++);    \
                }                                                                     \
                __str_len += snprintf(&__buff[__str_len], 4, "%02x ", *__p++);       \
            }                                                                         \
            if (__remain > 0)                                                         \
            {                                                                         \
                for (int32_t i = 0; i < __remain - 1; i++)                            \
                {                                                                     \
                    __str_len += snprintf(&__buff[__str_len], 4, "%02x ", *__p++);    \
                }                                                                     \
                __str_len += snprintf(&__buff[__str_len], 4, "%02x ", *__p++);       \
            }                                                                         \
            lnxall_syslog_uid(LOG_USER | level, EMS_LOG_UID, "*%s:%d %s", __FILE__, __LINE__, __buff);        \
        }                                                                             \
    } while (0)

#if defined(__arm__)
#define PTHREAD_NULL 0
#define proto_syslog(level, fmt, ...)                                         \
    do                                                                        \
    {                                                                         \
        if ((level) <= g_proto_log_level)                                     \
        {                                                                     \
            lnxall_syslog_uid(LOG_USER | level, EMS_LOG_UID, "%s[proto_syslog]%s:%d " fmt, log_level_string[level], __FILE__, __LINE__, ##__VA_ARGS__); \
        }                                                                     \
    } while (0)                      
#define ems_syslog(level, fmt, ...)                                           \
    do                                                                        \
    {                                                                         \
        if ((level) <= g_ems_log_level)                                     \
        {                                                                    \
            lnxall_syslog_uid(LOG_USER | level, EMS_LOG_UID, "%s[ems_syslog]%s:%d " fmt, log_level_string[level], __FILE__, __LINE__, ##__VA_ARGS__); \
	}\
    } while (0)
#elif defined(__aarch64__)
#define PTHREAD_NULL 0
#define proto_syslog(level, fmt, ...)                                         \
    do                                                                        \
    {                                                                         \
        if ((level) <= g_proto_log_level)                                     \
        {                                                                     \
            lnxall_syslog_uid(LOG_USER | level, EMS_LOG_UID, "%s[proto_syslog]%s:%d " fmt, log_level_string[level], __FILE__, __LINE__, ##__VA_ARGS__); \
        }                                                                     \
    } while (0)

                       
#define ems_syslog(level, fmt, ...)                                           \
    do                                                                        \
    {                                                                         \
        if ((level) <= g_ems_log_level)                                     \
        {                                                                     \
            lnxall_syslog_uid(LOG_USER | level, EMS_LOG_UID, "%s[ems_syslog]%s:%d " fmt, log_level_string[level], __FILE__, __LINE__, ##__VA_ARGS__); \
        }                                                                     \
    } while (0)

#elif defined __x86_64__
#define PTHREAD_NULL 0
#define proto_syslog(level, fmt, ...)                                         \
    do                                                                        \
    {                                                                         \
        if ((level) <= g_proto_log_level)                                     \
        {                                                                     \
            lnxall_syslog_uid(LOG_USER | level, EMS_LOG_UID, "%s[proto_syslog]%s:%d " fmt, log_level_string[level], __FILE__, __LINE__, ##__VA_ARGS__); \
        }                                                                     \
    } while (0)

#define ems_syslog(level, fmt, ...)                                           \
    do                                                                        \
    {                                                                         \
        if ((level) <= g_ems_log_level)                                     \
        {                                                                     \
            lnxall_syslog_uid(LOG_USER | level, EMS_LOG_UID, "%s[ems_syslog]%s:%d " fmt, log_level_string[level], __FILE__, __LINE__, ##__VA_ARGS__); \
        }                                                                     \
    } while (0)

#endif

// #ifdef proto_syslog
// #undef proto_syslog
// #define proto_syslog proto_syslog
// #
// #else
// #define proto_syslog proto_syslog
// #endif

#define proto_set_log_level(le) \
    do                          \
    {                           \
        g_proto_log_level = le; \
    } while (0)

#define ems_set_log_level(le) \
    do                          \
    {                           \
        g_ems_log_level = le; \
    } while (0)

typedef enum
{
    TYPE_ERROR  =   -1,
    TYPE_BOOL,
    TYPE_INT,
    TYPE_UINT,
    TYPE_FLOAT,
    TYPE_BITS,
    TYPE_SHORT,
    TYPE_USHORT,
    TYPE_MAX
}DATA_TYPE; //类型

typedef enum
{
    CRC16_ERROR  =   -1,
	CRC16_N,
    CRC16_X,
    CRC16_C,
    CRC16_M,
    CRC16_IBM,
    CRC16_USB,
    CRC16_DNP,
    CRC16_DEC,
    CRC16_MAX
}CRC16_TYPE;

typedef enum
{
    TYPE_TAG_ERROR  =   -1,
    TYPE_TAG_INT,
    TYPE_TAG_FLOAT,
    TYPE_TAG_MAX,
}DATA_TAG_TYPE; 

typedef enum
{
    PROPERTY_REALDATA=0, 
    PROPERTY_SYSTEM,
    PROPERTY_ALARM,
    PROPERTY_MAX
}PROPERTY_TYPE;

typedef enum
{
    HISTORY_TYPE_OFF = 0,
    HISTORY_TYPE_CHANGE,
    HISTORY_TYPE_PERIOD,
    HISTORY_TYPE_BOTH,
    HISTORY_TYPE_MAX
}DATA_HISTORY_TYPE; 

typedef enum
{
    ORDER_ERROR  =   -1,
    ORDER_A,
    ORDER_AB,
    ORDER_BA,
    ORDER_ABCD,
    ORDER_DCBA,
    ORDER_BADC,
    ORDER_CDAB,
    ORDER_ABCDEFGH,
    ORDER_GHEFCDAB,
    ORDER_BADCFEHG,
    ORDER_HGFEDCBA,
    ORDER_MAX
}DATA_ORDER;  //字序 请务必按照从少到多排序

#define MIN_TIMESTAMP 1577808000//最小时间戳 2000-01-01-00:00:00


typedef struct uart_attr
{
    char dev_f[30];
    int baud;
    uint8_t data_bit;
    uint8_t stop_bit;
    /* Parity: 'N', 'O', 'E' */
    char parity;
    struct termios old_tios;
} uart_attr;
// 字符缓冲器
typedef struct
{
    int size;         // 空间大小
    char *buffer_str; // 字符串存储
} StringBuffer;

// all io-queue operations return an IoQueueResult
typedef int IoQueueResult;

#define IO_QUEUE_RESULT_TRUE (2)
#define IO_QUEUE_RESULT_SUCCESS (1)
#define IO_QUEUE_RESULT_FALSE (0)
#define IO_QUEUE_RESULT_OUT_OF_MEMORY (-1)

// internal structure used for implementing the queue
typedef struct IoQueueNode IoQueueNode;
typedef struct IoQueueNode
{
    atomic_uintptr_t next;
    // data for the node is stored "after" it
} IoQueueNode;

// queue object
typedef struct IoQueue
{
    atomic_uintptr_t head;
    atomic_uintptr_t tail;
    size_t item_size;
    _Atomic(size_t) size; // 添加一个原子计数器
} IoQueue;
IoQueueResult io_queue_init(IoQueue *io_queue, size_t item_size);
IoQueueResult io_queue_has_front(IoQueue *io_queue);
IoQueueResult io_queue_front(IoQueue *io_queue, void *data);
IoQueueResult io_queue_pop(IoQueue *io_queue);
IoQueueResult io_queue_push(IoQueue *io_queue, void *data);
IoQueueResult io_queue_clear(IoQueue *io_queue);
uint16_t crc16_M(uint8_t *buffer, uint16_t buffer_length);
uint8_t toAsciiHigh(uint8_t byte);
uint8_t toAsciiLow(uint8_t byte);
uint8_t fromAscii(uint8_t high, uint8_t low);
uint8_t stringToHex(const char *str);
int get_data_order_size(DATA_ORDER order);
int get_localip(const char * eth_name, char *local_ip_addr);
const char * get_string_property(int type);
PROPERTY_TYPE get_property_by_string(char *tagTypeString);
DATA_TYPE get_type_by_string(char *typeString);
CRC16_TYPE get_crc16_by_string(char *crc16typeString);
const char* get_type_string(DATA_TYPE type);
DATA_ORDER get_order_by_string(char *typeString);
const char* get_order_string(DATA_ORDER order);
DATA_HISTORY_TYPE get_history_type_by_string(char *tagTypeString);
DATA_TAG_TYPE get_tag_type_by_string(char *tagTypeString);
uint32_t analysis_addr(char *addr);
uint32_t *analysis_addr_with_p(char *addr);
bool check_float_is_1(double data_f);
void cond_signal(pthread_cond_t *t_cond,pthread_mutex_t *t_mutex);
int cond_wait(pthread_cond_t *t_cond,pthread_mutex_t *t_mutex,int timeout_s,int timeout_ms);
int set_net_par(void);
int dev_is_open(char *dev);
const char *get_protocal_string(int type);
DATA_TAG_TYPE turn_data_type(DATA_TYPE type);

void parse_host_port(const char *URL, char **host, uint16_t *port);
int getCommandReturn(char *command,char *distchar,int size);
void GEN_ARRHEX2ASIC(unsigned char *hexdata, unsigned char *asicdata, unsigned short hexlength,char spilite);
int GEN_ARRASIC2HEX(unsigned char *data,unsigned char *dir,unsigned char len);

int connect_tcp(const char *ip, int port, uint32_t cnt_timeout);
int open_uart(uart_attr *attr);
int get_file_md5(const char *filename, char *result);
void copy_file(const char *src_filename, const char *dst_filename);
int ftp_upload_file(const char *ftp_url, const char *userpwd, const char *local_file);
int is_mounted(const char *path);

int is_virtual_device_and_to_dup(const char *info, char *map_ip);


uint64_t sysuptime(void);
void frame_wgap_delay(uint64_t lastread, int32_t gapms);
void str_to_lower_case(char *str);

#if defined(EN_OPCUA) || defined(EN_LC)

#define SERVER_CERT_CERT "/app/cert/server_cert.der"
#define SERVER_CERT_KEY  "/app/cert/server_key.pem"

#define CLIENT_CERT_CERT "/app/cert/client_cert.der"
#define CLIENT_CERT_KEY  "/app/cert/client_key.pem"

UA_ByteString loadFile(const char *const path);
#endif

// Modify DHCP/Static IP address for WAN
// if `netmask is NULL, default to 255.255.255.0
// if `ip or `gwip is NULL, enable DHCP instead of static IP
int port_config_update_wan(const char * ip, const char * gwip, const char * netmask);

/*
 * if `pfile ends with suffix `.lua, then try to execute lua script,
 * and replace `pfile with the final template configuration file.
 */
void check_load_template_config(char * pfile,
    unsigned int maxlen, const char * userdef);

StringBuffer *StringBuffer_Create(int size);
void StringBuffer_Free(StringBuffer *buffer);
int StringBuffer_Append(StringBuffer *buffer, const char *format, ...);
bool is_valid_ipv4_str(const char *ip_str);
const char *get_cJSON_valid_ip_str(cJSON *ip);

int http_post_upload_file(const char* http_url, const char* file_name, const char* file,
                          const char* username, const char* userpwd);
size_t local_strlcpy(char *dest, const char *src, size_t dest_size);
int write_file_data_safe(const char* file_path, const char* data, int data_len);
typedef int (*download_callback_t)(void *clientp, int dltotal, int dlnow, double ultotal, double ulnow);
int http_post_download_file(const char* url, const char* save_path, const char* file_name, download_callback_t callback);
#endif /* __COMMON_h */
