//! 数据接收器

use crate::consts::*;
use crate::frame::*;
use crc16;
use heapless::Vec;

/// 接收器状态
enum Status {
    Lead(u8),
    Start,
    Length1,
    Length2,
    End,
    Finish,
}

/// 接收器
pub struct Reader {
    /// 已处理的数据
    buf: Vec<u8, FrameLen>,
    /// 待处理的数据
    pend: Vec<u8, FrameLen>,
    /// 负载长度
    load_len: usize,
    /// 接收状态
    status: Status,
}
impl Reader {
    /// 创建一个空的接收器
    pub fn new() -> Self {
        Reader {
            buf: Vec::new(),
            pend: Vec::new(),
            load_len: 0,
            status: Status::Lead(0),
        }
    }
    /// 接收器是否为空
    pub fn is_empty(&self) -> bool {
        self.pend.is_empty() && self.buf.is_empty()
    }
    /// 清空接收器中处理完的数据
    fn clean(&mut self) {
        self.buf.clear();
        self.status = Status::Lead(0);
    }
    /// 处理一个字节
    fn recv_one(&mut self, res: u8) -> bool {
        match self.status {
            Status::Lead(mut count) => {
                if res == CHAR_LEAD {
                    count += 1;
                    if count >= 3 {
                        self.status = Status::Start;
                    } else {
                        self.status = Status::Lead(count);
                    }
                } else {
                    self.clean();
                }
            }
            Status::Start => {
                if res == CHAR_LEAD {
                } else if res == CHAR_START {
                    self.buf.push(res).unwrap();
                    self.status = Status::Length1;
                } else {
                    self.clean();
                }
            }
            Status::Length1 => {
                self.buf.push(res).unwrap();
                self.status = Status::Length2;
            }
            Status::Length2 => {
                self.buf.push(res).unwrap();
                self.load_len = (self.buf[Field::Length as usize] as usize) << 8
                    | self.buf[Field::Length as usize + 1] as usize;
                if self.load_len > LOAD_LEN {
                    self.clean();
                } else {
                    self.status = Status::End;
                }
            }
            Status::End => {
                if self.buf.len() < self.load_len + MIN_LEN - 1 {
                    self.buf.push(res).unwrap();
                } else {
                    if res == CHAR_END {
                        self.buf.push(res).unwrap();
                        self.status = Status::Finish;
                        return true;
                    } else {
                        self.clean();
                        self.recv_one(res);
                    }
                }
            }
            Status::Finish => {
                self.clean();
                self.recv_one(res);
            }
        }
        return false;
    }
    /// 接收数据并找出一个数据帧，返回负载数据
    pub fn recv(&mut self, buf: &[u8]) {
        if buf.len() > 0 {
            // 追加到待处理数据中
            self.pend.extend_from_slice(buf).unwrap();
        }
        for i in 0..self.pend.len() {
            let res = self.pend[i];
            let finish = self.recv_one(res);
            if finish {
                self.pend = Vec::<u8, FrameLen>::from_slice(&self.pend[i + 1..]).unwrap();
                return;
            }
        }
        self.pend.clear();
    }
    pub fn is_finish(&self) -> bool {
        return self.pend.is_empty();
    }
    pub fn is_ready(&self) -> bool {
        if let Status::Finish = self.status {
            return true;
        } else {
            return false;
        }
    }
    pub fn get_load(&self) -> &[u8] {
        if let Status::Finish = self.status {
            let load = frame2load(&self.buf);
            if load.len() > 0 {
                return load;
            }
        }
        return &[];
    }
}

/// 将数据帧转化为负载数据
fn frame2load(frame: &[u8]) -> &[u8] {
    let frame_len = frame.len();
    if frame_len < MIN_LEN || frame_len > FRAME_LEN {
        return &[];
    }
    let mut i_start = 0;
    while frame[i_start] == CHAR_LEAD {
        i_start += 1;
    }
    let frame_load_len = (frame[i_start + Field::Length as usize] as usize) << 8
        | frame[i_start + Field::Length as usize + 1] as usize;
    let frame_load =
        &frame[i_start + Field::Load as usize..i_start + Field::Load as usize + frame_load_len];
    let frame_check = (frame[i_start + Field::Load as usize + frame_load_len] as u16) << 8
        | frame[i_start + Field::Load as usize + frame_load_len + 1] as u16;
    // CRC检验
    let check = crc16::State::<crc16::MODBUS>::calculate(frame_load);
    if check == frame_check {
        return frame_load;
    } else {
        return &[];
    }
}
