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

#include <iostream>

#include <cm/memory>

#include "cmGeneratedFileStream.h"
#include "cmSystemTools.h"

cmCPackLog::cmCPackLog()
{
  DefaultOutput = &std::cout;
  DefaultError = &std::cerr;
}

cmCPackLog::~cmCPackLog() = default;

void cmCPackLog::SetLogOutputStream(std::ostream* os)
{
  LogOutputStream.reset();
  LogOutput = os;
}

bool cmCPackLog::SetLogOutputFile(const char* fname)
{
  LogOutputStream.reset();
  if (fname) {
    LogOutputStream = cm::make_unique<cmGeneratedFileStream>(fname);
  }
  if (LogOutputStream && !*LogOutputStream) {
    LogOutputStream.reset();
  }

  LogOutput = LogOutputStream.get();

  return LogOutput != nullptr;
}

void cmCPackLog::Log(int tag, const char* file, int line, const char* msg,
                     size_t length)
{
  // By default no logging
  bool display = false;

  // Display file and line number if debug
  bool useFileAndLine = Debug;

  bool output = false;
  bool debug = false;
  bool warning = false;
  bool error = false;
  bool verbose = false;

  // When writing in file, add list of tags whenever tag changes.
  std::string tagString;
  bool needTagString = false;
  if (LogOutput && LastTag != tag) {
    needTagString = true;
  }

  if (tag & LOG_OUTPUT) {
    output = true;
    display = true;
    if (needTagString) {
      if (!tagString.empty()) {
        tagString += ",";
      }
      tagString += "VERBOSE";
    }
  }
  if (tag & LOG_WARNING) {
    warning = true;
    display = true;
    if (needTagString) {
      if (!tagString.empty()) {
        tagString += ",";
      }
      tagString += "WARNING";
    }
  }
  if (tag & LOG_ERROR) {
    error = true;
    display = true;
    if (needTagString) {
      if (!tagString.empty()) {
        tagString += ",";
      }
      tagString += "ERROR";
    }
  }
  if (tag & LOG_DEBUG && Debug) {
    debug = true;
    display = true;
    if (needTagString) {
      if (!tagString.empty()) {
        tagString += ",";
      }
      tagString += "DEBUG";
    }
    useFileAndLine = true;
  }
  if (tag & LOG_VERBOSE && Verbose) {
    verbose = true;
    display = true;
    if (needTagString) {
      if (!tagString.empty()) {
        tagString += ",";
      }
      tagString += "VERBOSE";
    }
  }
  if (Quiet) {
    display = false;
  }
  if (LogOutput) {
    if (needTagString) {
      *LogOutput << "[" << file << ":" << line << " " << tagString << "] ";
    }
    LogOutput->write(msg, length);
  }
  LastTag = tag;
  if (!display) {
    return;
  }
  if (NewLine) {
    if (error && !ErrorPrefix.empty()) {
      *DefaultError << ErrorPrefix;
    } else if (warning && !WarningPrefix.empty()) {
      *DefaultError << WarningPrefix;
    } else if (output && !OutputPrefix.empty()) {
      *DefaultOutput << OutputPrefix;
    } else if (verbose && !VerbosePrefix.empty()) {
      *DefaultOutput << VerbosePrefix;
    } else if (debug && !DebugPrefix.empty()) {
      *DefaultOutput << DebugPrefix;
    } else if (!Prefix.empty()) {
      *DefaultOutput << Prefix;
    }
    if (useFileAndLine) {
      if (error || warning) {
        *DefaultError << file << ":" << line << " ";
      } else {
        *DefaultOutput << file << ":" << line << " ";
      }
    }
  }
  if (error || warning) {
    DefaultError->write(msg, length);
    DefaultError->flush();
  } else {
    DefaultOutput->write(msg, length);
    DefaultOutput->flush();
  }
  if (msg[length - 1] == '\n' || length > 2) {
    NewLine = true;
  }

  if (error) {
    cmSystemTools::SetErrorOccured();
  }
}
