//! Interprocess communication.

use alloc::vec::Vec;

use crate::{proccess::PID, time::Time};

extern crate alloc;

/// 131070 * 128
pub const TINY_MESSAGE_COUNT: usize = 131070;
/// 16384 * 1024
pub const SMALL_MESSAGE_COUNT: usize = 16384;
/// 65536 * 256
pub const MEDIUM_MESSAGE_COUNT: usize = 256;
///  262144 * 16
pub const LARGE_MESSAGE_COUNT: usize = 16;
/// 16777216 * 4
pub const HUGE_MESSAGE_COUNT: usize = 4;

/// 128 Bytes
pub type Tiny = [u8; 128];

/// 1 KiB
pub type Small = [u8; 1024];

/// 65.536 KiB
pub type Medium = [u8; 65536];

/// 1MiB
pub type Large = [u8; 1048576];

/// 16MiB
pub type Huge = [u8; 16777216];

/// An internal message to be held in a process message
pub enum Message {
    /// A Tiny message
    ///
    /// The message is 128 bytes long
    Tiny(Tiny),
    /// A Small message
    ///
    /// The message is 1 KiB long
    Small(Small),
    /// A Medium message
    ///
    /// The message is 65.536 KiB long
    Medium(Medium),
    /// A Large message
    ///
    /// The message is 1 MiB long
    Large(Large),
    /// A Huge message
    ///
    /// The message is 16 MiB long
    Huge(Huge),
}

/// A message that can be sent between processes
pub struct ProcessMessage {
    /// The sender of the message
    pub to_pid: PID,
    /// The receiver of the message
    pub from_pid: PID,
    /// The message
    pub message: Message,
    /// The time the message was sent
    pub sender_time: Time,
    /// The time the message was received
    pub receiver_time: Time,
}
impl ProcessMessage {
    /// Return the size of the message
    pub fn size(&self) -> usize {
        match &self.message {
            Message::Tiny(_) => 128,
            Message::Small(_) => 1024,
            Message::Medium(_) => 65536,
            Message::Large(_) => 1048576,
            Message::Huge(_) => 16777216,
        }
    }
}
#[derive(Debug)]
/// An enum of all possible errors that can occur when sending a message
pub enum MessagingError {
    /// The message is too large to be sent
    MessageTooLarge,
    /// The reciever of the message is not valid
    ProcessNonExistant,
    /// The message Queue is full
    TooManyMessages,
}

/// A mailbox that holds messages and PipeState
pub struct Mailbox {
    /// The messages in the mailbox
    pub messages: Vec<ProcessMessage>,
    /// The count of messages in the mailbox
    pub message_count: MessageCount,
}
impl Mailbox {
    /// append a message to the mailbox
    pub fn append(&mut self, message: ProcessMessage) -> Result<(), MessagingError> {
        let msg_size = message.size();

        if self.message_count.total() > 147730 {
            return Err(MessagingError::TooManyMessages);
        }

        match msg_size {
            TINY_MESSAGE_COUNT => {
                if self.message_count.tiny < TINY_MESSAGE_COUNT {
                    self.messages.push(message);
                    self.message_count.tiny += 1;
                    Ok(())
                } else {
                    Err(MessagingError::TooManyMessages)
                }
            }
            SMALL_MESSAGE_COUNT => {
                if self.message_count.small < SMALL_MESSAGE_COUNT {
                    self.messages.push(message);
                    self.message_count.small += 1;
                    Ok(())
                } else {
                    Err(MessagingError::TooManyMessages)
                }
            }
            MEDIUM_MESSAGE_COUNT => {
                if self.message_count.medium < MEDIUM_MESSAGE_COUNT {
                    self.messages.push(message);
                    self.message_count.medium += 1;
                    Ok(())
                } else {
                    Err(MessagingError::TooManyMessages)
                }
            }
            LARGE_MESSAGE_COUNT => {
                if self.message_count.large < LARGE_MESSAGE_COUNT {
                    self.messages.push(message);
                    self.message_count.large += 1;
                    Ok(())
                } else {
                    Err(MessagingError::TooManyMessages)
                }
            }
            HUGE_MESSAGE_COUNT => {
                if self.message_count.huge < HUGE_MESSAGE_COUNT {
                    self.messages.push(message);
                    self.message_count.huge += 1;
                    Ok(())
                } else {
                    return Err(MessagingError::TooManyMessages);
                }
            }
            _ => Err(MessagingError::MessageTooLarge),
        }
    }
}

/// A proper struct to list the number of messages in the mailbox
pub struct MessageCount {
    /// The number of tiny messages in the mailbox
    pub tiny: usize,
    /// The number of small messages in the mailbox
    pub small: usize,
    /// The number of medium messages in the mailbox
    pub medium: usize,
    /// The number of large messages in the mailbox
    pub large: usize,
    /// The number of huge messages in the mailbox
    pub huge: usize,
}

impl MessageCount {
    /// Return the total number of messages in the mailbox
    pub fn total(&self) -> usize {
        self.tiny + self.small + self.medium + self.large + self.huge
    }
}

impl Default for MessageCount {
    fn default() -> Self {
        MessageCount {
            tiny: 0,
            small: 0,
            medium: 0,
            large: 0,
            huge: 0,
        }
    }
}
