// This is a personal academic project. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "parser_utils.h"

const char * parser_utils_strcmpi_event(const enum string_cmp_event_types type) {
    const char *ret;

    switch (type) {
        case STRING_CMP_MAYEQ:
            ret = "wait(c)";
            break;
        case STRING_CMP_EQ:
            ret = "eq(c)";
            break;
        case STRING_CMP_NEQ:
            ret = "neq(c)";
            break;
    }
    return ret;
}

static void may_eq(struct parser_event *ret, const uint8_t c) {
    ret->type = STRING_CMP_MAYEQ;
    ret->n = 1;
    ret->data[0] = c;
}

static void eq(struct parser_event *ret, const uint8_t c) {
    ret->type = STRING_CMP_EQ;
    ret->n = 1;
    ret->data[0] = c;
}

static void neq(struct parser_event *ret, const uint8_t c) {
    ret->type = STRING_CMP_NEQ;
    ret->n = 1;
    ret->data[0] = c;
}

struct parser_definition * parser_utils_strcmpi(const char *s) {
    const size_t n = strlen(s);

    struct parser_state_transition **states = calloc(n + 2, sizeof(*states));
    size_t *nstates = calloc(n + 2, sizeof(*nstates));
    struct parser_state_transition *transitions = calloc(3 * (n + 2), sizeof(*transitions));

    if (states == NULL || nstates == NULL || transitions == NULL) {
        free(states);
        free(nstates);
        free(transitions);

        struct parser_definition * def = calloc(1, sizeof(struct parser_definition));
      
        return def;
    }

    // Estados fijos
    const size_t st_eq = n;
    const size_t st_neq = n + 1;

    for(size_t i = 0; i < n; i++) {
        const size_t dest = (i + 1 == n) ? st_eq : i + 1;

        transitions[i * 3 + 0].when = tolower(s[i]);
        transitions[i * 3 + 0].dest = dest;
        transitions[i * 3 + 0].act1 = i + 1 == n ? eq : may_eq;
        transitions[i * 3 + 1].when = toupper(s[i]);
        transitions[i * 3 + 1].dest = dest;
        transitions[i * 3 + 1].act1 = i + 1 == n ? eq : may_eq;
        transitions[i * 3 + 2].when = ANY;
        transitions[i * 3 + 2].dest = st_neq;
        transitions[i * 3 + 2].act1 = neq;
        states[i] = transitions + (i * 3 + 0);
        nstates[i] = 3;
    }

    // EQ
    transitions[(n + 0) * 3].when = ANY;
    transitions[(n + 0) * 3].dest = st_neq;
    transitions[(n + 0) * 3].act1 = neq;
    states[(n + 0)] = transitions + ((n + 0) * 3 + 0);
    nstates[(n + 0)] = 1;

    // NEQ
    transitions[(n + 1) * 3].when = ANY;
    transitions[(n + 1) * 3].dest = st_neq;
    transitions[(n + 1) * 3].act1 = neq;
    states[(n + 1)] = transitions + ((n + 1) * 3 + 0);
    nstates[(n + 1)] = 1;


    struct parser_definition * def = malloc(sizeof(*def));
    def->start_state = 0;
    def->states_count = n + 2;
    def->states = (struct parser_state_transition **) states;
    def->states_n = (size_t *) nstates;

    return def;
}

void parser_utils_strcmpi_destroy(struct parser_definition *p) {
    free((void *)p->states[0]);
    free((void *)p->states);
    free((void *)p->states_n);
    free(p);
}
