Merge 0.10->trunk
[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_remove = table.remove;
13 local t_sort = table.sort;
14 local setmetatable = setmetatable;
15 local next = next;
16
17 local _ENV = nil;
18
19 local function new()
20         local handlers = {};
21         local global_wrappers;
22         local wrappers = {};
23         local event_map = {};
24         local function _rebuild_index(handlers, event)
25                 local _handlers = event_map[event];
26                 if not _handlers or next(_handlers) == nil then return; end
27                 local index = {};
28                 for handler in pairs(_handlers) do
29                         t_insert(index, handler);
30                 end
31                 t_sort(index, function(a, b) return _handlers[a] > _handlers[b]; end);
32                 handlers[event] = index;
33                 return index;
34         end;
35         setmetatable(handlers, { __index = _rebuild_index });
36         local function add_handler(event, handler, priority)
37                 local map = event_map[event];
38                 if map then
39                         map[handler] = priority or 0;
40                 else
41                         map = {[handler] = priority or 0};
42                         event_map[event] = map;
43                 end
44                 handlers[event] = nil;
45         end;
46         local function remove_handler(event, handler)
47                 local map = event_map[event];
48                 if map then
49                         map[handler] = nil;
50                         handlers[event] = nil;
51                         if next(map) == nil then
52                                 event_map[event] = nil;
53                         end
54                 end
55         end;
56         local function get_handlers(event)
57                 return handlers[event];
58         end;
59         local function add_handlers(handlers)
60                 for event, handler in pairs(handlers) do
61                         add_handler(event, handler);
62                 end
63         end;
64         local function remove_handlers(handlers)
65                 for event, handler in pairs(handlers) do
66                         remove_handler(event, handler);
67                 end
68         end;
69         local function _fire_event(event_name, event_data)
70                 local h = handlers[event_name];
71                 if h then
72                         for i=1,#h do
73                                 local ret = h[i](event_data);
74                                 if ret ~= nil then return ret; end
75                         end
76                 end
77         end;
78         local function fire_event(event_name, event_data)
79                 local w = wrappers[event_name] or global_wrappers;
80                 if w then
81                         local curr_wrapper = #w;
82                         local function c(event_name, event_data)
83                                 curr_wrapper = curr_wrapper - 1;
84                                 if curr_wrapper == 0 then
85                                         if global_wrappers == nil or w == global_wrappers then
86                                                 return _fire_event(event_name, event_data);
87                                         end
88                                         w, curr_wrapper = global_wrappers, #global_wrappers;
89                                         return w[curr_wrapper](c, event_name, event_data);
90                                 else
91                                         return w[curr_wrapper](c, event_name, event_data);
92                                 end
93                         end
94                         return w[curr_wrapper](c, event_name, event_data);
95                 end
96                 return _fire_event(event_name, event_data);
97         end
98         local function add_wrapper(event_name, wrapper)
99                 local w;
100                 if event_name == false then
101                         w = global_wrappers;
102                         if not w then
103                                 w = {};
104                                 global_wrappers = w;
105                         end
106                 else
107                         w = wrappers[event_name];
108                         if not w then
109                                 w = {};
110                                 wrappers[event_name] = w;
111                         end
112                 end
113                 w[#w+1] = wrapper;
114         end
115         local function remove_wrapper(event_name, wrapper)
116                 local w;
117                 if event_name == false then
118                         w = global_wrappers;
119                 else
120                         w = wrappers[event_name];
121                 end
122                 if not w then return; end
123                 for i = #w, 1 do
124                         if w[i] == wrapper then
125                                 t_remove(w, i);
126                         end
127                 end
128                 if #w == 0 then
129                         if event_name == nil then
130                                 global_wrappers = nil;
131                         else
132                                 wrappers[event_name] = nil;
133                         end
134                 end
135         end
136         return {
137                 add_handler = add_handler;
138                 remove_handler = remove_handler;
139                 add_handlers = add_handlers;
140                 remove_handlers = remove_handlers;
141                 get_handlers = get_handlers;
142                 wrappers = {
143                         add_handler = add_wrapper;
144                         remove_handler = remove_wrapper;
145                 };
146                 add_wrapper = add_wrapper;
147                 remove_wrapper = remove_wrapper;
148                 fire_event = fire_event;
149                 _handlers = handlers;
150                 _event_map = event_map;
151         };
152 end
153
154 return {
155         new = new;
156 };