#include <fmt/core.h>
#include <string_view>
#include <charconv>
#include "dbc.hpp"

using namespace fmt;

%%{
  machine ansi_parser;

  action tstart {
    start = fpc;
  }

  action number {
    auto [ptr, ec] = std::from_chars(start, fpc, value);
    dbc::check(ec == std::errc(), "error in number parsing");
    println("NUM: {}", value);
  }

  action color256 {
    println("COLOR256");
  }

  action color24b {
    println("COLOR24B");
  }

  action colorSingle {
    println("SINGLE");
  }

  action colorBasic {
    println("BASIC");
  }

  action bg {
    println("BG");
  }

  action fg {
    println("FG");
  }

  action any {
    println("ANY: {}:{}", int(fc), fc);
  }

  action start {
    println("START");
  }

  action end {
    println("END");
  }

  ESC = 0x1B;
  start = ESC "[";
  fg = "38;" %fg;
  bg = "48;" %bg;
  color256 = "5;" %color256;
  color24b = "2;" %color24b;
  num = (digit+) >tstart %number;

  ansi := |*
      start => start;
      (fg|bg) color256 num ";" num => { println("256 doit"); };
      (fg|bg) color24b num ";" num ";" num => { println("24b doit"); };
      num ";" num => colorBasic;
      num => colorSingle;
      "m" => { fgoto main; };
  *|;

  main := (any @any -- ESC)* ESC @{ fhold; fgoto ansi; };

}%%

%% write data;

bool parse_ansi(std::string_view codes) {
  const char *start = NULL;
  int cs = 0;
  size_t value = 0;
  const char *p = codes.data();
  const char *pe = p + codes.size();
  const char *eof = pe;
  const char *ts = p;
  const char *te = p;
  int act = 0;

  %% write init;
  %% write exec;

  print("PROCESSED {} CHARS of {}", p - codes.data(), codes.size());

  return true;
}