//! Example implementation of ReadableMessage for a structured message
//!
//! This primarily serves to illustrate the documentation of `MessageOption`.

use coap_message::ReadableMessage;

struct MinimalMessage {
    code: u8,
    content_format: Option<u16>,
    etag: Option<Vec<u8>>,
    payload: Vec<u8>,
}

enum MessageOption<'a> {
    EncodedContentFormat([u8; 2]),
    EtagReference(&'a [u8]),
}

impl coap_message::MessageOption for MessageOption<'_> {
    fn number(&self) -> u16 {
        match self {
            MessageOption::EncodedContentFormat(_) => 12,
            MessageOption::EtagReference(_) => 4,
        }
    }
    fn value(&self) -> &[u8] {
        match self {
            MessageOption::EncodedContentFormat(d) => &d[..],
            MessageOption::EtagReference(d) => d,
        }
    }
}

struct OptionsIter<'a> {
    message: &'a MinimalMessage,
    emitted_content_format: bool,
    emitted_etag: bool,
}

impl<'a> Iterator for OptionsIter<'a> {
    type Item = MessageOption<'a>;

    fn next(&mut self) -> Option<MessageOption<'a>> {
        if !self.emitted_etag {
            self.emitted_etag = true;
            if let Some(ref e) = self.message.etag {
                return Some(MessageOption::EtagReference(e));
            }
        }
        if !self.emitted_content_format {
            self.emitted_content_format = true;
            if let Some(f) = self.message.content_format {
                return Some(MessageOption::EncodedContentFormat(f.to_be_bytes()));
            }
        }
        None
    }
}

impl ReadableMessage for MinimalMessage {
    type Code = u8;
    type MessageOption<'a> = MessageOption<'a>;
    type OptionsIter<'a> = OptionsIter<'a>;

    fn code(&self) -> u8 {
        self.code
    }

    fn payload(&self) -> &[u8] {
        self.payload.as_ref()
    }

    fn options(&self) -> OptionsIter<'_> {
        OptionsIter {
            message: self,
            emitted_content_format: false,
            emitted_etag: false,
        }
    }
}

fn main() {
    use coap_message::MessageOption;

    let m = MinimalMessage {
        code: 0x45, // Content
        etag: None,
        content_format: Some(0),
        payload: b"Hello World".to_vec(),
    };

    for option in m.options() {
        if option.number() == 12 {
            // No shortening happens, so we don't expect any
            assert!(
                option.value() == &[0, 0],
                "Not the expected content format value"
            );
        } else {
            panic!(
                "Option {}: {:?} not expected by construction",
                option.number(),
                option.value()
            );
        }
    }

    println!("Message was read as expected");
}
