aboutsummaryrefslogtreecommitdiff
path: root/src/crepe/api/EventManager.h
blob: d3a14dad8e056e77a7d8c99aea5bbfd1f56be631 (plain)
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
#pragma once

#include <memory>
#include <unordered_map>
#include <vector>
#include <functional>
#include <typeindex>
#include <type_traits>

#include "Event.h"
#include "EventHandler.h"

/**
 * \class EventManager
 * \brief The EventManager class is responsible for managing the subscription, triggering, 
 * and queueing of events. It handles events and dispatches them to appropriate subscribers.
 */
class EventManager {
public:
    /**
     * \brief Deleted copy constructor to prevent copying of the EventManager instance.
     */
    EventManager(const EventManager &) = delete;

    /**
     * \brief Deleted copy assignment operator to prevent assignment of the EventManager instance.
     */
    const EventManager & operator=(const EventManager &) = delete;

    /**
     * \brief Get the singleton instance of the EventManager.
     * 
     * This method returns the unique instance of the EventManager, creating it on the first call.
     * 
     * \return Reference to the EventManager instance.
     */
    static EventManager & get_instance() {
        static EventManager instance;
        return instance;
    }

    /**
     * \brief Subscribe to an event.
     * 
     * This method allows the registration of a callback for a specific event type and channel.
     * 
     * \tparam EventType The type of the event to subscribe to.
     * \param callback The callback function to invoke when the event is triggered.
     * \param channel The channel number to subscribe to (default is 0).
     */
    template <typename EventType>
    void subscribe(EventHandler<EventType> && callback, int channel = 0);

    /**
     * \brief Unsubscribe from an event.
     * 
     * This method removes a previously registered callback from an event.
     * 
     * \tparam EventType The type of the event to unsubscribe from.
     * \param callback The callback function to remove from the subscription list.
     * \param channel The event ID to unsubscribe from.
     */
    template <typename EventType>
    void unsubscribe(const EventHandler<EventType> &, int channel);

    /**
     * \brief Trigger an event.
     * 
     * This method invokes the appropriate callback(s) for the specified event.
     * 
     * \tparam EventType The type of the event to trigger.
     * \param event The event data to pass to the callback.
     * \param channel The channel from which to trigger the event (default is 0).
     */
    template <typename EventType>
    void trigger_event(const EventType & event, int channel);

    /**
     * \brief Queue an event for later processing.
     * 
     * This method adds an event to the event queue, which will be processed in the 
     * dispatch_events function.
     * 
     * \tparam EventType The type of the event to queue.
     * \param event The event to queue.
     * \param channel The channel number for the event (default is 0).
     */
    template <typename EventType>
    void queue_event(EventType&& event, int channel);

    /**
     * \brief Dispatch all queued events.
     * 
     * This method processes all events in the event queue and triggers the corresponding 
     * callbacks for each event.
     */
    void dispatch_events();

private:
    /**
     * \brief Default constructor for the EventManager.
     * 
     * This constructor is private to enforce the singleton pattern.
     */
    EventManager() = default;

    //! The queue of events to be processed.
    std::vector<std::tuple<std::unique_ptr<Event>, int, std::type_index>> events_queue; 
	//! Registered event handlers.
    std::unordered_map<std::type_index, std::vector<std::unique_ptr<IEventHandlerWrapper>>> subscribers; 
	//! Event handlers indexed by event ID.
    std::unordered_map<std::type_index, std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>> subscribers_by_event_id; 
};

template <typename EventType>
void EventManager::subscribe(EventHandler<EventType> && callback, int channel) {
    std::type_index event_type = typeid(EventType);
    std::unique_ptr<EventHandlerWrapper<EventType>> handler = std::make_unique<EventHandlerWrapper<EventType>>(callback);
    
    if (channel) {
        std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>& handlers_map = this->subscribers_by_event_id[event_type];
        std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>::iterator handlers = handlers_map.find(channel);
        if (handlers != handlers_map.end()) {
            handlers->second.emplace_back(std::move(handler));
        } else {
            handlers_map[channel].emplace_back(std::move(handler));
        }
    } else {
        std::vector<std::unique_ptr<IEventHandlerWrapper>>& handlers = this->subscribers[event_type];
        handlers.emplace_back(std::move(handler));
    }
}

template <typename EventType>
void EventManager::queue_event(EventType&& event, int channel) {
    std::type_index event_type = std::type_index(typeid(EventType));
    
    std::unique_ptr<EventType> event_ptr = std::make_unique<EventType>(std::forward<EventType>(event));

    std::tuple<std::unique_ptr<Event>, int, std::type_index> tuple(
        std::move(event_ptr),
        channel,
        event_type
    );
    this->events_queue.push_back(std::move(tuple));
}

template <typename EventType>
void EventManager::trigger_event(const EventType & event, int channel) {
    std::type_index event_type = std::type_index(typeid(EventType));
    
    if (channel > 0) {
        std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>& handlers_map = subscribers_by_event_id[event_type];
        std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>::iterator handlers_it = handlers_map.find(channel);
        
        if (handlers_it != handlers_map.end()) {
            std::vector<std::unique_ptr<IEventHandlerWrapper>>& handlers = handlers_it->second;
            for (std::vector<std::unique_ptr<IEventHandlerWrapper>>::iterator it = handlers.begin(); it != handlers.end();) {
				// erases callback if callback function returns true
                if ((*it)->exec(event)) {
                    it = handlers.erase(it);
                } else {
                    ++it;
                }
            }
        }
    } else {
        std::vector<std::unique_ptr<IEventHandlerWrapper>>& handlers = subscribers[event_type];
        for (std::vector<std::unique_ptr<IEventHandlerWrapper>>::iterator it = handlers.begin(); it != handlers.end();) {
			// erases callback if callback function returns true
             if ((*it)->exec(event)) {
                    it = handlers.erase(it);
            } else {
                    ++it;
             }
        }
    }
}

template <typename EventType>
void EventManager::unsubscribe(const EventHandler<EventType> & callback, int channel) {
    std::type_index event_type(typeid(EventType));
    std::string handler_name = callback.target_type().name();

    if (channel) {
        std::unordered_map<std::type_index, std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>>::iterator subscriber_list = this->subscribers_by_event_id.find(event_type);
        if (subscriber_list != this->subscribers_by_event_id.end()) {
            std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>& handlers_map = subscriber_list->second;
            std::unordered_map<int, std::vector<std::unique_ptr<IEventHandlerWrapper>>>::iterator handlers = handlers_map.find(channel);
            if (handlers != handlers_map.end()) {
                std::vector<std::unique_ptr<IEventHandlerWrapper>>& callbacks = handlers->second;
                for (std::vector<std::unique_ptr<IEventHandlerWrapper>>::iterator it = callbacks.begin(); it != callbacks.end(); ++it) {
                    if ((*it)->get_type() == handler_name) {
                        it = callbacks.erase(it);
                        return;
                    }
                }
            }
        }
    } else {
        std::unordered_map<std::type_index, std::vector<std::unique_ptr<IEventHandlerWrapper>>>::iterator handlers_it = this->subscribers.find(event_type);
        if (handlers_it != this->subscribers.end()) {
            std::vector<std::unique_ptr<IEventHandlerWrapper>>& handlers = handlers_it->second;
            for (std::vector<std::unique_ptr<IEventHandlerWrapper>>::iterator it = handlers.begin(); it != handlers.end(); ++it) {
                if ((*it)->get_type() == handler_name) {
                    it = handlers.erase(it);
                    return;
                }
            }
        }
    }
}