#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define lenof(x) (sizeof((x)) / sizeof(*(x)))

#define MAX_LINE_LEN 256
#define MAX_RCOL 32
#define RCOL_LEN 64

#define RED "\033[0;31m"
#define GREEN "\033[0;32m"
#define YELLOW "\033[0;33m"

#define HRED "\033[0;91m"
#define HGREEN "\033[0;92m"
#define HYELLOW "\033[0;93m"

#define RESET "\033[0m"

unsigned hash(char const *buf) {
  unsigned res = 5381;
  for (; *buf; buf++) {
    res = (res << 5) + res + *buf;
  }
  return res;
}

void err_misfmt_input(char const *reason) {
  fprintf(stderr, "error: misformatted input: %s\n", reason);
  exit(1);
}

char buf[MAX_LINE_LEN];

struct counters {
  unsigned char pfs[3];
};

unsigned num_rcol = 0;
unsigned rcol_hashes[MAX_RCOL] = {0};
char rcol_values[MAX_RCOL][RCOL_LEN];
struct counters rcol_ctr[MAX_RCOL] = {0};

unsigned rcol_lut(unsigned hash) {
  unsigned *p;
  for (p = rcol_hashes; *p; p++)
    if (*p == hash)
      return p - rcol_hashes + 1;
  return 0;
}

void rstrip(char *buf) {
  char *sub;
  for (; *buf; buf++) {
    if (isspace(*buf)) {
      for (sub = buf + 1; *sub && isspace(*sub); sub++)
        ;
      if (!*sub) {
        *buf = 0;
        break;
      }
    }
  }
}

void put(int pfs_mode) {
  if (pfs_mode == 0)
    printf(HGREEN "* " RESET);
  else if (pfs_mode == 1)
    printf(HRED "X " RESET);
  else
    printf(HYELLOW "- " RESET);
}

void finish(int last_lc, unsigned last_rcol_idx) {
  if (last_lc == 0)
    return;

  for (; last_rcol_idx < num_rcol; last_rcol_idx++) {
    put(2);
    rcol_ctr[last_rcol_idx].pfs[2] += 1;
  }
}

int main(int argc, char **argv) {
  int lcol_width;
  unsigned last_lc = 0;
  char *p, *lcol, *rcol;
  unsigned lcol_hash, rcol_hash, rcol_idx, last_rcol_idx = 0,
                                           actual_last_rcol_idx, i, j, pfs_mode;
  struct counters sum = {0};

  if (argc != 2 || !((lcol_width = atoi(argv[1])))) {
    fprintf(stderr, "usage: %s <left column width>\n", *argv);
    return 1;
  }

  while (buf == fgets(buf, lenof(buf), stdin)) {
    p = buf;
    for (; isspace(*p); p++)
      ;
    if (*p == '#' || !*p)
      continue;

    lcol = strtok(p, " \t");
    rcol = strtok(0, " \t");
    p = strtok(0, " \t");
    rstrip(p);

    if (!p || p[1])
      err_misfmt_input("3rd column invalid");

    if (*p == '0')
      pfs_mode = 1;
    else if (*p == '1')
      pfs_mode = 0;
    else if (*p == '-')
      pfs_mode = 2;
    else
      err_misfmt_input("3rd column invalid");

    lcol_hash = hash(lcol);
    rcol_hash = hash(rcol);

    actual_last_rcol_idx = last_rcol_idx;
    if (lcol_hash != last_lc) {
      last_rcol_idx = 0;
    }

    rcol_idx = rcol_lut(rcol_hash);
    if (rcol_idx == 0) {
      rcol_idx = ++num_rcol;
      /* TODO: validate length */
      rcol_hashes[rcol_idx - 1] = rcol_hash;
      /* TODO: validate length */
      strcpy(rcol_values[rcol_idx - 1], rcol);
    } else if (rcol_idx <= last_rcol_idx && last_rcol_idx != 0) {
      err_misfmt_input("ordering different from last time");
    }

    rcol_ctr[rcol_idx - 1].pfs[pfs_mode] += 1;

    if (lcol[0] == '-' && lcol[1] == 0)
      continue;

    if (lcol_hash != last_lc) {
      finish(last_lc, actual_last_rcol_idx);
      if (last_lc != 0)
        putchar('\n');
      last_lc = lcol_hash;
      last_rcol_idx = 0;
      printf("%*s  ", lcol_width, lcol);
    }

    for (i = last_rcol_idx + 1; i < rcol_idx; i++) {
      put(2);
      rcol_ctr[i - 1].pfs[2]++;
    }

    put(pfs_mode);
    last_rcol_idx = rcol_idx;

    fflush(stdout);
  }

  finish(last_lc, last_rcol_idx);
  if (last_lc != 0)
    putchar('\n');

  for (i = 0; i <= num_rcol; i++) {
    for (j = 0; j < lcol_width + (num_rcol - i) * 2; j++)
      putchar(' ');
    if (i != num_rcol) {
      putchar('^');
      sum.pfs[0] += rcol_ctr[i].pfs[0];
      sum.pfs[1] += rcol_ctr[i].pfs[1];
      sum.pfs[2] += rcol_ctr[i].pfs[2];
    } else
      putchar(' ');
    if (i != 0) {
      printf(" %s \t(%u/%u passed", rcol_values[num_rcol - i],
             rcol_ctr[num_rcol - i].pfs[0],
             rcol_ctr[num_rcol - i].pfs[0] + rcol_ctr[num_rcol - i].pfs[1]);
      if (rcol_ctr[num_rcol - i].pfs[2])
        printf(", %u skipped", rcol_ctr[num_rcol - i].pfs[2]);
      printf(")");
    }
    putchar('\n');
  }

  printf("\nSummary:\n");
  if (sum.pfs[0])
    printf(HGREEN "  %u passed" RESET "\n", sum.pfs[0]);
  if (sum.pfs[1])
    printf(HRED "  %u failed" RESET "\n", sum.pfs[1]);
  if (sum.pfs[2])
    printf(HYELLOW "  %u skipped" RESET "\n", sum.pfs[2]);

  return 0;
}
