#ifndef LIBACP_LIBACPCMP_H_
#define LIBACP_LIBACPCMP_H_

#include <stdint.h>
#include "libacpDef.h"

#ifdef _WIN32
#define LIBACPCMP_EXPORTS extern "C" __declspec(dllexport)
#else
#define LIBACPCMP_EXPORTS extern "C" __attribute__((visibility("default")))
#endif

#define MAKEVERSION(major, minor, patch)                                                     \
  ((uint32_t)(((uint8_t)(patch)) & 0xff)) | (((uint32_t)(((uint8_t)(minor)) & 0xff)) << 8) | \
      (((uint32_t)(((uint8_t)(major)) & 0xff)) << 16)

typedef void* ACPCONN_CMPHANDLE;  // 客户端连接的句柄
typedef void* ACPCMP_HANDLE;      // ACP主键的句柄

#pragma pack(push, 1)

typedef struct tagCmpDrvInfo {
  uint32_t dwCmpId;    // 组件Id,为Codesys内部的CMPID,非Codesys组件填0
  uint32_t dwVersion;  // 组件的版本
  char szCmpName[32];  // 组件名称,可视化字符串(必填),例如:  modbus,aoiservice,adiservice
} CmpDrvInfo;

typedef struct tagCMP_INIT_STRUCT {
  pfnOnControlCallback pfOnControl;
  pfnOnClientConnect pfOnConnect;
  pfnOnClientDisConnect pfOnDisconnect;
} CMP_INIT_STRUCT;

#pragma pack(pop)

/**
 * @brief 初始化组件需要依赖的资源
 * @return :
 *      成功返回0
 *      失败返回错误码
 */
LIBACPCMP_EXPORTS int libacpcmp_init();

/**
 * @brief 初始化组件,向ACP服务发起注册
 * @param in: szCmpName 组件名称,不可为空,例如: modbus,mqtt,
 * @param in: nCmpId    组件Id,为Codesys内部的CMPID
 * @param in: nVersion  当前服务的版本号
 * @param in: onControl 接收服务器控制的回调函数,接收服务发送的控制消息
 * @param out: result   成功返回0,失败返回错误码
 * @return :
 *      成功返回 ACPCMP_HANDLE
 *      失败返回 NULL,见result的错误码
 */
LIBACPCMP_EXPORTS ACPCMP_HANDLE libacpcmp_register(CmpDrvInfo* pDrvInfo, pfnOnControlCallback onControl,
                                                   void* lpContext, int* result);

/**
 * @brief 添加消息的路由,向ACP服务订阅port的关注的事件
 * @param in: handler libacpcmp_register返回的句柄
 * @param in: port 订阅消息的消息的路由port
 * @param in: cmpCallback  订阅port消息的回调函数
 * @param lpContex: 用户参数的指针
 * @return :
 *       成功返回0
 *       失败返回错误码
 */
LIBACPCMP_EXPORTS int libacpcmp_addrouter(ACPCMP_HANDLE handler, uint32_t port, pfnServerMsgRouterCallBack cmpCallback,
                                          void* lpContext);
/**
 * @brief    启动ACP的组件的事件循环,开始接收消息
 * @param in: handler libacpcmp_register返回的句柄
 * @return :
 *       成功返回0
 *       失败返回错误码
 */
LIBACPCMP_EXPORTS int libacpcmp_loop_start(ACPCMP_HANDLE handler);

/**
 * @brief     停止组件的事件循环,停止消息接收
 * @param in: handler libacpcmp_register返回的句柄
 * @return :
 *       成功返回0
 *       失败返回错误码
 */
LIBACPCMP_EXPORTS int libacpcmp_loop_stop(ACPCMP_HANDLE handler);

/**
 * @brief  发送消息到指定的客户端
 * @param in: req 回调函数中的请求实例的句柄
 * @param in: port 路由消息的port号
 * @param in: szBuff 发送缓冲区的起始地址
 * @param in: nBufLen 发送缓冲区的大小
 * @param in: nTimeOutMs 发送超时的时间
 * @param out: result 函数执行结果,成功返回0,失败返回错误码
 * @return :
 *       =0:表示发送成功
 *       <0:发送失败,见result返回值
 */
LIBACPCMP_EXPORTS int libacpcmp_send(msg_request req, uint32_t port, const char* szBuff, uint32_t nBufLen,
                                     uint32_t nTimeOutMs, int* result);

/*
 * @brief  发布消息到指定的消息通道
 * @param in: handler libacpcmp_register返回的句柄
 * @param in: szTopic 发布到指定的topic
 * @param in: data 发送缓冲区的起始地址
 * @param in: dataLen 发送缓冲区的大小
 * @return :
 *       =0:发送成功
 *       <0:发布失败
 */
LIBACPCMP_EXPORTS int libacpcmp_publish(ACPCMP_HANDLE handler, const char* szTopic, const char* data, uint32_t dataLen);

/*
 * @brief  订阅指定消息的通道
 * @param in: handler libacpcmp_register返回的句柄
 * @param in: szTopic 要订阅的topic
 * @param in: callback 消息通道的回调函数
 * @param in: lpContext 回调函数通知的用户指针
 * @return :
 *       =0:发送成功
 *       <0:发布失败
 */
LIBACPCMP_EXPORTS int libacpcmp_subscribe(ACPCMP_HANDLE handler, const char* szTopic, pfnSubscribeCallback callback,
                                          void* lpContext);

/*
 * @brief  取消订阅指定消息的通道
 * @param in: handler libacpcmp_register返回的句柄
 * @param in: szTopic 取消订阅的topic
 * @return :
 *       =0:取消订阅成功
 *       <0:取消订阅失败
 */
LIBACPCMP_EXPORTS int libacpcmp_unsubscribe(ACPCMP_HANDLE handler, const char* szTopic);

/**
 * @brief 取消组件向ACP服务的注册并释放libacpcmp_register初始化的组件句柄
 * @param in: handler libacpcmp_register返回的句柄
 * @return :
 *       成功返回:0
 *       失败返回错误码
 */
LIBACPCMP_EXPORTS int libacpcmp_destory(ACPCMP_HANDLE handler);

/*
 * @brei 获取最新的错误码
 * return 返回最近一次的错误码
 */
LIBACPCMP_EXPORTS int libacpcmp_get_errno();

/*
 * @brei 根据错误码获取对应的描述
 * return :返回一个错误描述信息
 */
LIBACPCMP_EXPORTS const char* libacpcmp_strerror(int acperrno);

/**
 * @brief 释放初始化的资源
 * @return :
 *      成功返回0
 *      失败返回错误码
 */
LIBACPCMP_EXPORTS int libacpcmp_finit();

#endif  // LIBACP_LIBACPCMP_H_
