#ifndef ANSICOLOR_H
#define ANSICOLOR_H

#include <cstdint>
#include <string>

#define CSI "\x1b["

/**
 * ANSI Color codes
 */

/**
 * @brief The colors available under ANSI-BBS
 */
enum class COLOR : std::int8_t {
  /// BLACK (0)
  BLACK,
  /// RED (1)
  RED,
  /// GREEN (2)
  GREEN,
  /// BROWN (3)
  BROWN,
  /// YELLOW (3)
  YELLOW = 3,
  /// BLUE (4)
  BLUE,
  /// MAGENTA (5)
  MAGENTA,
  /// CYAN (6)
  CYAN,
  /// WHITE (7)
  WHITE
};

/**
 * @brief ANSI-BBS text attributes
 */
enum class ATTR : std::int8_t {
  /// RESET forces all attributes (and Colors) to be sent.
  RESET,
  /// BOLD is the same as BRIGHT.
  BOLD,
  /// BRIGHT is the same as BOLD.
  BRIGHT = 1,
  /// SLOW BLINK
  BLINK = 5,
  /// INVERSE is Background on Foreground.
  INVERSE = 7
};

/**
 * @class ANSIColor
 * This holds foreground, background and ANSI-BBS attribute
 * information.
 * The special attribute RESET forces attribute and color
 * output always.
 *
 * @brief Foreground, Background and Attributes
 *
 */
class ANSIColor {
  /** Foreground color */
  COLOR fg;
  /** Background color */
  COLOR bg;
  // Track attributes (ATTR)
  /** reset flag / always send color and attributes */
  unsigned int reset : 1;
  /** bold / bright flag */
  unsigned int bold : 1;
  /** blink slow blinking text */
  unsigned int blink : 1;
  /** inverse */
  unsigned int inverse : 1;

public:
  ANSIColor();
  ANSIColor(ATTR a);
  ANSIColor(COLOR f);
  ANSIColor(COLOR f, ATTR a);
  ANSIColor(COLOR f, ATTR a1, ATTR a2);
  ANSIColor(COLOR f, COLOR b);
  ANSIColor(COLOR f, COLOR b, ATTR a);
  ANSIColor(COLOR f, COLOR b, ATTR a1, ATTR a2);
  ANSIColor(std::initializer_list<int> il);
  /*
  ANSIColor(int c1);
  ANSIColor(int c1, int c2);
  */

  ANSIColor &Attr(ATTR a);
  bool operator==(const ANSIColor &c) const;
  bool operator!=(const ANSIColor &c) const;
  void setFg(COLOR f);
  void setFg(COLOR f, ATTR a);
  void setBg(COLOR b);

  /**
   * Get the foreground color
   * @return COLOR
   */
  COLOR getFg() { return fg; };
  /**
   * Get the background color
   * @return COLOR
   */
  COLOR getBg() { return bg; };
  void attr(ATTR a);

  std::string output(void) const;
  std::string operator()(void) const;
};

extern ANSIColor reset;

#endif