1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
 * message.rs
 *
 * Holds the Message struct and other important structs and aliases:
 *   ColorStringQueue
 *   ColorString
 *   ColorChar
 */

use std::fmt;
use std::collections::VecDeque;
use std::convert::TryInto;

use pancurses::{chtype, A_BOLD, COLOR_PAIR};

// MessageQueue struct
// Holds many messages waiting to be used
pub struct MessageQueue {
    data: VecDeque<Message>,
    pub closed: bool,            // Do we recycle data?
}

impl MessageQueue {
    pub fn new(capacity: usize, closed: bool) -> Self {
	Self{data: VecDeque::with_capacity(capacity), closed}
    }
    pub fn pop(&mut self) -> Option<Message> { // pop from queue, check if we need to recycle
	let message_check = self.data.front(); // front() is used so data doesn't leave
	if message_check.is_none() {           // until it's safe (for updating)
	    return None;
	}
	
	if self.closed {
	    self.push(self.data.front().unwrap().clone());
	}
	self.data.pop_front()
    }
    pub fn push(&mut self, message: Message) {
	self.data.push_back(message);
    }
    pub fn push_update(&mut self, message: Message) {
	// Check through current messages
	// If there's one with the same ID, update the contents
	// else, push normally
	if let Some(compare_msg) = self.data.iter_mut().rev().find(|cmp| cmp.id == message.id) { // starting from the back is recycle-pop safe
	    compare_msg.contents = message.contents;
	} else {
	    self.push(message);
	}
    }
    pub fn append(&mut self, mut messages: VecDeque<Message>){
	self.data.append(&mut messages);
    }
    pub fn append_update(&mut self, messages: VecDeque<Message>){
	messages.into_iter().for_each(|message| self.push_update(message));
    }
    pub fn drain(&mut self) -> VecDeque<Message> {
	self.data.drain(..).collect::<VecDeque<Message>>()
    }
}

pub type ColorString = Vec<ColorChar>;

#[derive(Copy, Clone)]
pub struct ColorChar {
    pub data: u32,
    pub attr: chtype
}

impl ColorChar {
    pub fn new(data: u32, attr: chtype) -> Self {
	Self{data, attr}
    }
}

impl fmt::Debug for ColorChar {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_tuple("")
         .field(&(self.data as u8 as char))
         .field(&self.attr)
         .finish()
    }
}

// Message struct
// Holds basic info about a message
pub struct Message {
    pub contents: ColorString,
    pub id:       String,
}

impl Message {
    pub fn new(contents: ColorString, id: &str) -> Self {
	Self{contents, id: id.to_string()}
    }
    pub fn new_simple(string: &str, pair: i16, id: &str) -> Self {
	let mut contents = ColorString::with_capacity(string.len());
	for i in 0..string.len() {
	    contents.push(ColorChar::new(string.as_bytes()[i] as u32, COLOR_PAIR(pair.try_into().unwrap())));
	}
	Self::new(contents, id)
    }
    pub fn new_with_title(title: &str, body: &str, pair: i16, id: &str) -> Self { // creates new from body, title, and id
	let color = COLOR_PAIR(pair.try_into().unwrap());
	let mut contents = ColorString::with_capacity(title.len()+body.len());
	for i in 0..title.len() {
	    contents.push(ColorChar::new(title.as_bytes()[i] as u32, color | A_BOLD));
	}
	for i in 0..body.len() {
	    contents.push(ColorChar::new(body.as_bytes()[i] as u32, color));
	}
	Self::new(contents, id)
    }
    pub fn len(&self) -> usize {
	self.contents.len()
    }
}

impl Clone for Message {
    fn clone(&self) -> Message {
	Message::new(self.contents.clone(), &self.id.clone())
    }
}