#include "linuxcnc_tool_adapter.hh"

#include <array>

#include "tooldata.hh"

namespace {

std::array<CANON_TOOL_TABLE, CANON_POCKETS_MAX> &tool_table()
{
    static std::array<CANON_TOOL_TABLE, CANON_POCKETS_MAX> tools{};
    return tools;
}

int &selected_tool_index_ref()
{
    static int index = -1;
    return index;
}

int &current_tool_index_ref()
{
    static int index = 0;
    return index;
}

int &last_tool_index_ref()
{
    static int index = 0;
    return index;
}

CANON_TOOL_TABLE empty_tool()
{
    CANON_TOOL_TABLE tool{};
    tool.toolno = 0;
    tool.pocketno = 0;
    return tool;
}

CANON_TOOL_TABLE linuxcnc_empty_tool()
{
    CANON_TOOL_TABLE tool{};
    tool.toolno = -1;
    tool.pocketno = -1;
    tool.diameter = 0;
    tool.frontangle = 0;
    tool.backangle = 0;
    tool.orientation = 0;
    ZERO_EMC_POSE(tool.offset);
    tool.comment[0] = 0;
    return tool;
}

}  // namespace

namespace standalone {

void reset_tool_adapter()
{
    selected_tool_index_ref() = -1;
    current_tool_index_ref() = 0;
    auto &tools = tool_table();
    for (int index = 0; index < CANON_POCKETS_MAX; ++index) {
        tools[index] = empty_tool();
        tools[index].pocketno = index;
    }
    tools[0].pocketno = 0;
}

void set_tool_entry(int index, const CANON_TOOL_TABLE &tool)
{
    if ((index < 0) || (index >= CANON_POCKETS_MAX)) {
        return;
    }
    tool_table()[index] = tool;
}

CANON_TOOL_TABLE tool_entry_init()
{
    return empty_tool();
}

int find_tool_index_for_tool(int toolno)
{
    if (toolno == 0) {
        return 0;
    }

    const auto &tools = tool_table();
    for (int index = 1; index < CANON_POCKETS_MAX; ++index) {
        if (tools[index].toolno == toolno) {
            return index;
        }
    }
    if (tools[0].toolno == toolno) {
        return 0;
    }
    return -1;
}

int get_tool_entry(CANON_TOOL_TABLE *tool, int index)
{
    if ((tool == nullptr) || (index < 0) || (index >= CANON_POCKETS_MAX)) {
        return -1;
    }
    *tool = tool_table()[index];
    return 0;
}

int current_tool_index()
{
    return current_tool_index_ref();
}

int selected_tool_index()
{
    return selected_tool_index_ref();
}

void select_tool(int toolno)
{
    selected_tool_index_ref() = find_tool_index_for_tool(toolno);
}

void change_tool_number(int index)
{
    if ((index < 0) || (index >= CANON_POCKETS_MAX)) {
        return;
    }

    auto &tools = tool_table();
    CANON_TOOL_TABLE spindle_tool = tools[index];
    spindle_tool.pocketno = 0;
    tools[0] = spindle_tool;
    current_tool_index_ref() = index;
}

void change_selected_tool()
{
    change_tool_number(selected_tool_index_ref());
}

}  // namespace standalone

extern "C" {

toolidx_t tooldata_put(CANON_TOOL_TABLE tdata, int idx)
{
    if ((idx < 0) || (idx >= CANON_POCKETS_MAX)) {
        return IDX_FAIL;
    }

    auto &tools = tool_table();
    const bool is_new = tools[idx].toolno == -1;
    tools[idx] = tdata;
    if (idx > last_tool_index_ref()) {
        last_tool_index_ref() = idx;
    }
    return is_new ? IDX_NEW : IDX_OK;
}

toolidx_t tooldata_get(CANON_TOOL_TABLE *pdata, int idx)
{
    if ((pdata == nullptr) || (idx < 0) || (idx >= CANON_POCKETS_MAX)) {
        return IDX_FAIL;
    }

    *pdata = tool_table()[idx];
    return IDX_OK;
}

void tooldata_reset(void)
{
    auto &tools = tool_table();
    for (int idx = 0; idx < CANON_POCKETS_MAX; ++idx) {
        tools[idx] = linuxcnc_empty_tool();
    }
    selected_tool_index_ref() = -1;
    current_tool_index_ref() = 0;
    last_tool_index_ref() = 0;
}

void tooldata_last_index_set(int idx)
{
    last_tool_index_ref() = idx;
}

int tooldata_last_index_get(void)
{
    return last_tool_index_ref();
}

int tooldata_find_index_for_tool(int toolno)
{
    return standalone::find_tool_index_for_tool(toolno);
}

int tooldata_db_getall(void)
{
    return -1;
}

}  // extern "C"
