#ifndef UART_CLAY_UART_FUNC_H
#define UART_CLAY_UART_FUNC_H

#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>

#include "clay.h"

bool UART_modal_show = false;

typedef struct {
    int serial_port;
    Clay_String buffer;
} uart_data;

static void trim_message(const Clay_String message, const size_t length) {
    memset((void *)message.chars + length - 2, 0, message.length - length + 2);
}

int open_uart_port(const char *file_path) {
    const int serial_port = open(file_path, O_RDWR);
    if (serial_port < 0) {
        printf("Error %i from open: %s\n", errno, strerror(errno));
        return -1;
    }

    struct termios tty;
    if (tcgetattr(serial_port, &tty) < 0) {
        printf("Error %i from tcgetattr: %s\n", errno, strerror(errno));
        return -1;
    }

    tty.c_cflag &= ~PARENB; // Clear parity bit, disabling parity
    tty.c_cflag &= ~CSTOPB; // Clear stop field, only one stop bit used in communication
    tty.c_cflag &= ~CSIZE; // Clear all the size bits
    tty.c_cflag |= CS8; // 8 bits per byte
    tty.c_cflag &= ~CRTSCTS; // Disable RTS/CTS hardware flow control
    tty.c_cflag |= CREAD | CLOCAL; // Turn on READ & ignore ctrl lines (CLOCAL = 1)

    tty.c_lflag &= ~ICANON; // Non-canonical mode
    tty.c_lflag &= ~ECHO; // Disable echo
    tty.c_lflag &= ~ECHOE; // Disable erasure
    tty.c_lflag &= ~ECHONL; // Disable new-line echo
    tty.c_lflag &= ~ISIG; // Disable interpretation of INTR, QUIT and SUSP

    tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Turn off s/w flow ctrl
    tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL);
    // Disable any special handling of received bytes

    tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
    tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed

    tty.c_cc[VTIME] = 0;
    tty.c_cc[VMIN] = 1;

    // Set baud rate to be 9600
    cfsetspeed(&tty, B9600);

    // Save tty settings, also checking for error
    if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
        printf("Can't set fd state. Error %d, %s", errno, strerror(errno));
        return -1;
    }

    return serial_port;
}

void handle_uart(const uart_data *data, const char msg, const int response_length) {
    write(data->serial_port, &msg, 1);

    memset((void *)data->buffer.chars, 0, data->buffer.length);
    read(data->serial_port, (void *)data->buffer.chars, response_length);
}

#endif //UART_CLAY_UART_FUNC_H