#include "CSV_Utilities.hpp"

extern "C"
{
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
}

CSV_Table::CSV_Table()
{
    this->column_count = 0;
    this->mem_use = 0;
    this->max_element_depth = 0;
    this->Column_List_End = this->Column_List_Head = nullptr;
}

CSV_Table::~CSV_Table()
{
    this->reset();
}

void CSV_Table::reset()
{
    // 清理尾指针
    this->Column_List_End = nullptr;
    this->max_element_depth = 0;
    this->column_count = 0;
    this->mem_use = 0;

    // 清理头指针及其内容
    if (this->Column_List_Head != nullptr)
    {
        // 释放列
        while (this->Column_List_Head != nullptr)
        {
            decltype(this->Column_List_Head) p_target_column = this->Column_List_Head;

            // 释放单元格列表
            while (p_target_column->Cell_List_Head != nullptr)
            {
                decltype(p_target_column->Cell_List_Head) p_target_cell = p_target_column->Cell_List_Head;

                // 释放单元格内容
                if (p_target_cell->content_str != nullptr)
                    free(p_target_cell->content_str);

                p_target_column->Cell_List_Head = p_target_cell->p_next_cell;
                free(p_target_cell->content_str);
            }

            // 释放标题
            if (p_target_column->column_title_str != nullptr)
                free(p_target_column->column_title_str);

            this->Column_List_Head = p_target_column->p_next_column;
            free(p_target_column);
        }
    }
}

CSV_Type::CSV_Err CSV_Table::append_column(const char *title_name_str)
{

    // 开辟新节点
    decltype(this->Column_List_Head) p_new_column = (decltype(this->Column_List_Head))malloc(sizeof(*(this->Column_List_Head)));
    if (p_new_column == nullptr)
        return CSV_Type::CSV_ERROR_MEM_ALLOCATE_FAILED;
    this->mem_use += sizeof(*p_new_column);
    // 节点初始化
    p_new_column->Cell_List_Head = p_new_column->Cell_List_End = nullptr;
    p_new_column->p_next_column = nullptr;
    p_new_column->element_count = 0;

    // 存储列标题名
    if (title_name_str != nullptr)
    {
        char *p_title = (char *)malloc(strlen(title_name_str) + 1); // +1 for '\0'
        if (p_title == nullptr)
        {
            free(p_new_column);
            return CSV_Type::CSV_ERROR_MEM_ALLOCATE_FAILED;
        }

        this->mem_use += strlen(title_name_str) + 1;
        strcpy(p_title, title_name_str);
        p_new_column->column_title_str = p_title;
    }
    else
        p_new_column->column_title_str = nullptr;

    // 插入列链表
    if (this->column_count == 0)
        this->Column_List_End = this->Column_List_Head = p_new_column;
    else
    {
        this->Column_List_End->p_next_column = p_new_column;
        this->Column_List_End = p_new_column;
    }

    this->column_count++;
    return CSV_Type::CSV_ERROR_NONE;
}

CSV_Type::CSV_Err CSV_Table::insert_column_after(const char *target_column_title_str, const char *title_name_str)
{
    size_t count = 0;
    decltype(this->Column_List_Head) p_target_column = this->Column_List_Head;
    while (p_target_column != nullptr)
    {
        if (!strcmp(p_target_column->column_title_str, target_column_title_str))
            return this->insert_column_after(count, title_name_str);

        p_target_column = p_target_column->p_next_column;
        count++;
    }
    return CSV_Type::CSV_ERROR_COLUMN_NOT_FOUND;
}

CSV_Type::CSV_Err CSV_Table::insert_column_after(size_t target_column_position, const char *title_name_str)
{
    if (!(((target_column_position + 1) <= this->column_count) || ((target_column_position == 0) && (this->column_count == 0))))
        return CSV_Type::CSV_ERROR_ILLEGAL_COLUMN_POSITION;

    decltype(this->Column_List_Head) p_target_column = this->Column_List_Head;
    for (size_t count = 0; count < target_column_position; count++)
        p_target_column = p_target_column->p_next_column;

    // 开辟新节点
    decltype(p_target_column) p_new_column = (decltype(p_target_column))malloc(sizeof(*(p_target_column)));
    if (p_new_column == nullptr)
        return CSV_Type::CSV_ERROR_MEM_ALLOCATE_FAILED;
    this->mem_use += sizeof(*p_new_column);

    // 节点初始化
    p_new_column->Cell_List_Head = p_new_column->Cell_List_End = nullptr;
    p_new_column->p_next_column = nullptr;
    p_new_column->element_count = 0;

    // 存储列标题名
    if (title_name_str != nullptr)
    {
        char *p_title = (char *)malloc(strlen(title_name_str) + 1); // +1 for '\0'
        if (p_title == nullptr)
        {
            free(p_new_column);
            return CSV_Type::CSV_ERROR_MEM_ALLOCATE_FAILED;
        }

        this->mem_use += strlen(title_name_str) + 1;
        strcpy(p_title, title_name_str);
        p_new_column->column_title_str = p_title;
    }
    else
        p_new_column->column_title_str = nullptr;

    // 内部列表为空
    if (this->column_count == 0)
        this->Column_List_Head = this->Column_List_End = p_new_column;
    else
    {
        // 链接节点
        p_new_column->p_next_column = p_target_column->p_next_column;
        p_target_column->p_next_column = p_new_column;

        // 目标位置在末尾时
        if (target_column_position == this->column_count - 1)
            this->Column_List_End = p_new_column;
    }

    this->column_count++;
    return CSV_Type::CSV_ERROR_NONE;
}

CSV_Type::CSV_Err CSV_Table::insert_column_before(const char *target_column_title_str, const char *title_name_str)
{
    size_t count = 0;
    decltype(this->Column_List_Head) p_target_column = this->Column_List_Head;
    while (p_target_column != nullptr)
    {
        if (!strcmp(p_target_column->column_title_str, target_column_title_str))
            return this->insert_column_before(count, title_name_str);

        p_target_column = p_target_column->p_next_column;
        count++;
    }
    return CSV_Type::CSV_ERROR_COLUMN_NOT_FOUND;
}

CSV_Type::CSV_Err CSV_Table::insert_column_before(size_t target_column_position, const char *title_name_str)
{
    if (!(((target_column_position + 1) <= this->column_count) || ((target_column_position == 0) && (this->column_count == 0))))
        return CSV_Type::CSV_ERROR_ILLEGAL_COLUMN_POSITION;

    decltype(this->Column_List_Head) p_pre_column = this->Column_List_Head;
    decltype(this->Column_List_Head) p_target_column = this->column_count > 0 ? this->Column_List_Head->p_next_column : nullptr;
    for (size_t count = 1; count < target_column_position; count++)
    {
        p_pre_column = p_pre_column->p_next_column;
        p_target_column = p_target_column->p_next_column;
    }

    // 开辟新节点
    decltype(p_target_column) p_new_column = (decltype(p_target_column))malloc(sizeof(*(p_target_column)));
    if (p_new_column == nullptr)
        return CSV_Type::CSV_ERROR_MEM_ALLOCATE_FAILED;
    this->mem_use += sizeof(*p_new_column);

    // 节点初始化
    p_new_column->Cell_List_Head = p_new_column->Cell_List_End = nullptr;
    p_new_column->p_next_column = nullptr;
    p_new_column->element_count = 0;

    // 存储列标题名
    if (title_name_str != nullptr)
    {
        char *p_title = (char *)malloc(strlen(title_name_str) + 1); // +1 for '\0'
        if (p_title == nullptr)
        {
            free(p_new_column);
            return CSV_Type::CSV_ERROR_MEM_ALLOCATE_FAILED;
        }

        this->mem_use += strlen(title_name_str) + 1;
        strcpy(p_title, title_name_str);
        p_new_column->column_title_str = p_title;
    }
    else
        p_new_column->column_title_str = nullptr;

    // 链接节点
    if (this->column_count == 0)
        this->Column_List_Head = this->Column_List_End = p_new_column;
    else
    {
        if (target_column_position == 0)
        {
            // 目标为表头
            p_new_column->p_next_column = this->Column_List_Head;
            this->Column_List_Head = p_new_column;
        }
        else
        {
            p_new_column->p_next_column = p_target_column;
            p_pre_column->p_next_column = p_new_column;
        }
    }

    this->column_count++;

    return CSV_Type::CSV_ERROR_NONE;
}

CSV_Type::CSV_Err CSV_Table::append_cell(const char *target_column_title_str, const char *cell_content_str)
{
    size_t count = 0;
    decltype(this->Column_List_Head) p_target_column = this->Column_List_Head;
    while (p_target_column != nullptr)
    {
        if (!strcmp(p_target_column->column_title_str, target_column_title_str))
            return this->append_cell(count, cell_content_str);

        p_target_column = p_target_column->p_next_column;
        count++;
    }
    return CSV_Type::CSV_ERROR_COLUMN_NOT_FOUND;
}

CSV_Type::CSV_Err CSV_Table::append_cell(size_t target_column_position, const char *cell_content_str)
{
    if ((target_column_position + 1) > this->column_count)
        return CSV_Type::CSV_ERROR_COLUMN_NOT_FOUND;

    decltype(this->Column_List_Head) p_target_column = this->Column_List_Head;
    for (size_t count = 0; count < target_column_position; count++)
        p_target_column = p_target_column->p_next_column;

    decltype(p_target_column->Cell_List_Head) p_new_cell = (decltype(p_target_column->Cell_List_Head))malloc(sizeof(*(p_target_column->Cell_List_Head)));
    if (p_new_cell == nullptr)
        return CSV_Type::CSV_ERROR_MEM_ALLOCATE_FAILED;
    this->mem_use += sizeof(*p_new_cell);

    if (cell_content_str != nullptr)
    {
        char *p_content = (char *)malloc(strlen(cell_content_str) + 1); // +1 for '\0'
        if (p_content == nullptr)
        {
            free(p_new_cell);
            return CSV_Type::CSV_ERROR_MEM_ALLOCATE_FAILED;
        }

        this->mem_use += strlen(cell_content_str) + 1;
        strcpy(p_content, cell_content_str);
        p_new_cell->content_str = p_content;
    }
    else
        p_new_cell->content_str = nullptr;
    p_new_cell->p_next_cell = nullptr;

    if (p_target_column->element_count == 0)
        p_target_column->Cell_List_Head = p_target_column->Cell_List_End = p_new_cell;
    else
    {
        p_target_column->Cell_List_End->p_next_cell = p_new_cell;
        p_target_column->Cell_List_End = p_new_cell;
    }

    p_target_column->element_count++;

    if (p_target_column->element_count > this->max_element_depth)
        this->max_element_depth = p_target_column->element_count;

    return CSV_Type::CSV_ERROR_NONE;
}

CSV_Type::CSV_Err CSV_Table::insert_cell_after(const char *target_column_title_str, size_t target_cell_position, const char *cell_content_str)
{
    size_t count = 0;
    decltype(this->Column_List_Head) p_target_column = this->Column_List_Head;
    while (p_target_column != nullptr)
    {
        if (!strcmp(p_target_column->column_title_str, target_column_title_str))
            return this->insert_cell_after(count, target_cell_position, cell_content_str);

        p_target_column = p_target_column->p_next_column;
        count++;
    }
    return CSV_Type::CSV_ERROR_COLUMN_NOT_FOUND;
}

CSV_Type::CSV_Err CSV_Table::insert_cell_after(size_t target_column_position, size_t target_cell_position, const char *cell_content_str)
{
    if ((target_column_position + 1) > this->column_count)
        return CSV_Type::CSV_ERROR_ILLEGAL_COLUMN_POSITION;
    decltype(this->Column_List_Head) p_target_column = this->Column_List_Head;
    for (size_t count = 0; count < target_column_position; count++)
        p_target_column = p_target_column->p_next_column;

    if (!(((target_cell_position + 1) <= p_target_column->element_count) || ((target_cell_position == 0) && (p_target_column->element_count == 0))))
        return CSV_Type::CSV_ERROR_ILLEGAL_CELL_POSITION;

    decltype(p_target_column->Cell_List_Head) p_new_cell = (decltype(p_target_column->Cell_List_Head))malloc(sizeof(*(p_target_column->Cell_List_Head)));
    if (p_new_cell == nullptr)
        return CSV_Type::CSV_ERROR_MEM_ALLOCATE_FAILED;
    this->mem_use += sizeof(*p_new_cell);

    if (cell_content_str != nullptr)
    {
        char *p_content = (char *)malloc(strlen(cell_content_str) + 1); // +1 for '\0'
        if (p_content == nullptr)
        {
            free(p_new_cell);
            return CSV_Type::CSV_ERROR_MEM_ALLOCATE_FAILED;
        }

        this->mem_use += strlen(cell_content_str) + 1;
        strcpy(p_content, cell_content_str);
        p_new_cell->content_str = p_content;
    }
    else
        p_new_cell->content_str = nullptr;

    if (p_target_column->element_count == 0)
    {
        p_new_cell->p_next_cell = nullptr;
        p_target_column->Cell_List_Head = p_target_column->Cell_List_End = p_new_cell;
    }
    else
    {
        decltype(p_new_cell) p_target_cell = p_target_column->Cell_List_Head;
        for (size_t count = 0; count < target_cell_position; count++)
            p_target_cell = p_target_cell->p_next_cell;

        p_new_cell->p_next_cell = p_target_cell->p_next_cell;
        p_target_cell->p_next_cell = p_new_cell;
        if ((target_cell_position + 1) == p_target_column->element_count)
            p_target_column->Cell_List_End = p_new_cell;
    }

    p_target_column->element_count++;

    if (p_target_column->element_count > this->max_element_depth)
        this->max_element_depth = p_target_column->element_count;

    return CSV_Type::CSV_ERROR_NONE;
}

CSV_Type::CSV_Err CSV_Table::insert_cell_before(const char *target_column_title_str, size_t target_cell_position, const char *cell_content_str)
{
    size_t count = 0;
    decltype(this->Column_List_Head) p_target_column = this->Column_List_Head;
    while (p_target_column != nullptr)
    {
        if (!strcmp(p_target_column->column_title_str, target_column_title_str))
            return this->insert_cell_before(count, target_cell_position, cell_content_str);

        p_target_column = p_target_column->p_next_column;
        count++;
    }
    return CSV_Type::CSV_ERROR_COLUMN_NOT_FOUND;
}

CSV_Type::CSV_Err CSV_Table::insert_cell_before(size_t target_column_position, size_t target_cell_position, const char *cell_content_str)
{
    if ((target_column_position + 1) > this->column_count)
        return CSV_Type::CSV_ERROR_ILLEGAL_COLUMN_POSITION;
    decltype(this->Column_List_Head) p_target_column = this->Column_List_Head;
    for (size_t count = 0; count < target_column_position; count++)
        p_target_column = p_target_column->p_next_column;

    if (!(((target_cell_position + 1) <= p_target_column->element_count) || ((target_cell_position == 0) && (p_target_column->element_count == 0))))
        return CSV_Type::CSV_ERROR_ILLEGAL_CELL_POSITION;

    decltype(p_target_column->Cell_List_Head) p_new_cell = (decltype(p_target_column->Cell_List_Head))malloc(sizeof(*(p_target_column->Cell_List_Head)));
    if (p_new_cell == nullptr)
        return CSV_Type::CSV_ERROR_MEM_ALLOCATE_FAILED;
    this->mem_use += sizeof(*p_new_cell);

    if (cell_content_str != nullptr)
    {
        char *p_content = (char *)malloc(strlen(cell_content_str) + 1); // +1 for '\0'
        if (p_content == nullptr)
        {
            free(p_new_cell);
            return CSV_Type::CSV_ERROR_MEM_ALLOCATE_FAILED;
        }

        this->mem_use += strlen(cell_content_str) + 1;
        strcpy(p_content, cell_content_str);
        p_new_cell->content_str = p_content;
    }
    else
        p_new_cell->content_str = nullptr;

    if (p_target_column->element_count == 0)
    {
        p_new_cell->p_next_cell = nullptr;
        p_target_column->Cell_List_Head = p_target_column->Cell_List_End = p_new_cell;
    }
    else
    {
        if (target_cell_position == 0)
        {
            p_new_cell->p_next_cell = p_target_column->Cell_List_Head;
            p_target_column->Cell_List_Head = p_new_cell;
        }
        else
        {

            decltype(p_new_cell) p_pre_target_cell = p_target_column->Cell_List_Head;
            for (size_t count = 0; count < target_cell_position - 1; count++)
                p_pre_target_cell = p_pre_target_cell->p_next_cell;

            p_new_cell->p_next_cell = p_pre_target_cell->p_next_cell;
            p_pre_target_cell->p_next_cell = p_new_cell;
        }
    }

    p_target_column->element_count++;

    if (p_target_column->element_count > this->max_element_depth)
        this->max_element_depth = p_target_column->element_count;

    return CSV_Type::CSV_ERROR_NONE;
}

CSV_Type::CSV_Err CSV_Table::export_to_file(const char *file_name_str)
{
    // 打开文件
    FILE *p_file = fopen(file_name_str, "wb");
    if (p_file == nullptr)
        return CSV_Type::CSV_ERROR_FILE_CREATE_FAILED;

    // 横向元素表
    decltype(this->Column_List_Head->Cell_List_Head) *p_parallel_cell_list = nullptr;

    // 输出内容
    if (this->column_count != 0)
    {
        p_parallel_cell_list = (decltype(this->Column_List_Head->Cell_List_Head) *)malloc(sizeof(*this->Column_List_Head->Cell_List_Head) * this->column_count);
        if (p_parallel_cell_list == nullptr)
            return CSV_Type::CSV_ERROR_MEM_ALLOCATE_FAILED;

        // 输出标题及填充横向列表
        {
            size_t count = 0;
            for (decltype(this->Column_List_Head) p_target_column = this->Column_List_Head; p_target_column != nullptr; p_target_column = p_target_column->p_next_column)
            {
                if (fprintf(p_file, strstr(p_target_column->column_title_str, ",") ? "\"%s\"," : "%s,", p_target_column->column_title_str) < 0)
                    goto file_write_error;
                p_parallel_cell_list[count] = p_target_column->Cell_List_Head;
                count++;
            }
            fseek(p_file, -1, SEEK_CUR);
            if (fprintf(p_file, "\r\n") < 0)
                goto file_write_error;
        }

        // 输出横向行内容
        {
            for (size_t row_count = 0; row_count < this->max_element_depth; row_count++)
            {
                for (size_t column_count = 0; column_count < this->column_count; column_count++)
                {
                    if (p_parallel_cell_list[column_count] != nullptr)
                    {
                        if (fprintf(p_file, strstr(p_parallel_cell_list[column_count]->content_str, ",") ? "\"%s\"," : "%s,", p_parallel_cell_list[column_count]->content_str) < 0)
                            goto file_write_error;
                        p_parallel_cell_list[column_count] = p_parallel_cell_list[column_count]->p_next_cell;
                    }
                    else
                    {
                        if (fprintf(p_file, ",") < 0)
                            goto file_write_error;
                    }
                }
                fseek(p_file, -1, SEEK_CUR);
                if (fprintf(p_file, "\r\n") < 0)
                    goto file_write_error;
            }
        }

        free(p_parallel_cell_list);
    }

    fclose(p_file);
    return CSV_Type::CSV_ERROR_NONE;

// 写入错误处理
file_write_error:
    if (p_parallel_cell_list != nullptr)
        free(p_parallel_cell_list);
    fclose(p_file);
    return CSV_Type::CSV_ERROR_FILE_WRITE_FAILED;
}