#include "biboumi.h"

#ifdef BOTAN_FOUND

#include <fstream>

#include <utils/tolower.hpp>

#include <network/tls_policy.hpp>
#include <logger/logger.hpp>
#include <botan/exceptn.h>

bool BiboumiTLSPolicy::load(const std::string& filename)
{
  std::ifstream is(filename.data());
  if (is)
    {
      try {
          this->load(is);
          log_info("Successfully loaded policy file: ", filename);
          return true;
        } catch (const Botan::Exception& e) {
          log_error("Failed to parse policy_file ", filename, ": ", e.what());
          return false;
        }
    }
  log_info("Could not open policy file: ", filename);
  return false;
}

void BiboumiTLSPolicy::load(std::istream& is)
{
  const auto dict = BiboumiTLSPolicy::read_cfg(is);
  for (const auto& pair: dict)
    {
      // Workaround for options that are not overridden in Botan::TLS::Text_Policy
      if (pair.first == "require_cert_revocation_info")
        this->req_cert_revocation_info = !(pair.second == "0" || utils::tolower(pair.second) == "false");
      else if (pair.first == "verify_certificate")
        this->verify_certificate = !(pair.second == "0" || utils::tolower(pair.second) == "false");
      else
        this->set(pair.first, pair.second);
    }
}

bool BiboumiTLSPolicy::require_cert_revocation_info() const
{
  return this->req_cert_revocation_info;
}

std::map<std::string, std::string> BiboumiTLSPolicy::read_cfg(std::istream& is) {
   std::map<std::string, std::string> kv;
   size_t line = 0;

   while(is.good()) {
      std::string s;

      std::getline(is, s);

      ++line;

      if(s.empty() || s[0] == '#') {
         continue;
      }

      s = clean_ws(s.substr(0, s.find('#')));

      if(s.empty()) {
         continue;
      }

      auto eq = s.find('=');

      if(eq == std::string::npos || eq == 0 || eq == s.size() - 1) {
         throw Botan::Decoding_Error("Bad read_cfg input '" + s + "' on line " + std::to_string(line));
      }

      const std::string key = BiboumiTLSPolicy::clean_ws(s.substr(0, eq));
      const std::string val = BiboumiTLSPolicy::clean_ws(s.substr(eq + 1, std::string::npos));

      kv[key] = val;
   }

   return kv;
}

std::string BiboumiTLSPolicy::clean_ws(std::string_view s) {
   const char* ws = " \t\n";
   auto start = s.find_first_not_of(ws);
   auto end = s.find_last_not_of(ws);

   if(start == std::string::npos) {
      return "";
   }

   if(end == std::string::npos) {
      return std::string(s.substr(start, end));
   } else {
      return std::string(s.substr(start, start + end + 1));
   }
}

#endif
