
use crate::data::error::{DarraError, EcState, Result};
use crate::master::core::EtherCATMaster;
use crate::slave::core::Slave;

pub trait MasterTrySlaveExt {

    fn try_slave(&self, slave_index: u16) -> Result<Slave>;

    fn slave_opt(&self, slave_index: u16) -> Option<Slave>;
}

impl MasterTrySlaveExt for EtherCATMaster {
    fn try_slave(&self, slave_index: u16) -> Result<Slave> {
        if slave_index == 0 {
            return Err(DarraError::InvalidParameter(
                "从站索引必须 >= 1 (0 表示主站本身)".into(),
            ));
        }
        let count = self.slave_count();
        if slave_index > count {
            return Err(DarraError::InvalidParameter(format!(
                "从站索引 {} 越界 (实际从站数 = {})",
                slave_index, count
            )));
        }
        Ok(self.slave(slave_index))
    }

    fn slave_opt(&self, slave_index: u16) -> Option<Slave> {
        let count = self.slave_count();
        if slave_index >= 1 && slave_index <= count {
            Some(self.slave(slave_index))
        } else {
            None
        }
    }
}

pub trait MasterStateTryExt {

    fn try_set_state(&self, target: EcState, timeout_ms: u32) -> Result<()>;
}

impl MasterStateTryExt for EtherCATMaster {
    fn try_set_state(&self, target: EcState, timeout_ms: u32) -> Result<()> {
        use crate::utils::ffi;
        use std::os::raw::c_int;
        let mi = self.index();
        let ok = unsafe { ffi::SetStateWithTimeout(mi, target as c_int, timeout_ms) } != 0;
        if ok { Ok(()) } else { Err(DarraError::StateChangeFailed(target as u8)) }
    }
}
