use crate::hardware::mcp23017::Mcp23017;
use anyhow::Result;
use log::trace;
use std::fmt::Debug;
use crate::hardware::a4963::A4963;
use crate::hardware::pwm::PwmOutput;

pub trait Hardware {
    type Mcp23017<'a>: Mcp23017 + Send + Debug
    where
        Self: 'a;
    type Pwm: PwmOutput + Sync + Send;

    fn new_mcp23017_a(&self) -> Result<Self::Mcp23017<'_>>;
    fn new_mcp23017_b(&self) -> Result<Self::Mcp23017<'_>>;

    fn new_pwm0(&self) -> Result<Self::Pwm>;

    // fn new_mct8316a(&self) -> Result<impl Mct8316a + Sync>;
    fn new_a4963<'a, 'b>(&'a mut self) -> Result<impl A4963 + Send + 'b> ;

    fn get_battery_voltage(&self) -> Result<f64>;

    // fn get_fault(&self) -> Result<bool>;

    // fn get_fg(&self) -> Result<bool>;
}

#[cfg(feature = "raspi")]
mod raspi;

#[cfg(feature = "raspi")]
pub fn initialize() -> Result<impl Hardware> {
    trace!("initialize()");
    raspi::RaspiHardware::new()
}

#[cfg(not(feature = "raspi"))]
#[allow(unreachable_code)]
pub fn initialize() -> Result<impl Hardware> {
    trace!("initialize()");
    sim::SimHardware::new()
}

pub mod error;

pub mod channelization;
pub mod mcp23017;
#[cfg(feature = "raspi")]
mod mcp3208;
// pub mod mct8316a;
pub mod pin;
mod sim;
pub mod a4963;
pub mod pwm;
