#![no_std]

use core::iter;

use alloc::{sync::Arc, vec::Vec};
use device_api::{
    clock::Hertz,
    device::{Device, DeviceInitContext},
    interrupt::{InterruptHandler, IrqVector},
};
use libk::error::Error;
use libk_util::OneTimeInit;

use crate::port::Port8250;

extern crate alloc;

#[cfg(any(rust_analyzer, target_arch = "aarch64", target_arch = "riscv64"))]
pub mod fdt;
#[cfg(any(rust_analyzer, target_arch = "x86_64", target_arch = "x86"))]
pub mod io;
pub mod port;

pub trait Config: Sync + Send {
    type Port: PortConfig;

    fn ports(&self) -> &[Self::Port];
    fn enable_interrupt(&self, handler: Arc<dyn InterruptHandler>) -> Result<(), Error>;
}

pub trait PortConfig: Sync + Send {
    fn input_clock_frequency(&self) -> Result<Hertz, Error>;
    fn enable_clocks(&self) -> Result<(), Error>;
    fn deassert_resets(&self) -> Result<(), Error>;
}

pub trait Access: Sized + Send + 'static {
    type Config: Config;

    /// # Safety
    ///
    /// Unsafe: allows physical memory access.
    unsafe fn map(config: &<Self::Config as Config>::Port) -> Result<Self, Error>;

    fn read(&self, reg: u8) -> u8;
    fn write(&mut self, reg: u8, val: u8);
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Vendor {
    DwApbUart,
    Bcm2835Aux,
    Generic8250,
    Generic16550,
}

pub struct Uart8250<A: Access> {
    config: A::Config,
    vendor: Vendor,
    ports: Vec<Arc<Port8250<A>>>,
}

impl<A: Access> Uart8250<A> {
    pub fn new(config: A::Config, vendor: Vendor) -> Self {
        let ports = config
            .ports()
            .iter()
            .map(|_| {
                Arc::new(Port8250 {
                    vendor,
                    inner: OneTimeInit::new(),
                })
            })
            .collect();
        Self {
            config,
            vendor,
            ports,
        }
    }

    /// # Safety
    ///
    /// Unsafe: the function is meant only to be called once, directly
    /// interacts with the device state.
    pub unsafe fn init_inner(self: &Arc<Self>) -> Result<(), Error> {
        let ports = self.ports.iter();
        let port_configs = self.config.ports().iter();
        for (port, config) in iter::zip(ports, port_configs) {
            port.clone().init(config)?;
        }

        Ok(())
    }
}

impl<A: Access> Device for Uart8250<A> {
    unsafe fn init(self: Arc<Self>, _cx: DeviceInitContext) -> Result<(), Error> {
        unsafe { self.init_inner() }
    }

    unsafe fn init_irq(self: Arc<Self>) -> Result<(), Error> {
        self.config.enable_interrupt(self.clone())?;
        for port in self.ports.iter() {
            port.enable_irq();
        }
        Ok(())
    }

    fn display_name(&self) -> &str {
        match self.vendor {
            Vendor::DwApbUart => "Synopsys DesignWare 16550 UART",
            Vendor::Bcm2835Aux => "bcm2835 AUX UART",
            Vendor::Generic16550 => "16550 UART",
            Vendor::Generic8250 => "8250 UART",
        }
    }
}

impl<A: Access> InterruptHandler for Uart8250<A> {
    fn handle_irq(self: Arc<Self>, _vector: IrqVector) -> bool {
        for port in self.ports.iter() {
            if port.handle_irq() {
                return true;
            }
        }
        false
    }
}
