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
//! Contains the HandlerChain struct that manages all windows represented by
//! the IMessageHandler trait.

use std::cell::RefCell;
use std::fmt::Display;

use super::handlerchain_message::Message;
use super::handlerchain_imessagehandler_trait::IMessageHandler;

//-----------------------------------------------------------------------------

/// Represents the type of actions the process_message() method returns for the
/// HandlerChain::send_message() to act on.
pub enum MessageReturnTypes {
    /// Message was processed, stop further processing of the message.
    Stop,
    /// Continue with processing of the message.
    Continue,
    /// Window is closed, remove from handlers list and stop further processing
    /// of the message.
    Close,
}

//-----------------------------------------------------------------------------

/// Represents a list of handlers that all implement the IMessageHandler
/// trait.  This list can be dynamically updated and each element in
/// the list is passed messages for processing.
pub struct HandlerChain {
    /// The list of message handlers.
    message_handlers: Vec<Box<RefCell<dyn IMessageHandler>>>,
}

impl HandlerChain {
    /// Constructor.
    ///
    /// # Returns
    /// Returns a new instance of the HandlerChain struct.
    pub fn new() -> HandlerChain {
        HandlerChain {
            message_handlers: vec![],
        }
    }

    /// Add the given instance of the IMessageHandler interface to end of the
    /// list of handlers.
    /// 
    /// Normally this would guard against adding the same window twice, but this
    /// HandlerChain takes ownership of the window and therefore the same
    /// window can never be added twice to this HandlerChain.
    pub fn add_handler(&mut self, handler: impl IMessageHandler+'static) {
        self.message_handlers.push(Box::new(RefCell::new(handler)))
    }

    /// Remove an instance of the IMessageHandler interface from the list.
    /// 
    /// If the message handler is not in the list, the request to remove
    /// is ignored.
    pub fn remove_handler(&mut self, handler_id: i32) {
        let found_index = self.message_handlers.iter_mut().position(|x| x.borrow().id() == handler_id);
        if let Some(index) = found_index {
            self.message_handlers.remove(index);
        }
    }

    /// Send a message to each of the handlers in the list.
    ///
    /// # Parameters
    /// - message
    ///
    ///   The Message object to send to each handler.
    pub fn send_message(&mut self, message: &Message) {
        for handler in self.message_handlers.iter() {
            let result = handler.borrow_mut().process_message(&message);
            match result {
                MessageReturnTypes::Stop => break,
                MessageReturnTypes::Continue => continue,
                MessageReturnTypes::Close => { 
                    let handler_id = handler.borrow().id();
                    self.remove_handler(handler_id);
                    break;
                }
            }
        }
    }
}

impl Display for HandlerChain {
    /// Convert this HandlerChain to a string that is returned.
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // We make a copy of the handlers so our processing of handlers
        // is not impacted by updates to the master handler list.
        let mut output = String::new();
        for handler in self.message_handlers.iter() {
            output.push_str(&format!("    {}\n", handler.borrow().to_string()))
        }

        f.write_fmt(format_args!("{}", output))
    }
}