/src/console/interfaces.rs
use core::slice;

use crate::console::get_global_console;
use crate::console::Key;

pub struct RustConsoleOperations {
    pub readkey: fn() -> Option<Key>,
    pub readline: fn(buf: &mut [u8]) -> usize,
    pub writeb: fn(b: u8),
    pub write: fn(a: &[u8]),
    pub discard: fn(),
    pub pos: fn(x: usize, y: usize),
    pub clear: fn(),
}

#[repr(C)]
pub struct CConsoleOperations {
    pub readkey: extern "C" fn() -> i32,
    pub readline: extern "C" fn(buf: *mut u8, len: usize) -> usize,
    pub writeb: extern "C" fn(b: u8),
    pub write: extern "C" fn(a: *const u8, len: usize),
    pub discard: extern "C" fn(),
    pub pos: extern "C" fn(x: usize, y: usize),
    pub clear: extern "C" fn(),
}

/* Console driver function table */

/* Rust versions */
fn rust_readkey() -> Option<Key> {
    get_global_console().readkey()
}

fn rust_readline(buf: &mut [u8]) -> usize {
    get_global_console().readline(buf)
}

fn rust_writeb(b: u8) {
    get_global_console().writeb(b)
}

fn rust_write(a: &[u8]) {
    get_global_console().write(a)
}

fn rust_discard() {
    get_global_console().discard()
}

fn rust_pos(x: usize, y: usize) {
    get_global_console().pos(x, y)
}

fn rust_clear() {
    get_global_console().clear()
}

pub const RUST_CONSOLE_OPERATIONS: RustConsoleOperations = RustConsoleOperations {
    readkey: rust_readkey,
    readline: rust_readline,
    writeb: rust_writeb,
    write: rust_write,
    discard: rust_discard,
    pos: rust_pos,
    clear: rust_clear,
};

/* C versions */
extern "C" fn c_readkey() -> i32 {
    match rust_readkey() {
        Some(k) => match k {
            Key::Char(c) => c as i32,
            Key::Command(c) => -(1024 + c as i32),
        }
        None => -1,
    }
}

extern "C" fn c_readline(buf: *mut u8, len: usize) -> usize {
    let buf = unsafe { slice::from_raw_parts_mut(buf, len) };
    rust_readline(buf)
}

extern "C" fn c_writeb(b: u8) {
    rust_writeb(b)
}

extern "C" fn c_write(a: *const u8, len: usize) {
    let a = unsafe { slice::from_raw_parts(a, len) };
    rust_write(a)
}

extern "C" fn c_discard() {
    rust_discard()
}

extern "C" fn c_pos(x: usize, y: usize) {
    rust_pos(x, y)
}

extern "C" fn c_clear() {
    rust_clear()
}

pub const C_CONSOLE_OPERATIONS: CConsoleOperations = CConsoleOperations {
    readkey: c_readkey,
    readline: c_readline,
    writeb: c_writeb,
    write: c_write,
    discard: c_discard,
    pos: c_pos,
    clear: c_clear,
};