#ifndef CMD_H
#define CMD_H

#include <stdbool.h>
#include <stdint.h>
#include "buffer.h"

#define STR_SIZE 255

#define CMD_GET_METRICS 0x00
#define CMD_GET_USER_PAGES 0x01
#define CMD_LIST_USERS 0x02
#define CMD_MODIFY_USERNAME 0x03
#define CMD_MODIFY_PASSWORD 0x04
#define CMD_ADD_USER 0x05
#define CMD_DELETE_USER 0x006
#define CMD_GET_PASSWORD_DISSECTOR_STATUS 0x07
#define CMD_MODIFY_PASSWORD_DISSECTOR_STATUS 0x08
#define CMD_GET_AUTHENTICATION_STATUS 0x09
#define CMD_MODIFY_AUTHENTICATION_STATUS 0x0A

#define CMD_NOT_SUPPORTED_CMD 0xFF

#define CONFIG_OK 0x00
#define CONFIG_SERVER_ERROR 0xA0
#define CONFIG_INVALID_TOKEN 0xB0
#define CONFIG_INVALID_PARAMETER 0xC0
#define CONFIG_USER_NOT_FOUND 0xC1
#define CONFIG_ALREADY_USER_EXISTS 0xC2
#define CONFIG_VERSION_NOT_SUPPORTED 0xD0
#define CONFIG_UNKNOWN_COMMAND 0xFE

enum cmd_state {
    cmd_version,
    cmd_token,
    cmd_cmd,
    cmd_parameters,
    cmd_done,
    cmd_error_unsupported_version,
    cmd_error_invalid_token,
    cmd_error_unsupported_command,
    cmd_error_invalid_parameter
};

enum param_state {
    param_ulen,
    param_uname,
    param_new_ulen,
    param_new_uname,
    param_plen,
    param_passwd,
    param_byte,
    param_value,
};

enum cmd_response_status {
    status_succeeded = 0x00,
    status_failure = 0x01,
};

struct cmd_parser {
    void (* on_token) (struct cmd_parser * parser, const uint64_t token);
    void (* on_cmd) (struct cmd_parser * parser, const uint8_t cmd);
    void * data;
    enum cmd_state state;
    enum param_state param_state;
    uint8_t * cmd;
    uint8_t remaining;
    uint8_t * verified;
    uint64_t token;

    uint8_t idx;

    char * username;
    char * new_username;
    char * password;
    uint8_t * byte;
    uint16_t * value;

    void * parameters;
};

extern bool is_valid(uint8_t c);

void cmd_parser_init(struct cmd_parser * p);

enum cmd_state cmd_parser_feed(struct cmd_parser * p, uint8_t b);

enum cmd_state cmd_consume(buffer * b, struct cmd_parser * p, bool * errored);

bool cmd_is_done(enum cmd_state state, bool * errored);

extern uint8_t cmd_error(const struct cmd_parser * p);

void cmd_parser_close(struct cmd_parser * p);

#endif
