#include "DLT_Utilities.hpp"

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

// 构造函数
DLT_Log::DLT_Log()
{
    // 初始化内容
    this->loaded_msg_count = 0;
    this->max_payload_len = 0;
    this->Msg_List_Head = nullptr;
    this->Msg_List_End = nullptr;
}

// 析构函数
DLT_Log::~DLT_Log()
{
    clear();
}

// 清理请求的存储并恢复初始状态
void DLT_Log::clear(void)
{

    if (this->Msg_List_Head == nullptr)
        return;

    // 释放分配的空间
    while (this->Msg_List_Head != nullptr)
    {
        DLT_Type::DLT_Msg_Node *p_target = this->Msg_List_Head;
        this->Msg_List_Head = this->Msg_List_Head->p_next;
        free(p_target->Msg.payload_buffer);
        free(p_target);
    }

    // 初始化内容
    this->loaded_msg_count = 0;
    this->max_payload_len = 0;
    this->mem_use = 0;
    this->Msg_List_Head = nullptr;
    this->Msg_List_End = nullptr;
}

DLT_Type::DLT_Err DLT_Log::dlt_file_read_header(FILE *p_file, DLT_Type::DLT_Msg *Msg)
{
    if (Msg == nullptr)
        return DLT_Type::DLT_ERROR_NULL_POINTER;

    // 存储头
    {

        // 读取存储头
        if (fread(&(Msg->storage_header), sizeof(Msg->storage_header), 1, p_file) != 1)
        {
            if (feof(p_file))
                return DLT_Type::DLT_ERROR_END_OF_FILE;
            else
                return DLT_Type::DLT_ERROR_FILE_READ_FAILED;
        }

        // 检查存储头
        if (memcmp(Msg->storage_header.pattern, "DLT\x01", 4))
            return DLT_Type::DLT_ERROR_INVALID_HEADER;
    }

    // 标准头
    {
        // 读取标准头
        if (fread(&(Msg->standard_header), sizeof(Msg->standard_header), 1, p_file) != 1)
        {
            if (feof(p_file))
                return DLT_Type::DLT_ERROR_INCOMPLETE_DATA;
            else
                return DLT_Type::DLT_ERROR_FILE_READ_FAILED;
        }

        // 反向拼接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, p_file) != 1)
            {
                if (feof(p_file))
                    return DLT_Type::DLT_ERROR_INCOMPLETE_DATA;
                else
                    return DLT_Type::DLT_ERROR_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, p_file) != 1)
            {
                if (feof(p_file))
                    return DLT_Type::DLT_ERROR_INCOMPLETE_DATA;
                else
                    return DLT_Type::DLT_ERROR_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, p_file) != 1)
            {
                if (feof(p_file))
                    return DLT_Type::DLT_ERROR_INCOMPLETE_DATA;
                else
                    return DLT_Type::DLT_ERROR_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, p_file) != 1)
        {
            if (feof(p_file))
                return DLT_Type::DLT_ERROR_INCOMPLETE_DATA;
            else
                return DLT_Type::DLT_ERROR_FILE_READ_FAILED;
        }
    }

    // 计算Payload长度
    Msg->payload_length = Msg->standard_header.len - msg_header_len;

    return DLT_Type::DLT_ERROR_NONE;
}

DLT_Type::DLT_Err DLT_Log::dlt_file_read_payload(FILE *p_file, DLT_Type::DLT_Msg *Msg)
{
    if (Msg == nullptr)
        return DLT_Type::DLT_ERROR_NULL_POINTER;

    // 读取Payload
    Msg->payload_buffer = (uint8_t *)malloc(Msg->payload_length);
    this->mem_use += Msg->payload_length;

    if (Msg->payload_buffer == nullptr)
        return DLT_Type::DLT_ERROR_MEM_ALLOCATE_FAILED;

    if (fread(Msg->payload_buffer, Msg->payload_length, 1, p_file) != 1)
    {
        free(Msg->payload_buffer);
        this->mem_use -= Msg->payload_length;
        Msg->payload_buffer = nullptr;

        if (feof(p_file))
            return DLT_Type::DLT_ERROR_INCOMPLETE_DATA;
        else
            return DLT_Type::DLT_ERROR_FILE_READ_FAILED;
    }

    return ::DLT_Type::DLT_ERROR_NONE;
}

DLT_Type::DLT_Err DLT_Log::load_from_file(const char *file_name_str)
{
    // 打开文件
    FILE *p_file = fopen(file_name_str, "rb");
    if (p_file == nullptr)
        return DLT_Type::DLT_ERROR_FILE_OPEN_FAILED;

    // 解析消息内容
    {
        DLT_Type::DLT_Err err = DLT_Type::DLT_ERROR_NONE;
        while (1)
        {
            DLT_Type::DLT_Msg Msg;

            err = dlt_file_read_header(p_file, &Msg);
            if (err != DLT_Type::DLT_ERROR_NONE)
            {
                if (err == DLT_Type::DLT_ERROR_END_OF_FILE)
                    break;
                fclose(p_file);
                return err;
            }
            err = dlt_file_read_payload(p_file, &Msg);
            if (err != DLT_Type::DLT_ERROR_NONE)
            {
                fclose(p_file);
                return err;
            }

            DLT_Type::DLT_Msg_Node *p_target_msg = (DLT_Type::DLT_Msg_Node *)malloc(sizeof(DLT_Type::DLT_Msg_Node));
            this->mem_use += sizeof(DLT_Type::DLT_Msg_Node);
            if (p_target_msg == nullptr)
            {
                this->mem_use -= sizeof(DLT_Type::DLT_Msg_Node);
                fclose(p_file);
                return DLT_Type::DLT_ERROR_MEM_ALLOCATE_FAILED;
            }
            p_target_msg->p_next = nullptr;
            p_target_msg->Msg = Msg;

            if (this->Msg_List_Head == nullptr)
            {
                this->Msg_List_Head = this->Msg_List_End = p_target_msg;
            }
            else
            {
                this->Msg_List_End->p_next = p_target_msg;
                this->Msg_List_End = p_target_msg;
            }

            // 统计最长长度
            if (Msg.payload_length > this->max_payload_len)
                this->max_payload_len = Msg.payload_length;

            this->loaded_msg_count++;
        }
    }

    fclose(p_file);
    return DLT_Type::DLT_ERROR_NONE;
}

size_t DLT_Log::get_msg_list(DLT_Type::DLT_Msg_Node *(&p_msg_list))
{
    if (this->loaded_msg_count != 0)
        p_msg_list = this->Msg_List_Head;
    else
        p_msg_list = nullptr;

    return this->loaded_msg_count;
}

DLT_Type::DLT_Err DLT_Log::sort_msg_list(void)
{
    // 临时分配的排序用指针数组
    DLT_Type::DLT_Msg_Node **Node_P_Arr = (DLT_Type::DLT_Msg_Node **)malloc(sizeof(DLT_Type::DLT_Msg_Node *) * this->loaded_msg_count);
    if (Node_P_Arr == nullptr)
        return DLT_Type::DLT_ERROR_MEM_ALLOCATE_FAILED;

    // 填充地址数组
    {
        DLT_Type::DLT_Msg_Node *p_target_node = this->Msg_List_Head;
        for (size_t count = 0; count < loaded_msg_count; count++)
        {
            Node_P_Arr[count] = p_target_node;
            p_target_node = p_target_node->p_next;
        }
    }

    // qsort排序
    qsort(Node_P_Arr,
          loaded_msg_count,
          sizeof(DLT_Type::DLT_Msg_Node *),

          // 升序，小时间戳在前
          [](const void *param1, const void *param2) -> int
          {
              DLT_Type::DLT_Msg_Node *Node1 = *(DLT_Type::DLT_Msg_Node **)param1;
              DLT_Type::DLT_Msg_Node *Node2 = *(DLT_Type::DLT_Msg_Node **)param2;
              if (Node1->Msg.storage_header.seconds > Node2->Msg.storage_header.seconds)
                  return 1;
              else if (Node1->Msg.storage_header.seconds == Node2->Msg.storage_header.seconds)
              {
                  if (Node1->Msg.storage_header.microseconds > Node2->Msg.storage_header.microseconds)
                      return 1;
                  else if (Node1->Msg.storage_header.microseconds == Node2->Msg.storage_header.microseconds)
                  {
                      // 存在0.1ms时间戳
                      if (Node1->Msg.standard_header.htyp.WTMS && Node2->Msg.standard_header.htyp.WTMS)
                      {
                          if (Node1->Msg.standard_header_extra.tmsp > Node2->Msg.standard_header_extra.tmsp)
                              return 1;
                          else if (Node1->Msg.standard_header_extra.tmsp == Node2->Msg.standard_header_extra.tmsp)
                              return 0;
                          else if (Node1->Msg.standard_header_extra.tmsp < Node2->Msg.standard_header_extra.tmsp)
                              return -1;
                      }
                      else
                          return 0;
                  }
                  else
                      return -1;
              }
              else
                  return -1;

              return 0;
          });

    // 重新连接消息列表
    {
        this->Msg_List_Head = Node_P_Arr[0];
        this->Msg_List_End = Node_P_Arr[this->loaded_msg_count - 1];
        this->Msg_List_End->p_next = nullptr;

        DLT_Type::DLT_Msg_Node *p_target = Node_P_Arr[0];
        for (size_t count = 1; count < this->loaded_msg_count; count++)
        {
            p_target->p_next = Node_P_Arr[count];
            p_target = p_target->p_next;
        }
    }

    // 释放空间
    free(Node_P_Arr);
    return DLT_Type::DLT_ERROR_NONE;
}

DLT_Type::DLT_Err DLT_Log::export_to_csv(const char *file_name_str)
{
    FILE *p_file = fopen(file_name_str, "wb");
    if (p_file == nullptr)
        return DLT_Type::DLT_ERROR_FILE_CREATE_FAILED;

    // 打印首行
    {
        fprintf(p_file, "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(p_file, "B%d,", count);
        fseek(p_file, -1, SEEK_CUR);
        fprintf(p_file, "\r\n");
    }

    // 遍历每行数据
    DLT_Type::DLT_Msg_Node *p_msg = this->Msg_List_Head;
    for (size_t line_count = 0; line_count < this->loaded_msg_count; line_count++)
    {

        // 输出索引号
        fprintf(p_file, "%d,", line_count);

        // 输出日期和时间
        {
            time_t timestamp = (time_t)p_msg->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(p_file, "%s.%d,", time_str, p_msg->Msg.storage_header.microseconds);
        }

        // 输出头附加信息
        {
            // 存在扩展时间戳
            if (p_msg->Msg.standard_header.htyp.WTMS)
            {
                /**< Timestamp since system start in 0.1 milliseconds */
                char time_str[20];
                sprintf(time_str, "%d", p_msg->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, p_file);
                    // 输出剩余的时间
                    fprintf(p_file, ".%s,", p_sec_end);
                }
                else
                {
                    fprintf(p_file, "0.");
                    for (int count = 4 - strlen(time_str); count > 0; count--)
                        fputc('0', p_file);
                    fprintf(p_file, "%s,", time_str);
                }
            }
            else
                fprintf(p_file, "N/A,");

            // 消息计数
            fprintf(p_file, "%d,", p_msg->Msg.standard_header.mcnt);

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

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

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

            // 输出 Type 、Subtype 、Mode 、#Args
            if (p_msg->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(p_file, "%s,", Type_str[p_msg->Msg.extendedheader.msin.MSTP]);
                fprintf(p_file, "%s,", SubType_Str[p_msg->Msg.extendedheader.msin.MSTP][(p_msg->Msg.extendedheader.msin.MTIN - 1) % 0xF]);

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

        // Payload概览行
        fprintf(p_file, ",");

        // 逐个打印 Payload
        for (size_t count = 0; count < p_msg->Msg.payload_length; count++)
            fprintf(p_file, "%0X,", p_msg->Msg.payload_buffer[count]);

        fseek(p_file, -1, SEEK_CUR);
        fprintf(p_file, "\r\n");

        p_msg = p_msg->p_next;
    }

    fclose(p_file);

    return DLT_Type::DLT_ERROR_NONE;
}