#include "io.h"
#include "core/config.h"
#include "logger.h"
#include <fstream>
#include <string>

namespace satdump
{
    namespace image
    {
        void load_img(Image &img, std::string file)
        {
            if (!std::filesystem::exists(file))
                logger->error("File " + file + " does not exist!");

            std::ifstream file_sigature_src(file, std::ios::binary);
            uint8_t signature[10];
            file_sigature_src.read((char *)signature, 10);
            if (signature[0] == 0xFF && signature[1] == 0xD8)
                load_jpeg(img, file);
            else if (signature[0] == 0x89 && signature[1] == 0x50 && signature[2] == 0x4E && signature[3] == 0x47)
                load_png(img, file);
            else if (signature[0] == 0xff && signature[1] == 0x4f && signature[2] == 0xff && signature[3] == 0x51)
                load_j2k(img, file);
            else if (signature[0] == 'P' && (signature[1] == '5' || signature[1] == '6'))
                load_pbm(img, file);
            else if (signature[0] == 'I' && signature[1] == 'I' && signature[2] == '*')
                load_tiff(img, file);
            else if (signature[0] == 'q' && signature[1] == 'o' && signature[2] == 'i' && signature[3] == 'f')
                load_qoi(img, file);
        }

        void load_img(Image &img, uint8_t *buffer, int size)
        {
            if (buffer[0] == 0xFF && buffer[1] == 0xD8)
                load_jpeg(img, buffer, size);
            else if (buffer[0] == 0x89 && buffer[1] == 0x50 && buffer[2] == 0x4E && buffer[3] == 0x47)
                load_png(img, buffer, size);
        }

        void save_img(Image &img, std::string file, bool fast)
        {
            if (!append_ext(&file))
                return;
            logger->info("Saving " + file + "...");
            if (file.find(".png") != std::string::npos)
                save_png(img, file, fast);
            else if (file.find(".jpeg") != std::string::npos || file.find(".jpg") != std::string::npos)
                save_jpeg(img, file);
            else if (file.find(".j2k") != std::string::npos)
                save_j2k(img, file);
            else if ((file.find(".ppm") != std::string::npos) || (file.find(".pgm") != std::string::npos) || (file.find(".pbm") != std::string::npos))
                save_pbm(img, file);
            else if ((file.find(".tif") != std::string::npos) || (file.find(".gtif") != std::string::npos) || (file.find(".tiff") != std::string::npos))
                save_tiff(img, file);
            else if (file.find(".qoi") != std::string::npos)
                save_qoi(img, file);
        }

        void save_img_safe(Image &img, std::string file, bool fast)
        {
            int id = 1;
        recheck:
            std::string file2 = file + (id > 1 ? ("_" + std::to_string(id)) : "");
            std::string name2 = file2;
            if (!image::append_ext(&name2))
                return;
            if (std::filesystem::exists(name2))
            {
                id++;
                goto recheck;
            }
            image::save_img(img, file2, fast);
        }

        // Append selected file extension
        bool append_ext(std::string *file, bool prod)
        {
            // Do nothing if there's already an extension
            if (file->find(".png") != std::string::npos || file->find(".jpeg") != std::string::npos || file->find(".jpg") != std::string::npos || file->find(".j2k") != std::string::npos ||
                file->find(".pgm") != std::string::npos || file->find(".pbm") != std::string::npos || file->find(".ppm") != std::string::npos || file->find(".tif") != std::string::npos ||
                file->find(".tiff") != std::string::npos || file->find(".gtif") != std::string::npos || file->find(".qoi") != std::string::npos)
                return true;

            // Otherwise, load the user setting
            std::string image_format;
            try
            {
                if (prod)
                    image_format = satdump_cfg.getValueFromSatDumpGeneral<std::string>("product_format");
                else
                    image_format = satdump_cfg.getValueFromSatDumpGeneral<std::string>("image_format");
            }
            catch (std::exception &e)
            {
                logger->error("Image format not specified, and default format cannot be found! %s", e.what());
                return false;
            }

            if (image_format != "png" && image_format != "jpg" && image_format != "j2k" && image_format != "pbm" && image_format != "tif" && image_format != "qoi")
            {
                logger->error("Image format not specified, and default format is invalid!");
                return false;
            }

            *file += "." + image_format;
            return true;
        }
    } // namespace image
} // namespace satdump