/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file LICENSE.rst or https://cmake.org/licensing for details.  */
#include "cmConfigureLog.h"

#include <cassert>
#include <cstdio>
#include <iterator>
#include <sstream>
#include <utility>

#include <cmext/algorithm>
#include <cmext/string_view>

#include <cm3p/json/writer.h>

#include "cm_utf8.h"

#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmRange.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
#include "cmake.h"

cmConfigureLog::cmConfigureLog(std::string logDir,
                               std::vector<unsigned int> logVersions)
  : LogDir(std::move(logDir))
  , LogVersions(std::move(logVersions))
{
  // Always emit events for the latest log version.
  static unsigned int const LatestLogVersion = 1;
  if (!cm::contains(this->LogVersions, LatestLogVersion)) {
    this->LogVersions.emplace_back(LatestLogVersion);
  }

  Json::StreamWriterBuilder builder;
  this->Encoder.reset(builder.newStreamWriter());
}

cmConfigureLog::~cmConfigureLog()
{
  if (this->Opened) {
    this->EndObject();
    this->Stream << "...\n";
  }
}

bool cmConfigureLog::IsAnyLogVersionEnabled(
  std::vector<unsigned int> const& v) const
{
  // Both input lists are sorted.  Look for a matching element.
  auto i1 = v.cbegin();
  auto i2 = this->LogVersions.cbegin();
  while (i1 != v.cend() && i2 != this->LogVersions.cend()) {
    if (*i1 < *i2) {
      ++i1;
    } else if (*i2 < *i1) {
      ++i2;
    } else {
      return true;
    }
  }
  return false;
}

void cmConfigureLog::WriteBacktrace(cmMakefile const& mf)
{
  std::vector<std::string> backtrace;
  auto root = mf.GetCMakeInstance()->GetHomeDirectory();
  for (auto bt = mf.GetBacktrace(); !bt.Empty(); bt = bt.Pop()) {
    auto t = bt.Top();
    if (!t.Name.empty() || t.Line == cmListFileContext::DeferPlaceholderLine) {
      t.FilePath = cmSystemTools::RelativeIfUnder(root, t.FilePath);
      std::ostringstream s;
      s << t;
      backtrace.emplace_back(s.str());
    }
  }
  this->WriteValue("backtrace"_s, backtrace);
}

void cmConfigureLog::WriteChecks(cmMakefile const& mf)
{
  if (!mf.GetCMakeInstance()->HasCheckInProgress()) {
    return;
  }
  this->BeginObject("checks"_s);
  for (auto const& value :
       cmReverseRange(mf.GetCMakeInstance()->GetCheckInProgressMessages())) {
    this->BeginLine() << "- ";
    this->Encoder->write(value, &this->Stream);
    this->EndLine();
  }
  this->EndObject();
}

void cmConfigureLog::EnsureInit()
{
  if (this->Opened) {
    return;
  }
  assert(!this->Stream.is_open());

  std::string name = cmStrCat(this->LogDir, "/CMakeConfigureLog.yaml");
  this->Stream.open(name.c_str(), std::ios::out | std::ios::app);

  this->Opened = true;

  this->Stream << "\n---\n";
  this->BeginObject("events"_s);
}

cmsys::ofstream& cmConfigureLog::BeginLine()
{
  for (unsigned i = 0; i < this->Indent; ++i) {
    this->Stream << "  ";
  }
  return this->Stream;
}

void cmConfigureLog::EndLine()
{
  this->Stream << std::endl;
}

void cmConfigureLog::BeginArray()
{
  ++this->Indent;
}

void cmConfigureLog::NextArrayElement()
{
  assert(this->Indent);
  --this->Indent;
  this->BeginLine() << '-';
  this->EndLine();
  ++this->Indent;
}

void cmConfigureLog::EndArray()
{
  assert(this->Indent);
  --this->Indent;
}

void cmConfigureLog::BeginObject(cm::string_view key)
{
  this->BeginLine() << key << ':';
  this->EndLine();
  ++this->Indent;
}

void cmConfigureLog::EndObject()
{
  assert(this->Indent);
  --this->Indent;
}

void cmConfigureLog::BeginEvent(std::string const& kind, cmMakefile const& mf)
{
  this->EnsureInit();

  this->BeginLine() << '-';
  this->EndLine();

  ++this->Indent;

  this->WriteValue("kind"_s, kind);
  this->WriteBacktrace(mf);
  this->WriteChecks(mf);
}

void cmConfigureLog::EndEvent()
{
  assert(this->Indent);
  --this->Indent;
}

void cmConfigureLog::WriteValue(cm::string_view key, std::nullptr_t)
{
  this->BeginLine() << key << ": null";
  this->EndLine();
}

void cmConfigureLog::WriteValue(cm::string_view key, bool value)
{
  this->BeginLine() << key << ": " << (value ? "true" : "false");
  this->EndLine();
}

void cmConfigureLog::WriteValue(cm::string_view key, int value)
{
  this->BeginLine() << key << ": " << value;
  this->EndLine();
}

void cmConfigureLog::WriteValue(cm::string_view key, std::string const& value)
{
  this->BeginLine() << key << ": ";
  this->Encoder->write(value, &this->Stream);
  this->EndLine();
}

void cmConfigureLog::WriteValue(cm::string_view key,
                                std::vector<std::string> const& list)
{
  this->BeginObject(key);
  for (auto const& value : list) {
    this->BeginLine() << "- ";
    this->Encoder->write(value, &this->Stream);
    this->EndLine();
  }
  this->EndObject();
}

void cmConfigureLog::WriteValue(cm::string_view key,
                                std::map<std::string, std::string> const& map)
{
  static std::string const rawKeyChars = //
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"         //
    "abcdefghijklmnopqrstuvwxyz"         //
    "0123456789"                         //
    "-_"                                 //
    ;
  this->BeginObject(key);
  for (auto const& entry : map) {
    if (entry.first.find_first_not_of(rawKeyChars) == std::string::npos) {
      this->WriteValue(entry.first, entry.second);
    } else {
      this->BeginLine();
      this->Encoder->write(entry.first, &this->Stream);
      this->Stream << ": ";
      this->Encoder->write(entry.second, &this->Stream);
      this->EndLine();
    }
  }
  this->EndObject();
}

void cmConfigureLog::WriteLiteralTextBlock(cm::string_view key,
                                           cm::string_view text)
{
  this->BeginLine() << key << ": |";
  this->EndLine();

  auto const l = text.length();
  if (l) {
    ++this->Indent;
    this->BeginLine();

    auto i = decltype(l){ 0 };
    while (i < l) {
      // YAML allows ' ', '\t' and "printable characters", but NOT other
      // ASCII whitespace; those must be escaped, as must the upper UNICODE
      // control characters (U+0080 - U+009F)
      static constexpr unsigned int C1_LAST = 0x9F;
      auto const c = static_cast<unsigned char>(text[i]);
      switch (c) {
        case '\r':
          // Print a carriage return only if it is not followed by a line feed.
          ++i;
          if (i == l || text[i] != '\n') {
            this->WriteEscape(c);
          }
          break;
        case '\n':
          // Print any line feeds except the very last one
          if (i + 1 < l) {
            this->EndLine();
            this->BeginLine();
          }
          ++i;
          break;
        case '\t':
          // Print horizontal tab verbatim
          this->Stream.put('\t');
          ++i;
          break;
        case '\\':
          // Escape backslash for disambiguation
          this->Stream << "\\\\";
          ++i;
          break;
        default:
          if (c >= 32 && c < 127) {
            // Print ascii byte.
            this->Stream.put(text[i]);
            ++i;
            break;
          } else if (c > 127) {
            // Decode a UTF-8 sequence.
            unsigned int c32;
            auto const* const s = text.data() + i;
            auto const* const e = text.data() + l;
            auto const* const n = cm_utf8_decode_character(s, e, &c32);
            if (n > s && c32 > C1_LAST) {
              auto const k = std::distance(s, n);
              this->Stream.write(s, static_cast<std::streamsize>(k));
              i += static_cast<unsigned>(k);
              break;
            }
          }

          // Escape non-printable byte.
          this->WriteEscape(c);
          ++i;
          break;
      }
    }

    this->EndLine();
    --this->Indent;
  }
}

void cmConfigureLog::WriteEscape(unsigned char c)
{
  char buffer[6];
  int n = snprintf(buffer, sizeof(buffer), "\\x%02x", c);
  if (n > 0) {
    this->Stream.write(buffer, n);
  }
}
