#include <serial.h>
#include <string_utils.h>

extern EFI_SYSTEM_TABLE *ST;

serial_context g_serial;

void serial_init(EFI_SERIAL_IO_PROTOCOL *SerialIo) {
    g_serial.SerialIo = SerialIo;
    uefi_call_wrapper(SerialIo->Reset, 1, SerialIo);
}

void serial_write_char(char c) {
    if (!g_serial.SerialIo) {
        uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, (CHAR16*)L"serial: null io\n");
        return;
    }
    UINTN size = 1;
    EFI_STATUS status = uefi_call_wrapper(g_serial.SerialIo->Write, 3, g_serial.SerialIo, &size, &c);
    if (status != EFI_SUCCESS) {
        uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, (CHAR16*)L"serial: write failed\n");
    }
}

void serial_write(String str) {
    if (!g_serial.SerialIo) {
        uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, (CHAR16*)L"serial: null io\n");
        return;
    }
    while (*str) {
        serial_write_char(*str++);
    }
}

void serial_write_hex(UINTN val) {
    char buf[19];
    buf[0] = '0';
    buf[1] = 'x';
    SSINT32 pos = 2;
    if (val == 0) {
        buf[pos++] = '0';
    } else {
        char tmp[17];
        SSINT32 len = 0;
        while (val) {
            UINTN digit = val & 0xF;
            tmp[len++] = digit < 10 ? '0' + digit : 'A' + digit - 10;
            val >>= 4;
        }
        for (SSINT32 i = len - 1; i >= 0; i--) {
            buf[pos++] = tmp[i];
        }
    }
    buf[pos] = '\0';
    serial_write(buf);
}

char serial_read_char() {
    if (!g_serial.SerialIo) return 0;
    char c = 0;
    UINTN size = 1;
    EFI_STATUS status = uefi_call_wrapper(g_serial.SerialIo->Read, 3, g_serial.SerialIo, &size, &c);
    if (status != EFI_SUCCESS || size == 0) return 0;
    return c;
}