//! #简单的visa库基于visa-rs二次封装
//! ~~~rust
//! use mcuvisa::{AccessMode, IInstr, RRm,power::p66319_d::P66319D};
//! let cdd = mcuvisa::DefaultRM::new().unwrap();
//! let mut cdsd= cdd.m_open("TCPIP0::localhost::inst0::INSTR",AccessMode::NO_LOCK, 30).unwrap();
//! cdsd.m_send("cmd");
//! cdsd.m_get_describ();
//! let mut pow = P66319D::new(cdsd);
//! pow.m_init();
//! ~~~
pub mod power;
pub mod sp8315;
pub mod cmw500;
use log::debug;
use std::ffi::CString;
use std::io::{BufRead, BufReader, Write,Read};
use std::time::Duration;
pub use visa_rs::{flags::AccessMode, DefaultRM,Instrument};
pub trait RRm {
    /// ```
    /// GPIB0::{}::INSTR
    /// TCPIP0::{}::inst0::INSTR
    /// ```
    fn m_open(&self, path: &str,accessmode:AccessMode, timeout: u64) -> visa_rs::Result<visa_rs::Instrument>;
}
impl RRm for DefaultRM {
    fn m_open(&self, path: &str,accessmode:AccessMode, timeout: u64) -> visa_rs::Result<visa_rs::Instrument> {
        self.open(
            &CString::new(path).unwrap().into(),
            accessmode,
            std::time::Duration::from_secs(timeout),
        )
    }
}
pub trait IInstr {
    fn m_send(&mut self, cmd: &str) -> std::io::Result<()>;
    fn m_send1(&mut self, cmd: &str) -> std::io::Result<()>;
    fn m_read(&mut self) -> Option<String>;
    fn m_read1(&mut self) -> Option<String>;
    fn m_query(&mut self, msg: &str) -> Option<String>;
    fn m_query1(&mut self,msg: &str) -> Option<String>;
    fn m_query_and_confirm(&mut self, cmd: &str, confirm_answer: &str) -> Result<String, String>;
    fn m_query_while_key_time(
        &mut self,
        cmd: &str,
        confirm_key: &str,
        time_s: u64,
    ) -> Result<String, String>;
    fn m_get_describ(&mut self) -> Option<String> ;
}
impl IInstr for visa_rs::Instrument {
    fn m_send(&mut self, cmd: &str) -> std::io::Result<()> {
        self.write_all(format!("{}\n", cmd).as_bytes())
    }
    fn m_send1(&mut self, cmd: &str) -> std::io::Result<()> {
        self.write_all(format!("{}\n", cmd).as_bytes())?;
        let mut datatemp = String::new();
        self.write_all(b"OPC?")?;
        let mut buf_reader = BufReader::new(self);
        let nowtime=std::time::Instant::now();
        while nowtime.elapsed()<std::time::Duration::from_secs(30){
            if let Ok(_) = buf_reader.read_line(&mut datatemp) {
                if datatemp.contains("1"){
                    return Ok(());
                }
            }
            esleep::ms(200);
        }
        Err(std::io::ErrorKind::TimedOut.into())
    }

    fn m_read(&mut self) -> Option<String> {
        let mut datatemp = String::new();
        let mut buf_reader = BufReader::new(self);
        let nowtime=std::time::Instant::now();
        while nowtime.elapsed()<std::time::Duration::from_secs(30){
            if let Ok(_) = buf_reader.read_line(&mut datatemp) {
                debug!("{datatemp}");
                return Some(datatemp);
            }
            esleep::s(1);
        }
        None
    }

    fn m_query(&mut self, msg: &str) -> Option<String> {
        self.m_send(msg).ok()?;
        self.m_read()
    }

    fn m_query_and_confirm(&mut self, cmd: &str, confirm_answer: &str) -> Result<String, String> {
        let mut tmpdata = String::new();
        if let Some(getdata) = self.m_query(cmd) {
            if getdata.contains(confirm_answer) {
                return Ok(getdata);
            }
            tmpdata = getdata;
        }
        Err(tmpdata)
    }

    fn m_query_while_key_time(
        &mut self,
        cmd: &str,
        confirm_key: &str,
        time_s: u64,
    ) -> Result<String, String> {
        let marktime = std::time::Instant::now();
        let mut errmsg = String::new();
        loop {
            if let Some(data) = self.m_query(cmd) {
                let cc: Vec<&str> = data.split(",").collect();
                for idx in cc {
                    if let Some(_) = idx.find(confirm_key) {
                        return Ok(data);
                    }
                }
                errmsg = data;
            }
            if marktime.elapsed() > Duration::from_secs(time_s) {
                return Err(errmsg);
            }
            esleep::s(1);
        }
    }
    fn m_get_describ(&mut self) -> Option<String> {
        self.m_query("*IDN?")
    }

    fn m_read1(&mut self) -> Option<String> {
        let mut buff = [0;2048];
        if let Ok(dn) = self.read(&mut buff){
            return Some(unsafe { String::from_utf8_unchecked(buff[..dn].to_vec()) });
        }
        None
    }

    fn m_query1(&mut self,msg: &str) -> Option<String> {
        self.m_send(msg);
        self.m_read1()
    }
}
#[cfg(test)]
mod totess{
    #[test]
    fn test1(){
        use std::sync::Arc;
        use super::*;
        use super::power::p66319_d as powered;
        let mut cdd = DefaultRM::new().unwrap();
        // println!("{}",cdd.find_res(&CString::new("*").unwrap().into()).unwrap().to_string());
        let mut cdsd= cdd.m_open("path",AccessMode::NO_LOCK, 30).unwrap();
        // cdsd.m_send(cmd)
        let dsdd = Box::new(cdsd);
        let dsdd1 = dsdd;
        let cd = std::thread::spawn(move ||{
            
            dsdd1
        });
        cd.join().unwrap();
    }
    #[test]
    fn test2(){
        use super::*;
        let mut cdd = DefaultRM::new().unwrap();
        let mut cdsd= cdd.m_open("TCPIP0::127.0.0.1::inst0::INSTR",AccessMode::NO_LOCK, 30).unwrap();
        // cdsd.m_send("SYSTem:COMMunicate:HISLip:VRESource?");
        if let Some(dd) = cdsd.m_query("FETCh:LTE:MEAS:MEValuation:ACLR:CURRent?"){
            println!("{}",dd);
        }
    }
}