use super::LinkTrait;
use core::fmt;
use std::io;
use std::sync::Arc;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio_serial::SerialStream;

pub struct Serial {
    addr: String,
    serial: SerialStream,
    data: [u8; 4096],
}
impl Serial {
    pub async fn new(addr: &str, port: u32) -> io::Result<Serial> {
        let serial = tokio_serial::new(addr, port);
        let serial = SerialStream::open(&serial).unwrap();
        Ok(Serial {
            addr: format!("{}:{}", addr, port),
            serial,
            data: [0; 4096],
        })
    }
}

#[async_trait::async_trait]
impl LinkTrait for Serial {
    async fn send(&mut self, msg: &[u8]) -> io::Result<()> {
        self.serial.write_all(msg).await
    }
    async fn recv(&mut self) -> io::Result<Arc<Vec<u8>>> {
        let len = self.serial.read(&mut self.data).await?;
        let data = Arc::new(Vec::from(&self.data[..len]));
        log::info!("{} recv: {:02X?}", self, data);
        Ok(data)
    }
}

impl fmt::Display for Serial {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_fmt(format_args!("Serial({:?})", self.addr))
    }
}