#ifndef LIBACP_LIBACP_H_
#define LIBACP_LIBACP_H_

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

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

/**
 * @brief  初始化ACP的库,有些特殊功能需要先初始化才可以
 * return: 成功返回0,失败返回对应错误码
 */
LIBACP_EXPORTS int libacp_init();

/**
 * @brief 获取ACP当前的版本信息
 * @param in/out: major acp的主版本号
 * @param in/out: minor acp的副版本号
 * @param in/out: patch acp的补丁版本号
 * return: 成功返回0,失败返回对应错误码
 */
LIBACP_EXPORTS int libacp_version(OUT int* major, OUT int* minor, OUT int* patch);

/**
 * @brief 注册ACP扫描的回调事件
 * @param in/out: pfnAcpDeviceDiscovery acp设备发现的回调函数
 * @param in: lpContext  传入用户参数
 * return: 成功返回0,失败返回对应错误码
 */
LIBACP_EXPORTS int libacp_registerAcpScanEvent(IN pfnAcpDeviceScanCallback pfnCallBack, IN void* lpContext);

/**
 * @brief 开启ACP设备扫描功能,将扫描到的设备回调通知给注册的回调函数
 * @param return: 成功返回0,失败返回对应错误码
 */
LIBACP_EXPORTS int libacp_startAcpScan();

/**
 * @brief 停止ACP设备扫描
 * @param return: 成功返回0,失败返回对应错误码
 * return: 成功返回0,失败返回对应错误码
 */
LIBACP_EXPORTS int libacp_stopAcpScan();

/*
 * @breif 输入DeviceId字符串创建一个AcpDeviceId
 * param szHostDeviceId(in): 设备ID, eg: 192.168.110.11.1.1  前面为IP地址,后面为版本号1.1
 * param pDeviceId(in/out): 调用者开辟内存,传出设备Id
 * return: 成功返回0,失败返回对应错误码
 */
LIBACP_EXPORTS int libacp_makeAcpDeviceId(IN const char* szHostDeviceId, OUT AcpDeviceId* pDeviceId);

/*
 * @breif 输入DeviceId字符串和port号创建一个AcpDeviceAddr
 * param szHostDeviceId(in): DeviceId的字符串 eg: 192.168.110.12.1.1 前面为IP地址,后面为版本号1.1
 * param port(in): 标识本地的一个客户端
 * param pDeviceAddr(in/out): 调用者开辟内存,传出设备的地址
 * return: 成功返回0,失败返回对应错误码
 */
LIBACP_EXPORTS int libacp_makeAcpDeviceAddr(IN const char* szHostDeviceId, IN uint16_t port,
                                            OUT AcpDeviceAddr* pDeviceAddr);

/*
 * @breif 获取本地的Acp的deviceId
 * param pDeviceAddr(in/out): 调用者开辟内存,传出Acp的DeviceId
 * return: 成功返回0,失败返回对应错误码
 */
LIBACP_EXPORTS int libacp_getLocalAcpDeviceId(OUT AcpDeviceId* pDeviceId);

/*
 * @breif: 获取一个远程主机的DeviceId
 * param:szHostIp(in): 远端主机的IP地址
 * param:nTimeOutms(in): 超时时间
 * param:pDeviceId(in/out): 调用者开辟内存,对端的DeviceId
 * return: 成功返回0,失败返回对应错误码
 */
LIBACP_EXPORTS int libacp_getRemoteAcpDeviceId(IN const char* szHostIp, IN int nTimeOutms, OUT AcpDeviceId* pDeviceId);

/*
 * @brei 创建一个ACP的通讯句柄
 * param pAddr(in): acp服务端的DeviceId
 * param type(in):  通讯类型,默认采用TCP的通讯方式,
 *       0: TCP通讯
 *       1：UDP通讯
 *       2：linux共享内存
 *       3：windows共享内存
 *       4: linux domain socket
 * return 成功返回通讯句柄,失败返回NULL
 */
LIBACP_EXPORTS ACP_HANDER libacp_createInstance(IN AcpDeviceId* pDeviceId, IN int type);

/*
 * @brei 创建一个ACP的通讯句柄
 * param pAddr(in): acp服务端的DeviceId
 * param type(in):  通讯类型,默认采用TCP的通讯方式,
 *       0: TCP通讯
 *       1：UDP通讯
 *       2：linux共享内存
 *       3：windows共享内存
 *       4: unix domain socket
 * param pfnAcpConnCallback(in): 连接状态的回调函数
 * param lpContext(in): 连接状态里面的回调函数的用户指针
 * return 成功返回通讯句柄,失败返回NULL
 */
LIBACP_EXPORTS ACP_HANDER libacp_createInstanceEx(IN AcpDeviceId* pDeviceId, IN int type, IN int timeoutms,
                                                  IN pfnAcpConnCallback connCallback, IN void* lpContext);

/*
 * @brei  设置自动重连接的相关参数，使用TCP连接的时候有效
 *  设置自动重连后,调用libacp_loop_start()该函数后,会自动检测断线重连
 * param pAddr(in): libacp_createInstance通讯实例的handler
 * param nIntervalSec(in): 自动重新连接的时间间隔，单位为秒
 * return 成功返回0,失败返回错误码
 */
LIBACP_EXPORTS int libacp_reconnect_delay_set(IN ACP_HANDER handler, IN int nIntervalSec);

/*
 * @brei 当连接断开后,用户可以主动调用该函数进行主动重连
 * param pAddr(in): libacp_createInstance通讯实例的handler
 * param nTimeoutMs(in): 重连的超时时间,单位为ms
 * return 重连成功返回true,失败返回false
 */
LIBACP_EXPORTS bool libacp_reconnect(IN ACP_HANDER handler, int nTimeoutMs);

/*
 * @brei 同步的发送数据到服务端
 * param handler(in): libacp_createInstance通讯实例的handler
 * param port(in): 路由消息对应的端口号
 * param reqData(in): 发送缓冲区的首地址
 * param reqLen(in)： 发送缓冲区大小
 * parma IdGroup(in): IdGroup
 * param IdOffset(in): IdOffset
 * return
 *      >=0 返回发送的数据大小
 *      -1  发送失败,可以通过libacp_get_errno()获取错误码
 */
LIBACP_EXPORTS int libacp_sync_send(IN ACP_HANDER handler, IN uint16_t port, IN uint32_t IdGroup, IN uint32_t IdOffset,
                                    IN const char* reqData, IN int reqLen, IN int timeoutMs);

/*
 * @brei 同步等待接收数据,如果接收的缓冲区小于事件的缓冲区
 *       需要进行循环接收数据
 * param handler(in): libacp_createInstance通讯实例的handler
 * param port(out): 返回对应的路由消息的端口号
 * param recvBuf(in/out)： 接收缓冲区的首地址
 * param recvLen(in)： 接收缓冲区的大小
 * return 返回本次接收数据的缓冲区大小
 *    -1:表示出错了,协议错误等,可以通过libacp_get_errno()获取错误码
 *     0:对端关闭了连接
 *    0>:成功接收的缓存区大小
 */
LIBACP_EXPORTS int libacp_sync_recv(IN ACP_HANDER handler, OUT uint16_t* port, OUT char* recvBuf, IN int recvLen,
                                    IN int timeoutMs);

/*
 * @brei: 给客户端添加一个注册路由事件的功能
 * param handler(in): 订阅通讯的实例句柄
 * param port(in):  注册的端口号
 * param callback(in): 消息通知的回调函数
 * param lpContex(in): 用户指针参数
 * return
 *      成功返回0
 *      失败返回错误码
 */
LIBACP_EXPORTS int libacp__registerRouterEvent(IN ACP_HANDER handler, IN uint16_t port,
                                               IN pfnClientMsgRouterCallBack callback, IN void* lpContex);

/*
 * @brei: 取消注册的事件
 * param handler(in): 订阅通讯的实例句柄
 * param port(in):  取消注册的端口号
 * return
 *     成功返回0
 *     失败返回错误码
 */
LIBACP_EXPORTS int libacp__unregisterRouterEvent(IN ACP_HANDER handler, IN uint16_t port);

/*
 * @brei: 启动一个事件循环,使用异步接收数据的时候,
 * param handler:libacp_createInstance返回的创建的句柄
 * return
 *        成功返回0
 *        失败返回对应错误码
 */
LIBACP_EXPORTS int libacp_loop_start(IN ACP_HANDER handler);

/*
 * @brei: 关闭事件循环,停止异步接收数据的时候,
 * param handler:libacp_createInstance返回的创建的句柄
 * return
 *      成功返回0,
 *      失败返回对应错误码
 */
LIBACP_EXPORTS int libacp_loop_stop(IN ACP_HANDER handler);

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

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

/*
 * @brief  取消订阅指定消息的通道
 * @param in: handler libacp_createInstance返回的创建的句柄
 * @param in: szTopic 取消订阅的topic
 * @return :
 *       =0:取消订阅成功
 *       <0:取消订阅失败
 */
LIBACP_EXPORTS int libacp_unsubscribe(IN ACP_HANDER handler, const char* szTopic);

/*
 * @brei: 释放创建的通讯的实例句柄,释放后无法进行网络数据交互
 * param handler:libacp_createInstance返回的创建的句柄
 * return 成功返回0,失败返回错误码
 */
LIBACP_EXPORTS int libacp_releaseInstance(IN ACP_HANDER handler);

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

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

/**
 * @brief 释放acp初始化的信息
 * return: 总是成功的,返回0
 */
LIBACP_EXPORTS int libacp_destory();

// ****************通讯协议接口的封装*************************//
/*
 * @brei: 下载文件到指定的ACP的服务下或者从ACP服务的机器上上传文件到本地
 * param addr: ACP服务的DeviceId和路由port
 * param indexGroup: ACP业务的IdGroup
 * param indexOffset: ACP业务的IdOffset
 * param szFilePath: 待操作的文件的全路径
 * param szDstDir:   目标目录
 * param callback:   回调通知进度的回调函数
 * param lpContext:  用户的回调函数指针
 * return
 *        失败返回0, 可以通过libacp_get_errno()获取对应的错误码
 *        成功返回传输Id,该传输Id关联到回答函数的传输Id
 */
LIBACP_EXPORTS uint32_t AcpFileTransfer(AcpDeviceAddr addr, uint32_t indexGroup, uint32_t indexOffset,
                                        const char* szFileFullPath, const char* szDstDir,
                                        pfnFileTransferCallback callback, void* lpContext);

#endif  // LIBACP_LIBACP_H_
