Documentation
use crate::knxnet::hpai::HPAI;
use crate::knxnet::{KnxNetIpError};
use crate::knxnet::crd::ConnectionRespType;
use crate::knxnet::cri::ConnectionReqType;
use crate::knxnet::status::StatusCode;

#[derive(Debug, Copy, Clone)]
#[repr(u8)]
pub(crate) enum Layer {
    TunnelLayerData = 0x02,
    TunnelLayerRaw = 0x04,
    TunnelLayerBusmon = 0x80,
}


#[derive(Debug, PartialEq, Default)]
pub(crate) struct ConnectRequest {
    pub(crate) data: HPAI,
    pub(crate) control: HPAI,
    pub(crate) connection_type: ConnectionReqType
}

#[derive(Debug, PartialEq, Default)]
pub(crate) struct ConnectResponse{
    pub(crate) channel: u8,
    pub(crate) status: StatusCode,
    pub(crate) data: HPAI,
    pub(crate) connection_type: ConnectionRespType,
}

impl ConnectRequest {
    pub(crate) fn payload_length(&self)->u16 {
        return self.connection_type.length() + 2 * HPAI::length();
    }

    pub(crate) fn encode(&self, buf: &mut Vec<u8>){
        self.control.encode(buf);
        self.data.encode(buf);
        self.connection_type.encode(buf);
    }

    pub(crate) fn decode(&mut self, buf: &[u8]) -> Result<(), KnxNetIpError> {
        if buf.len() < 2 * HPAI::length() as usize {
            return Err(KnxNetIpError::MessageTooShort(buf.len()))
        }
        self.control = HPAI::decode(&buf[0..8])?;
        self.data = HPAI::decode(&buf[8..16])?;
        self.connection_type = ConnectionReqType::decode(&buf[16..buf.len()])?;
        return Ok(());
    }
}


impl ConnectResponse {
    pub(crate) fn payload_length(&self)->u16 {
        return 2 + if self.status == StatusCode::NoError {HPAI::length() + self.connection_type.length()} else {0};
    }

    pub(crate) fn encode(&self, buf: &mut Vec<u8>){
        buf.push(self.channel);
        buf.push(self.status as u8);
        if self.status == StatusCode::NoError {
            self.data.encode(buf);
            self.connection_type.encode(buf);
        }
    }

    pub(crate) fn decode(&mut self, buf: &[u8]) -> Result<(), KnxNetIpError> {
        if buf.len() < 2{
            return Err(KnxNetIpError::MessageTooShort(buf.len()))
        }
        self.channel = buf[0];
        self.status = match StatusCode::from_repr(buf[1]) {
            Some(status) => status,
            None => return Err(KnxNetIpError::UnknownStatus(buf[1]))
        };

        if self.status == StatusCode::NoError{
            if buf.len() < 2 + HPAI::length() as usize{
                return Err(KnxNetIpError::MessageTooShort(buf.len()))
            }
            self.data = HPAI::decode(&buf[2..10])?;
            self.connection_type = ConnectionRespType::decode(&buf[10..buf.len()])?;
        }
        return Ok(());
    }
}