#ifndef PARSER_H
#define PARSER_H

#include <stdint.h>
#include <stddef.h>

struct parser_event {
    /** tipo de evento */
    unsigned type;
    /** caracteres asociados al evento */
    uint8_t data[3];
    /** cantidad de datos en el buffer 'data' */
    uint8_t n;

    /** lista de eventos: si es diferente de null ocurrieron varios eventos */
    struct parser_event *next;
};

/* CDT del parser */
typedef struct parser {
    /** tipificación para cada caracter */
    const unsigned *classes;
    /** definición de estados */
    struct parser_definition *def;

    /* estado actual */
    unsigned state;

    /* evento que se retorna */
    struct parser_event e1;
    /* evento que se retorna */
    struct parser_event e2;
} parser;

/** describe una transición entre estados  */
struct parser_state_transition {
    /* condición: un caracter o una clase de caracter. Por ej: '\r' */
    int when;
    /** descriptor del estado destino cuando se cumple la condición */
    unsigned dest;
    /** acción 1 que se ejecuta cuando la condición es verdadera. requerida. */
    void (*act1)(struct parser_event *ret, const uint8_t c);
    /** otra acción opcional */
    void (*act2)(struct parser_event *ret, const uint8_t c);
};

/** predicado para utilizar en `when' que retorna siempre true */
static const unsigned ANY = 1 << 9;

/** declaración completa de una máquina de estados */
struct parser_definition {
    /** cantidad de estados */
    unsigned states_count;
    /** por cada estado, sus transiciones */
    struct parser_state_transition **states;
    /** cantidad de estados por transición */
    size_t *states_n;

    /** estado inicial */
    unsigned start_state;
};

/**
 * inicializa el parser.
 *
 * `classes`: caracterización de cada caracter (256 elementos)
 */
struct parser * parser_init(const unsigned *classes, struct parser_definition *def);

/** destruye el parser */
void parser_destroy(struct parser *p);

/** permite resetear el parser al estado inicial */
void parser_reset(struct parser *p);

/**
 * el usuario alimenta el parser con un caracter, y el parser retorna un evento
 * de parsing. Los eventos son reusado entre llamadas por lo que si se desea
 * capturar los datos se debe clonar.
 */
struct parser_event * parser_feed(struct parser *p, const uint8_t c);

/**
 * En caso de la aplicacion no necesite clases caracteres, se
 * provee dicho arreglo para ser usando en `parser_init'
 */
const unsigned * parser_no_classes(void);


#endif
