util.events: Add get_handlers() method
[prosody.git] / util / events.lua
1 -- Prosody IM
2 -- Copyright (C) 2008-2010 Matthew Wild
3 -- Copyright (C) 2008-2010 Waqas Hussain
4 --
5 -- This project is MIT/X11 licensed. Please see the
6 -- COPYING file in the source package for more information.
7 --
8
9
10 local pairs = pairs;
11 local t_insert = table.insert;
12 local t_sort = table.sort;
13 local setmetatable = setmetatable;
14 local next = next;
15
16 module "events"
17
18 function new()
19         local handlers = {};
20         local global_wrappers;
21         local wrappers = {};
22         local event_map = {};
23         local function _rebuild_index(handlers, event)
24                 local _handlers = event_map[event];
25                 if not _handlers or next(_handlers) == nil then return; end
26                 local index = {};
27                 for handler in pairs(_handlers) do
28                         t_insert(index, handler);
29                 end
30                 t_sort(index, function(a, b) return _handlers[a] > _handlers[b]; end);
31                 handlers[event] = index;
32                 return index;
33         end;
34         setmetatable(handlers, { __index = _rebuild_index });
35         local function add_handler(event, handler, priority)
36                 local map = event_map[event];
37                 if map then
38                         map[handler] = priority or 0;
39                 else
40                         map = {[handler] = priority or 0};
41                         event_map[event] = map;
42                 end
43                 handlers[event] = nil;
44         end;
45         local function remove_handler(event, handler)
46                 local map = event_map[event];
47                 if map then
48                         map[handler] = nil;
49                         handlers[event] = nil;
50                         if next(map) == nil then
51                                 event_map[event] = nil;
52                         end
53                 end
54         end;
55         local function get_handlers(event)
56                 return handlers[event];
57         end;
58         local function add_handlers(handlers)
59                 for event, handler in pairs(handlers) do
60                         add_handler(event, handler);
61                 end
62         end;
63         local function remove_handlers(handlers)
64                 for event, handler in pairs(handlers) do
65                         remove_handler(event, handler);
66                 end
67         end;
68         local function _fire_event(event_name, event_data)
69                 local h = handlers[event_name];
70                 if h then
71                         for i=1,#h do
72                                 local ret = h[i](event_data);
73                                 if ret ~= nil then return ret; end
74                         end
75                 end
76         end;
77         local function fire_event(event_name, event_data)
78                 local w = wrappers[event_name] or global_wrappers;
79                 if w then
80                         local curr_wrapper = #w;
81                         local function c(event_name, event_data)
82                                 curr_wrapper = curr_wrapper - 1;
83                                 if curr_wrapper == 0 then
84                                         if global_wrappers == nil or w == global_wrappers then
85                                                 return _fire_event(event_name, event_data);
86                                         end
87                                         w, curr_wrapper = global_wrappers, #global_wrappers;
88                                         return w[curr_wrapper](c, event_name, event_data);
89                                 else
90                                         return w[curr_wrapper](c, event_name, event_data);
91                                 end
92                         end
93                         return w[curr_wrapper](c, event_name, event_data);
94                 end
95                 return _fire_event(event_name, event_data);
96         end
97         local function add_wrapper(event_name, wrapper)
98                 local w;
99                 if event_name == false then
100                         w = global_wrappers;
101                         if not w then
102                                 w = {};
103                                 global_wrappers = w;
104                         end
105                 else
106                         w = wrappers[event_name];
107                         if not w then
108                                 w = {};
109                                 wrappers[event_name] = w;
110                         end
111                 end
112                 w[#w+1] = wrapper;
113         end
114         local function remove_wrapper(event_name, wrapper)
115                 local w;
116                 if event_name == false then
117                         w = global_wrappers;
118                 else
119                         w = wrappers[event_name];
120                 end
121                 if not w then return; end
122                 for i = #w, 1 do
123                         if w[i] == wrapper then
124                                 table.remove(w, i);
125                         end
126                 end
127                 if #w == 0 then
128                         if event_name == nil then
129                                 global_wrappers = nil;
130                         else
131                                 wrappers[event_name] = nil;
132                         end
133                 end
134         end
135         return {
136                 add_handler = add_handler;
137                 remove_handler = remove_handler;
138                 add_handlers = add_handlers;
139                 remove_handlers = remove_handlers;
140                 get_handlers = get_handlers;
141                 wrappers = {
142                         add_handler = add_wrapper;
143                         remove_handler = remove_wrapper;
144                 };
145                 add_wrapper = add_wrapper;
146                 remove_wrapper = remove_wrapper;
147                 fire_event = fire_event;
148                 _handlers = handlers;
149                 _event_map = event_map;
150         };
151 end
152
153 return _M;