#ifndef __DLT_UTILITIES_HPP__
#define __DLT_UTILITIES_HPP__

extern "C"
{
#include "stdint.h"
#include "stdio.h"
}

// DLT 类型定义
namespace DLT_Type
{
#pragma pack(1) // 紧凑字节对齐

    /**
     * The structure of the DLT file storage header. This header is used before each stored DLT message.
     */
    typedef struct
    {
        char pattern[4];      /**< This pattern should be DLT0x01 */
        uint32_t seconds;     /**< seconds since 1.1.1970 */
        int32_t microseconds; /**< Microseconds */
        char ecu[4];          /**< The ECU id is added, if it is not already in the DLT message itself */
    } DltStorageHeader;

    typedef struct
    {
        struct
        {
            uint8_t UEH : 1;  // Use Extended Header            1 启用扩展头        0 不启用
            uint8_t MSBF : 1; // Most Significant Byte First    1 Payload大端序列   0 小端序列
            uint8_t WEID : 1; // With ECU ID      (4 Byte)      1 包含ECU_ID        0 不含
            uint8_t WSID : 1; // With Session ID  (4 Byte)      1 包含会话 ID       0 不含
            uint8_t WTMS : 1; // With Timestamp   (4 Byte)      1 含时间戳          0 不含
            uint8_t VERS : 3; // Version Number DLT协议版本

        } htyp;       /**< This parameter contains several informations, see definitions below */
        uint8_t mcnt; /**< The message counter is increased with each sent DLT message */
        uint16_t len; /**< Length of the complete message, without storage header */
    } DltStandardHeader;

    /**
     * The structure of the DLT extra header parameters. Each parameter is sent only if enabled in htyp.
     */
    typedef struct
    {
        char ecu[4];   /**< ECU id */
        uint32_t seid; /**< Session number */
        uint32_t tmsp; /**< Timestamp since system start in 0.1 milliseconds */
    } DltStandardHeaderExtra;

    /**
     * The structure of the DLT extended header. This header is only sent if enabled in htyp parameter.
     */
    typedef struct
    {
        struct
        {
            uint8_t VERB : 1; // (Verbose) 冗余模式   1 启用        0 不启用
            uint8_t MSTP : 3; // (Message Type)
            uint8_t MTIN : 4; // (Message Type Info)
        } msin;               /**< messsage info */
        uint8_t noar;         /**< number of arguments */
        char apid[4];         /**< application id */
        char ctid[4];         /**< context id */
    } DltExtendedHeader;

#pragma pack(0) // 恢复字节对齐

    // DLT 错误信息枚举
    typedef enum
    {
        DLT_ERROR_NONE = 0,            // 无错误
        DLT_ERROR_NULL_POINTER,        // 空指针
        DLT_ERROR_FILE_OPEN_FAILED,    // 文件打开失败
        DLT_ERROR_FILE_READ_FAILED,    // 文件读取失败
        DLT_ERROR_FILE_CREATE_FAILED,  // 文件创建失败
        DLT_ERROR_END_OF_FILE,         // 文件结尾
        DLT_ERROR_INVALID_HEADER,      // 非法头
        DLT_ERROR_INCOMPLETE_DATA,     // 数据不完整
        DLT_ERROR_MEM_ALLOCATE_FAILED, // 内存分配失败
        DLT_ERROR_MSG_LIST_EMPTY,      // 消息列表为空
    } DLT_Err;

    // DLT消息条目结构定义
    typedef struct
    {
        DltStorageHeader storage_header;              // 存储头
        DltStandardHeader standard_header;            // 标准头
        DltStandardHeaderExtra standard_header_extra; // 标准头额外内容
        DltExtendedHeader extendedheader;             // 扩展头
        size_t payload_length;                        // 消息长度
        uint8_t *payload_buffer;                      // 载荷
    } DLT_Msg;                                        // 文件中的消息条目

    // DLT消息链表节点
    typedef struct DLT_Msg_Node_Struct
    {
        DLT_Msg Msg;
        DLT_Msg_Node_Struct *p_next;
    } DLT_Msg_Node;
}

// DLT 日志类
class DLT_Log
{
private:
    size_t loaded_msg_count; // 消息条目计数
    size_t max_payload_len;  // 最长载荷长度
    size_t mem_use;          // 存储占用

    DLT_Type::DLT_Msg_Node *Msg_List_Head; // 消息列表头
    DLT_Type::DLT_Msg_Node *Msg_List_End;  // 消息列表尾

    /**
     * @brief   从文件中读取dlt头
     * @param   p_file              要读取的文件
     * @param   Msg                 读取后存储的目标结构体
     * @return  DLT_Type::DLT_Err   错误类型枚举
     */
    DLT_Type::DLT_Err dlt_file_read_header(FILE *p_file, DLT_Type::DLT_Msg *Msg);

    /**
     * @brief   从文件中读取dlt载荷
     * @param   p_file              要读取的文件
     * @param   Msg                 读取后存储的目标结构体
     * @return  DLT_Type::DLT_Err   错误类型枚举
     */
    DLT_Type::DLT_Err dlt_file_read_payload(FILE *p_file, DLT_Type::DLT_Msg *Msg);

public:
    DLT_Log();  // 构造函数
    ~DLT_Log(); // 析构函数
    /**
     * @brief 从文件加载DLT消息，多个文件会顺序加入
     * @param file_name_str         目标文件名
     * @return DLT_Type::DLT_Err    错误类型枚举
     */
    DLT_Type::DLT_Err load_from_file(const char *file_name_str);

    /**
     * @brief 获取解析完成的消息列表
     * @param p_msg_list 消息列表存入的指针
     * @return 消息列表计数
     */
    size_t get_msg_list(DLT_Type::DLT_Msg_Node *(&p_msg_list));

    /**
     * @brief 将消息列表按时间戳排序
     * @param null
     * @return DLT_Type::DLT_Err    错误类型枚举
     */
    DLT_Type::DLT_Err sort_msg_list(void);

    /**
     * @brief 导出为CSV
     * @param file_name_str 目标文件名
     * @return DLT_Type::DLT_Err 错误类型枚举
     */
    DLT_Type::DLT_Err export_to_csv(const char *file_name_str);

    /**
     * @brief 清理请求的存储并恢复初始状态
     * @param null
     * @return null
     */
    void clear(void);
};

#endif