#include "iq_types.h"
#include "core/exception.h"
#include "imgui/imgui.h"
#include <map>
#include <vector>

// // Needed to properly use IQType as the key in std::map
// #if defined(BUILD_ZIQ) || defined(BUILD_ZIQ2)
// namespace std
// {
//     template <>
//     struct less<satdump::ndsp::IQType>
//     {
//         bool operator()(const satdump::ndsp::IQType &lhs, const satdump::ndsp::IQType &rhs) const { return lhs.type + lhs.ziq_depth < rhs.type + rhs.ziq_depth; }
//     };
// } // namespace std
// #endif

namespace satdump
{
    namespace ndsp
    {
        // Helper function
        static std::map<IQType, size_t> reverse_lut(const std::vector<IQType> lut)
        {
            std::map<IQType, size_t> ret;
            for (size_t i = 0; i < lut.size(); i++)
                ret[lut[i]] = i;
            return ret;
        }

        static const std::vector<IQType> play_fwd_lut = {
            CF32, CS32, CS16, CS8, CU8,
            // #ifdef BUILD_ZIQ
            //                                                                ZIQ,
            // #endif
            // #ifdef BUILD_ZIQ2
            //                                                                ZIQ2
            // #endif
        };

        static const std::vector<IQType> record_fwd_lut = {
            CF32, CS32, CS16, CS8, WAV16,
            // #ifdef BUILD_ZIQ
            //                                                                  {ZIQ, 32},  {ZIQ, 16}, {ZIQ, 8},
            // #endif
            // #ifdef BUILD_ZIQ2
            //                                                                  {ZIQ2, 16}, {ZIQ2, 8}
            // #endif
        };

        static const std::map<IQType, size_t> record_rev_lut = reverse_lut(record_fwd_lut);
        static const std::map<IQType, size_t> play_rev_lut = reverse_lut(play_fwd_lut);

        IQType::operator std::string() const
        {
            switch (type)
            {
            case CF32:
                return "cf32";
                break;
            case CS32:
                return "cs32";
                break;
            case CS16:
                return "cs16";
                break;
            case CS8:
                return "cs8";
                break;
            case CU8:
                return "cu8";
                break;
            case WAV16:
                return "wav16";
                break;
                // #ifdef BUILD_ZIQ
                //             case ZIQ:
                //                 return "ziq";
                //                 break;
                // #endif
                // #ifdef BUILD_ZIQ2
                //             case ZIQ2:
                //                 return "ziq2";
                //                 break;
                // #endif
            default:
                throw satdump_exception("Invalid baseband type!");
            };
        }

        void IQType::from_string(const std::string &s)
        {
            if (s == "cs32" || s == "s32")
                type = CS32;
            else if (s == "cs16" || s == "s16")
                type = CS16;
            else if (s == "cs8" || s == "s8")
                type = CS8;
            else if (s == "cf32" || s == "f32")
                type = CF32;
            else if (s == "cu8" || s == "u8")
                type = CU8;
            else if (s == "wav16")
                type = WAV16;
            // #ifdef BUILD_ZIQ
            //             else if (s == "ziq")
            //                 type = ZIQ;
            // #endif
            // #ifdef BUILD_ZIQ2
            //             else if (s == "ziq2")
            //                 type = ZIQ2;
            // #endif
            else
                throw satdump_exception("Unknown baseband type " + s);
        }

        bool IQType::draw_combo(const char *label)
        {
            int selected = play_rev_lut.at(*this);
            bool ret = ImGui::Combo(label, &selected,
                                    "cf32\0"
                                    "cs32\0"
                                    "cs16\0"
                                    "cs8\0"
                                    "cu8\0"
                                    "w16\0"
                                    // #ifdef BUILD_ZIQ
                                    //                                     "ziq\0"
                                    // #endif
                                    // #ifdef BUILD_ZIQ2
                                    //                                     "ziq2\0"
                                    // #endif
                                    "\0");

            if (ret)
                *this = play_fwd_lut[selected];

            return ret;
        }
    } // namespace ndsp
} // namespace satdump