#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#define ARR_LEN(X) (sizeof(X) / sizeof(X[0]))

typedef enum {
  STATE_START,
  STATE_INVALID,
  STATE_OBJ,
  STATE_ARR,
  STATE_END,
} states;

states handle_start(char input);
states handle_obj(char input);
states handle_arr(char input);

states state_machine(states current, char input);

bool check_input(const char *text);

// clang-format off
const char *inputs[] = {
	"{}",
	"[]",
	"{           }",
	"[         ]",
	"           {}",
	"           []",
	"{}              ",
	"[]              ",
	"{",
	"[",
	"}",
	"]",
	"{f}",
	"[8]",
};
// clang-format on

int main(int argc, char *argv[]) {
  for (int i = 0; i < ARR_LEN(inputs); ++i) {
    printf("%20s is %s\n", inputs[i],
           check_input(inputs[i]) ? "VALID" : "INVALID");
  }

  return EXIT_SUCCESS;
}

bool check_input(const char *text) {
  states current = STATE_START;

  for (const char *c = &(text[0]); *c != '\0'; ++c) {
    current = state_machine(current, *c);
  }

  return current == STATE_END;
}

states handle_start(char input) {
  if (isspace(input)) {
    return STATE_START;
  }

  switch (input) {
  case '{':
    return STATE_OBJ;
  case '[':
    return STATE_ARR;
  default:
    return STATE_INVALID;
  }
}

states handle_obj(char input) {
  if (isspace(input)) {
    return STATE_OBJ;
  } else if (input == '}') {
    return STATE_END;
  }

  return STATE_INVALID;
}

states handle_arr(char input) {
  if (isspace(input)) {
    return STATE_ARR;
  } else if (input == ']') {
    return STATE_END;
  }

  return STATE_INVALID;
}

states state_machine(states current, char input) {
  switch (current) {
  case STATE_START:
    return handle_start(input);
  case STATE_OBJ:
    return handle_obj(input);
  case STATE_ARR:
    return handle_arr(input);
  default:
    return current;
  }
}