use crate::data_messages::*;
use crate::receive_error::*;
use std::fmt;
use std::mem::size_of;

#[repr(C)]
#[derive(Clone, Copy)]
pub struct $name_pascal_case$Message {
    pub timestamp: u64,
    $arguments_struct_declare$
}

impl Default for $name_pascal_case$Message {
    fn default() -> Self {
        Self {
            timestamp: 0,
            $arguments_struct_default$
        }
    }
}

impl DataMessage for $name_pascal_case$Message {
    fn get_ascii_id() -> u8 {
        b'$ascii_id$'
    }

    fn parse_ascii(message: &str) -> Result<Self, ReceiveError> {
        match scan_fmt!(message, "{},{d},$arguments_scan_fmt$\n", char, u64, $arguments_types$) {
            Ok((_, timestamp, $arguments_scan_result$)) => Ok(Self {
                timestamp,
                $arguments_struct_asign$
            }),
            Err(_) => Err(ReceiveError::UnableToParseAsciiMessage),
        }
    }

    fn parse_binary(message: &[u8]) -> Result<Self, ReceiveError> {
        #[repr(C, packed)]
        struct BinaryMessage {
            _id: u8,
            timestamp: u64,
            $arguments_packed_struct$
            _termination: u8,
        }

        if message.len() != size_of::<BinaryMessage>() {
            return Err(ReceiveError::InvalidBinaryMessageLength);
        }

        let binary_message = unsafe {
            let ref binary_message = *(message.as_ptr() as *const BinaryMessage);
            binary_message
        };

        Ok(Self {
            timestamp: binary_message.timestamp,
            $arguments_assign_struct$
        })
    }

    fn get_csv_file_name(&self) -> &'static str {
        "$name_pascal_case$.csv"
    }

    fn get_csv_headings(&self) -> &'static str {
        "Timestamp (us),$csv_headings$\n"
    }

    fn to_csv_row(&self) -> String {
        format!("{},$arguments_csv_format$\n", self.timestamp, $arguments_self_list$)
    }
}

impl fmt::Display for $name_pascal_case$Message {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{:>8} us$arguments_string_format$", self.timestamp, $arguments_self_list$)
    }
}