#include "st25dv.h"

#define IDENT_NAME_MAX (sizeof(IDENTIFIER.name_str) - 1)
#define IDENT_DIAM_MAX (sizeof(IDENTIFIER.diameter_str) - 1)

static void set_identifier(const char* name, uint8_t name_len, const char* diam, uint8_t diam_len) {
    if (name_len > IDENT_NAME_MAX) {
        name_len = IDENT_NAME_MAX;
    }
    if (diam_len > IDENT_DIAM_MAX) {
        diam_len = IDENT_DIAM_MAX;
    }
    memcpy(IDENTIFIER.name_str, name, name_len);
    IDENTIFIER.name_str[name_len] = '\0';
    IDENTIFIER.name_len = name_len;

    memcpy(IDENTIFIER.diameter_str, diam, diam_len);
    IDENTIFIER.diameter_str[diam_len] = '\0';
    IDENTIFIER.diameter_len = diam_len;

    IDENTIFIER.hashed = hash(IDENTIFIER.name_str, 0, 59);
}

identifier_results get_nugget_data(void) {

    NDEF_MSG = rfid_read_first_ndef_entry();

    // readNDEFText reports parse failures through success; without this check a
    // missing or malformed tag leaves stale/uninitialised bytes in payload and
    // we transmit them as the node identity.
    if (NDEF_MSG.success != 0) {
#if DO_UART
        uart_print_uint8(NDEF_MSG.success, "NDEF parse failed, code ");
#endif
        set_identifier("UNKNOWN", 7, "N/A", 3);
        return IDENTIFIER;
    }

    TRIMMED_STRING = remove_spaces(NDEF_MSG.payload, NDEF_MSG.payload_len);
    char* delim_ptr = strchr(TRIMMED_STRING.str, ',');
    if (delim_ptr != NULL) {
        uint8_t index_comma = (uint8_t)(delim_ptr - TRIMMED_STRING.str);
        // The diameter is what follows the comma, so its length is the
        // remainder of the string -- not the whole string's length, which read
        // off the end of the 21-byte buffer.
        uint8_t diam_len = (uint8_t)(TRIMMED_STRING.length - index_comma - 1);
        set_identifier(TRIMMED_STRING.str, index_comma, delim_ptr + 1, diam_len);
    } else {
        set_identifier(TRIMMED_STRING.str, (uint8_t)TRIMMED_STRING.length, "N/A", 3);
    }

    return IDENTIFIER;
}

trimmed_string_struct remove_spaces(char* str, uint8_t len_str) {
    const uint8_t max_len = sizeof(TRIMMED_STRING.str) - 1;
    uint8_t j = 0;

    memset(TRIMMED_STRING.str, 0, sizeof(TRIMMED_STRING.str));
    for (uint8_t i = 0; (i < len_str) && str[i]; i++) {
        if ((str[i] != ' ') && (j < max_len)) {
            TRIMMED_STRING.str[j++] = str[i];
        }
    }

    // Callers run strchr() over this, so it has to be terminated.
    TRIMMED_STRING.str[j] = '\0';
    TRIMMED_STRING.length = j;
    return TRIMMED_STRING;
}

void rfid_set_low_power_down(bool state) {
    SET_PIN_OUT(DDRD, DDD5);
    if (state) {
        SET_PIN_HIGH(PORTD, PD5);
    } else {
        SET_PIN_LOW(PORTD, PD5);
    }
}

ndef_message rfid_read_first_ndef_entry(void) {
    rfid_set_low_power_down(false);
    rfid_set_i2c_power(true);
    _delay_ms(1);

    // static: a 65-byte frame here sat on top of an already deep call chain and
    // was a large part of the stack overrun.
    static unsigned char DATA_BUFFER_INTERNAL[NDEF_READ_LEN];
    memset(DATA_BUFFER_INTERNAL, 0, sizeof(DATA_BUFFER_INTERNAL));
    rfid_read_memory(DATA_BUFFER_INTERNAL, NDEF_READ_LEN, 0x0000 + 4);

    NDEF_MSG = readNDEFText(DATA_BUFFER_INTERNAL, NDEF_READ_LEN);


    rfid_set_low_power_down(true);
    rfid_set_i2c_power(false);
    return NDEF_MSG;
}

uint8_t rfid_read_system_register(void) {
    return read_one_byte_16bit_addr_no_err_register(I2C_SYSTEM_ADDR, 0x0000);
}

void rfid_set_i2c_power(bool state) {

    SET_PIN_OUT(DDRE, DDE0);
    if (state) {
        SET_PIN_HIGH(PORTE, PE0);
    } else {
        SET_PIN_LOW(PORTE, PE0);
    }
}

uint8_t rfid_read_memory(uint8_t* data, uint8_t num_bytes, uint16_t address) {
    return read_n_bytes_16bit_addr(I2C_USER_ADDR, address, data, num_bytes);
}
