//===-- support/terminal_colors.cpp -----------------------------*- C++ -*-===//
//
//                                 The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file support/terminal_colors.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Implementation for rosa/support/terminal_colors.h.
///
//===----------------------------------------------------------------------===//

#include "rosa/support/terminal_colors.h"

#include "rosa/config/config.h"

#include "rosa/support/debug.hpp"

#include <array>

#ifdef ROSA_POSIX
#include <unistd.h>
#endif // defined(ROSA_POSIX)

namespace rosa {
namespace terminal {

/// ANSI color codes for POSIX terminals.
///
/// \note Use \c std::array for runtime efficiency, though static casting is
/// necessary for indexing.
///
/// \note Do not index with \c rosa::Color::NumColors!
constexpr std::array<const char *, static_cast<size_t>(Color::NumColors)>
    ANSIColorCodes{{
        "0",  ///< Default - Attribute reset
        "30", ///< Black
        "31", ///< Red
        "32", ///< Green
        "33", ///< Yelow
        "34", ///< Blue
        "35", ///< Magenta
        "36", ///< Cyan
        "37", ///< Lightgrey
        "90", ///< Darkgrey
        "91", ///< Lightred
        "92", ///< Lightgreen
        "93", ///< Lightyellow
        "94", ///< Lightblue
        "95", ///< Lightmagenta
        "96", ///< Lightcyan
        "97"  ///< White
    }};

std::ostream &operator<<(std::ostream &os, const Color color) {
  ASSERT(color != Color::NumColors);
// Handle color only when printing to terminal and it supports colors.
#ifdef ROSA_POSIX
  // Identify terminal by checking if the stream is buffered as one of the
  // standard outputs, and the corresponding C standard output stream is
  // pointing to a terminal.
  //
  // \note This implementation may be tricked so that it does not print color
  // to terminal, but should never print color codes to a non-terminal output.
  if ((os.rdbuf() == std::cout.rdbuf() && isatty(fileno(stdin))) ||
      ((os.rdbuf() == std::cerr.rdbuf() || os.rdbuf() == std::clog.rdbuf()) &&
       isatty(fileno(stderr)))) {
    os << "\033[" << ANSIColorCodes[static_cast<size_t>(color)] << "m";
  }
#elif defined(ROSA_WINDOWS)
  // \todo Windows terminals support ANSI color codes from Windows 10
  // Threshold 2, custom stuff is required for earlier versions.
  (void)ANSIColorCodes; // To shut up compiler warning.
#endif // defined(ROSA_POSIX) || defined(ROSA_WINDOWS)
  return os;
}

} // End namespace terminal
} // End namespace rosa
