#include "DLT_Utilities.hpp"

extern "C"
{
#include "stdlib.h"
#include "string.h"
#include "sys/time.h"
}

/**
 * @brief 从文件加载
 * @param path_to_file 文件路径串
 * @return std::string 错误信息
 */
std::string DLT_Log::Load_From_File(const char *path_to_file)
{
    // 尝试打开文件
    FILE *pFile = fopen(path_to_file, "rb");
    if (pFile == nullptr)
        return "File \"" + std::string(path_to_file) + "\" open failed.";

    // Lambda 读取头
    auto Lambda_Read_Header = [&](DLT_Msg &Msg) -> std::string
    {
        // 读取存储头
        if (fread(&(Msg.storage_header), sizeof(Msg.storage_header), 1, pFile) != 1)
        {
            if (feof(pFile))
                return "Unexpected EOF.";
            else
                return "File read failed.";
        }

        // 检查存储头
        if (memcmp(Msg.storage_header.pattern, "DLT\x01", 4))
            return "Invalid storage header pattern.Must be \"DLT0x01\".";

        // 读取标准头
        if (fread(&(Msg.standard_header), sizeof(Msg.standard_header), 1, pFile) != 1)
        {
            if (feof(pFile))
                return "Unexpected EOF.";
            else
                return "File read failed.";
        }

        // 检查标准头协议版本
        if (Msg.standard_header.htyp.VERS != 0x01)
            return "Unsupported protocol version.";

        // 反向拼接len字段
        // [PRS_Dlt_00091] ⌈The Standard Header and the Extended Header shall be in big endian format (MSB first).⌋ (RS_LT_00016,RS_LT_00013)
        // DLT标准头是大端序，与小端序存储的uint16正好相反，所以需要反向
        {
            uint16_t len_swap;
            *((uint8_t *)&len_swap) = *(((uint8_t *)&Msg.standard_header.len) + 1);
            *(((uint8_t *)&len_swap) + 1) = *((uint8_t *)&Msg.standard_header.len);
            Msg.standard_header.len = len_swap;
        }

        // 消息头长度统计
        size_t msg_header_len = sizeof(Msg.standard_header);

        // 标准头扩展部分
        {
            // 含有额外的ECU ID
            if (Msg.standard_header.htyp.WEID)
            {
                msg_header_len += sizeof(Msg.standard_header_extra.ecu);

                if (fread(&(Msg.standard_header_extra.ecu), sizeof(Msg.standard_header_extra.ecu), 1, pFile) != 1)
                {
                    if (feof(pFile))
                        return "Unexpected EOF.";
                    else
                        return "File read failed.";
                }
            }

            // 含有额外的 Session ID (会话ID)
            if (Msg.standard_header.htyp.WSID)
            {
                msg_header_len += sizeof(Msg.standard_header_extra.seid);

                if (fread(&(Msg.standard_header_extra.seid), sizeof(Msg.standard_header_extra.seid), 1, pFile) != 1)
                {
                    if (feof(pFile))
                        return "Unexpected EOF.";
                    else
                        return "File read failed.";
                }

                // 反向拼接Session ID字段
                // [PRS_Dlt_00091] ⌈The Standard Header and the Extended Header shall be in big endian format (MSB first).⌋ (RS_LT_00016,RS_LT_00013)
                {
                    uint32_t data_swap;

                    *((uint8_t *)&data_swap) = *(((uint8_t *)&Msg.standard_header_extra.seid) + 3);
                    *(((uint8_t *)&data_swap) + 1) = *(((uint8_t *)&Msg.standard_header_extra.seid) + 2);
                    *(((uint8_t *)&data_swap) + 2) = *(((uint8_t *)&Msg.standard_header_extra.seid) + 1);
                    *(((uint8_t *)&data_swap) + 3) = *((uint8_t *)&Msg.standard_header_extra.seid);

                    Msg.standard_header_extra.seid = data_swap;
                }
            }

            // 含有额外的 timestamp (0.1ms 自系统启动后的时间计数)
            if (Msg.standard_header.htyp.WSID)
            {
                msg_header_len += sizeof(Msg.standard_header_extra.tmsp);

                if (fread(&(Msg.standard_header_extra.tmsp), sizeof(Msg.standard_header_extra.tmsp), 1, pFile) != 1)
                {
                    if (feof(pFile))
                        return "Unexpected EOF.";
                    else
                        return "File read failed.";
                }

                // 反向拼接Session ID字段
                // [PRS_Dlt_00091] ⌈The Standard Header and the Extended Header shall be in big endian format (MSB first).⌋ (RS_LT_00016,RS_LT_00013)
                {
                    uint32_t data_swap;

                    *((uint8_t *)&data_swap) = *(((uint8_t *)&Msg.standard_header_extra.tmsp) + 3);
                    *(((uint8_t *)&data_swap) + 1) = *(((uint8_t *)&Msg.standard_header_extra.tmsp) + 2);
                    *(((uint8_t *)&data_swap) + 2) = *(((uint8_t *)&Msg.standard_header_extra.tmsp) + 1);
                    *(((uint8_t *)&data_swap) + 3) = *((uint8_t *)&Msg.standard_header_extra.tmsp);

                    Msg.standard_header_extra.tmsp = data_swap;
                }
            }
        }

        // 扩展头读取
        if (Msg.standard_header.htyp.UEH)
        {
            msg_header_len += sizeof(Msg.extendedheader);

            // 读取标扩展头
            if (fread(&(Msg.extendedheader), sizeof(Msg.extendedheader), 1, pFile) != 1)
            {
                if (feof(pFile))
                    return "Unexpected EOF.";
                else
                    return "File read failed.";
            }
        }

        // 分配payload空间并无错误信息返回
        Msg.payload.resize(Msg.standard_header.len - msg_header_len);
        return std::string();
    };

    // Lambda 读取载荷
    auto Lambda_Read_Payload = [&](DLT_Msg &Msg) -> std::string
    {
        if (fread(&Msg.payload[0], Msg.payload.size(), 1, pFile) != 1)
        {
            if (feof(pFile))
                return "Unexpected EOF.";
            else
                return "File read failed.";
        }

        return std::string();
    };

    // 错误信息串
    std::string err_str;
    // 循环解析文件
    while (true)
    {
        DLT_Msg Msg = {0};

        err_str = Lambda_Read_Header(Msg);
        if (!err_str.empty())
            break;

        if (Msg.payload.size() > 0)
            err_str = Lambda_Read_Payload(Msg);

        if (err_str.empty() == true)
        {
            if (Msg.payload.size() > this->private_max_payload_len)
                this->private_max_payload_len = Msg.payload.size();
            this->private_msg_list.push_back(Msg);
        }
        else
            break;

        // 读取结束判定
        if (fgetc(pFile) == EOF)
            break;
        else
            fseek(pFile, -1, SEEK_CUR);
    }

    fclose(pFile);
    return err_str;
}

/**
 * @brief 以CSV格式导出到文件
 * @param path_to_file 文件路径串
 * @return std::string 错误信息
 */
std::string DLT_Log::Export_CSV(const char *path_to_file)
{
    // 尝试打开文件
    FILE *pFile = fopen(path_to_file, "wb");
    if (pFile == nullptr)
        return "File \"" + std::string(path_to_file) + "\" open failed.";

    // 打印首行
    {
        fprintf(pFile, "Index,Date&Time(Local),Timestamp,Count,ECU ID,Application ID,Context ID ,Session ID,Type,Sub Type,Mode,#Args,Payload,");

        for (size_t count = 0; count < this->max_payload_len; count++)
            fprintf(pFile, "B%d,", count);
        fseek(pFile, -1, SEEK_CUR);
        fprintf(pFile, "\r\n");
    }

    // 遍历每行数据
    size_t line_count = 0;
    for (auto Msg : this->private_msg_list)
    {
        // 输出索引号
        fprintf(pFile, "%d,", line_count);

        // 输出日期和时间
        {
            time_t timestamp = (time_t)Msg.storage_header.seconds;
            struct tm *time_struct = localtime(&timestamp);
            char time_str[100] = {'\0'};
            // 格式化为 "YY/MM/DD HH:MM:SS"
            strftime(time_str, sizeof(time_str), "%Y/%m/%d %H:%M:%S", time_struct);
            fprintf(pFile, "%s.%d,", time_str, Msg.storage_header.microseconds);
        }

        // 输出头附加信息
        {
            // 存在扩展时间戳
            if (Msg.standard_header.htyp.WTMS)
            {
                /**< Timestamp since system start in 0.1 milliseconds */
                char time_str[20];
                sprintf(time_str, "%d", Msg.standard_header_extra.tmsp);
                if (strlen(time_str) > 4)
                {
                    char *p_sec_end = time_str + strlen(time_str) - 4;

                    // 输出秒
                    for (char *p = time_str; p < p_sec_end; p++)
                        fputc(*p, pFile);
                    // 输出剩余的时间
                    fprintf(pFile, ".%s,", p_sec_end);
                }
                else
                {
                    fprintf(pFile, "0.");
                    for (int count = 4 - strlen(time_str); count > 0; count--)
                        fputc('0', pFile);
                    fprintf(pFile, "%s,", time_str);
                }
            }
            else
                fprintf(pFile, "N/A,");

            // 消息计数
            fprintf(pFile, "%d,", Msg.standard_header.mcnt);

            // 存在扩展ECU ID
            if (Msg.standard_header.htyp.WEID)
                fprintf(pFile, "%.4s,", Msg.standard_header_extra.ecu);
            else
                fprintf(pFile, "%.4s,", Msg.storage_header.ecu);

            // 输出 Apid 和 Ctid
            if (Msg.standard_header.htyp.UEH)
            {
                fprintf(pFile, "%.4s,", Msg.extendedheader.apid);
                fprintf(pFile, "%.4s,", Msg.extendedheader.ctid);
            }
            else
            {
                // skip apid && ctid
                fprintf(pFile, "N/A,N/A,");
            }

            // 存在 Session ID
            if (Msg.standard_header.htyp.WSID)
                fprintf(pFile, "%d,", Msg.standard_header_extra.seid);
            else
                fprintf(pFile, "N/A,");

            // 输出 Type 、Subtype 、Mode 、#Args
            if (Msg.standard_header.htyp.UEH)
            {
                const char *Type_str[] = {"log", "trace", "network", "control"};
                const char *SubType_Str[][0xF] = {
                    // LOG
                    {"fatal", "error", "warn", "info", "debug", "verbose", nullptr},
                    // Trace
                    {"variable", "function in", "function out", "state", "vbf", nullptr},
                    // Network
                    {"IPC", "CAN", "FlexRay", "Most", "Ethernet", "SOME/IP", "0x7", "0x8", "0x9", "0xA", "0xB", "0xC", "0xD", "0xE", "0xF"},
                    // Control
                    {"Request", "response", nullptr},
                };

                // Type && Subtype
                fprintf(pFile, "%s,", Type_str[Msg.extendedheader.msin.MSTP]);
                fprintf(pFile, "%s,", SubType_Str[Msg.extendedheader.msin.MSTP][(Msg.extendedheader.msin.MTIN - 1) % 0xF]);

                // Mode && #Args
                fprintf(pFile, "%s,", Msg.extendedheader.msin.VERB ? "verbose" : "non-verbose");
                fprintf(pFile, "%d,", Msg.extendedheader.noar);
            }
            else
                fprintf(pFile, "N/A,N/A,N/A,N/A,");
        }

        // Payload概览列跳过
        fprintf(pFile, ",");

        // 逐个打印 Payload
        for (auto data_byte : Msg.payload)
            fprintf(pFile, "%0X,", data_byte);

        // 结束行
        fseek(pFile, -1, SEEK_CUR);
        fprintf(pFile, "\r\n");
        line_count++;
    }

    fclose(pFile);
    return std::string();
}

// 对消息列表进行排序
void DLT_Log::Sort(void)
{
    // Quick Sort
    qsort(&this->private_msg_list[0],
          this->private_msg_list.size(),
          sizeof(this->private_msg_list[0]),
          [](const void *param1, const void *param2) -> int
          {
              const DLT_Msg *pMsg1 = (const DLT_Msg *)param1;
              const DLT_Msg *pMsg2 = (const DLT_Msg *)param2;

              if (pMsg1->storage_header.seconds > pMsg2->storage_header.seconds)
                  return 1;
              else if (pMsg1->storage_header.seconds == pMsg2->storage_header.seconds)
              {
                  if (pMsg1->storage_header.microseconds > pMsg2->storage_header.microseconds)
                      return 1;
                  else if (pMsg1->storage_header.microseconds == pMsg2->storage_header.microseconds)
                  {
                      // 存在0.1ms时间戳
                      if (pMsg1->standard_header.htyp.WTMS && pMsg2->standard_header.htyp.WTMS)
                      {
                          if (pMsg1->standard_header_extra.tmsp > pMsg2->standard_header_extra.tmsp)
                              return 1;
                          else if (pMsg1->standard_header_extra.tmsp == pMsg2->standard_header_extra.tmsp)
                              return 0;
                          else
                              return -1;
                      }
                      else
                          return 0;
                  }
                  else
                      return -1;
              }
              else
                  return -1;

              return 0;
          });
}

// 清除缓存的信息
void DLT_Log::Clear(void)
{
    this->private_max_payload_len = 0;

    // 清空内容
    std::vector<DLT_Msg> empty_list;
    this->private_msg_list.swap(empty_list);
}