#include <cstdlib>
#include <iostream>
#include <sstream>
#include <fstream>
#include "error.h"
#include "util.h"
#include "katom.h"
#include "kutil.h"
#include "show.h"

#include <filesystem>

std::string read_file(const std::string& filename)
{
  std::ifstream stream {};
  std::ostringstream buffer {};
  stream.open(filename);
  if (stream.is_open()) {
    stream >> buffer.rdbuf();
  } else {
    std::cout << "File not opened\n";
  }
  return buffer.str();
}


std::string klammertext_dir()
{
  std::string khome { "KLAMMERTEXT_HOME" };
  char* kdir = getenv(khome.c_str());
  if (kdir == nullptr) {
    std::stringstream ss {};
    ss << "The environment variable " << q_(khome) << " is not defined";
    throw Environment_error(ss.str());
  }
  return kdir;
}

bool in_subset(const std::string& base, const std::vector<std::string>& subset)
{
    return subset.empty() ||
        (std::find(subset.begin(), subset.end(), base) != subset.end());
}

    

std::vector<std::string> sks_files_of_type(const std::string& extension, const std::vector<std::string>& subset)
{
    bool dbg = false;
    std::string kdir = klammertext_dir();
    std::vector<std::string> result {};
    if (dbg) msg() << "Extension: " << extension << "\n";
    for (auto base : sks_basenames) {
        std::string ext_dir { kdir + "/sks/" + base + "/" + extension };
        if (file_exists(ext_dir)) {
            std::string list_filename { ext_dir + "/list.txt" };
            if (file_exists(list_filename)) {
                if (dbg) msg() << "  List: " << list_filename << "\n";
                std::string list = string_from_file(list_filename);
                for (auto s : regex_split(list, std::regex(R"(\n+)"), true)) { // split_lines(list)) {
                    if (s[0] == '#')
                        continue;
                    std::string ext_filename = { ext_dir + "/" + s };
                    if (!file_exists(ext_filename)) {
                        std::string msg = "File " + ext_filename + " in " + list_filename + " does not exist";
                        throw Internal_error(msg);
                    }
                    if (in_subset(fs::path(s).stem(), subset)) {
                        if (dbg) msg() << "    Add: " << ext_filename << "\n";
                        result.push_back(ext_filename);
                    }
                }
            } else {
                for (auto f : get_files_in_directory(ext_dir)) {
                    if (f[f.size()-1] != '~') {
                        if (in_subset(fs::path(f).stem(), subset)) {
                            result.push_back(ext_dir + "/" + f);
                            if (dbg) msg() << "    Add: " << f << "\n";
                        }
                    }
                }
            }
        }
    }
    return result;
}

std::string find_kt_file(const std::string& filename)
{
    std::string result {};
    std::vector<std::string> prefix {"", "kt/"};
    std::vector<std::string> suffix {"", ".kt"};
    std::vector<std::string> all_possible {};
    for (auto p : prefix) {
        for (auto s : suffix) {
            std::string possible { p + filename + s };
            //std::cout << "Checking: " << possible << "\n";
            if (file_exists(possible, false)) {
                result = possible;
                all_possible.push_back(possible);
                break;
            }
        }
        if (result.size() > 0) {
            break;
        }
    }
    if (result.size() == 0) {
        std::cout << "Filename \"" << filename << "\" does not exist and\ndoes not match any of the default patterns:\n";
        for (std::string f : all_possible) {
            std::cout << "   " << f << "\n";
        }
        exit(1);
    }
    //std::cout << "   Found: " << result << "\n";
    return result;
}


std::string caption_marker(const std::string& name, const std::string& caption, const std::string& delimiter)
{
    std::string result {caption};
    if (caption.size() > 0) {
        result = delimiter + caption;
    }
    result = caption_delimiter + name + caption_delimiter + result + caption_delimiter;
    return result;
}

/*
std::string process(Machine& M, const std::string& target, const fs::path& source_filename,
                    bool post_process, bool unescape_chars)
{
    // Text text(source_filename, false, false);
    Source source;
    source.read(source_filename
    text.parse();
    M.preserve_parse(text);
    M.extract_definitions(text);
    M.apply(target, text);
    std::string processed = M.to_string(target, text, post_process, unescape_chars);
    //processed = modify_whitespace_string(processed);
    //M.restore_parse(text);
    return processed;
}

std::string process(Machine& M, const std::string& target, const std::string& source_text,
                    bool post_process, bool unescape_chars)
{
    Text text(source_text, false, false);
    text.parse();
    M.preserve_parse(text);
    M.extract_definitions(text);
    M.apply(target, text);
    std::string processed = M.to_string(target, text, post_process, unescape_chars);
    //M.restore_parse(text);
    return processed;
}

std::string process(Machine& M, const std::string& target,
                    const std::string& source_text, const fs::path& source_filename,
                    bool post_process, bool unescape_chars)
{
    Text text({source_text}, {source_filename}, false, false);
    text.parse();
    M.preserve_parse(text);
    M.extract_definitions(text);
    M.apply(target, text);
    std::string processed = M.to_string(target, text, post_process, unescape_chars);
    //M.restore_parse(text);
    return processed;
}
*/
