/*******************************************************************************
 *
 * File:     terminal_colors.cpp
 *
 * Contents: Facility for printing colorized text to terminals supporting it.
 *
 * Copyright 2017
 *
 * Author: David Juhasz (david.juhasz@tuwien.ac.at)
 *
 ******************************************************************************/

#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 std::array for runtime efficiency, though static casting is
// necessary for indexing.
// NOTE: Do not index with 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)
  // FIXME: Windows terminals support ANSI color codes from Windows 10
  // Threshold 2, custom stuff is required for earlier versions.
#endif // defined(ROSA_POSIX) || defined(ROSA_WINDOWS)
  return os;
}

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

