#include "deframer.h"
#include "common/simple_deframer.h"
#include "core/style.h"
#include "imgui/imgui_stdlib.h"
#include "logger.h"
#include <fstream>
#include <string>

namespace satdump
{
    std::string DeframerTool::getName() { return "Deframer"; }

    void DeframerTool::renderMenu(std::shared_ptr<BitContainer> &container, bool is_busy)
    {
        if (is_busy)
            style::beginDisabled();

        ImGui::InputText("Syncword", &deframer_syncword);
        ImGui::InputInt("Syncword Size", &deframer_syncword_size);
        ImGui::InputInt("Frame Size (Bits)", &deframer_syncword_framesize);
        ImGui::InputInt("Threshold", &deframer_threshold);
        ImGui::Checkbox("Byte Aligned", &deframer_byte_aligned);
        ImGui::Checkbox("Soft Bits In", &deframer_soft_bits_in);

        if (ImGui::Button("DeframeTest"))
            should_process = true;

        ImGui::Text("Frames : %d", deframer_current_frames);

        if (is_busy)
            style::endDisabled();
    }

    bool DeframerTool::needToProcess() { return should_process; }

    void DeframerTool::setProcessed() { should_process = false; }

    void DeframerTool::process(std::shared_ptr<BitContainer> &container, float &process_progress)
    {
        uint8_t *ptr = container->get_ptr();
        size_t size = container->get_ptr_size();

        char name[1000];
        tmpnam(name);
        std::string tmpfile = name;
        std::ofstream file_out(tmpfile, std::ios::binary);

        char *syncword_endptr;
        uint64_t syncword = strtoull(deframer_syncword.c_str(), &syncword_endptr, 16);
        if (*syncword_endptr != 0)
        {
            logger->error("Cannot parse syncword!");
            return;
        }

        def::SimpleDeframer def_test(syncword, deframer_syncword_size, deframer_syncword_framesize, deframer_threshold, deframer_byte_aligned, deframer_soft_bits_in);
        deframer_current_frames = 0;
        size_t current_ptr = 0;

        while (current_ptr < size)
        {
            size_t csize = std::min<size_t>(8192, size - current_ptr);
            auto vf = def_test.work(ptr + current_ptr, csize);
            current_ptr += csize;

            for (auto &f : vf)
                file_out.write((char *)f.data(), f.size());
            deframer_current_frames += vf.size();

            process_progress = double(current_ptr) / double(size);
        }

        file_out.close();
        std::shared_ptr<satdump::BitContainer> newbitc;

        try
        {
            newbitc = std::make_shared<satdump::BitContainer>("Deframed (" + deframer_syncword + " , " + std::to_string(deframer_syncword_framesize) + ")", tmpfile);
        }
        catch (std::exception &e)
        {
            logger->error("Error loading deframed data: %s", e.what());
            return;
        }

        newbitc->d_bitperiod = deframer_syncword_framesize;
        newbitc->init_display();
        newbitc->d_is_temporary = true;

        if (container->bitview != nullptr)
            ((BitViewHandler *)container->bitview)->addSubHandler(std::make_shared<BitViewHandler>(newbitc));
        else
            logger->error("Can't add container!");
    }
} // namespace satdump