Merge with backout
[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 ipairs = ipairs;
11 local pairs = pairs;
12 local t_insert = table.insert;
13 local t_sort = table.sort;
14 local select = select;
15
16 module "events"
17
18 function new()
19         local dispatchers = {};
20         local handlers = {};
21         local event_map = {};
22         local function _rebuild_index(event) -- TODO optimize index rebuilding
23                 local _handlers = event_map[event];
24                 local index = handlers[event];
25                 if index then
26                         for i=#index,1,-1 do index[i] = nil; end
27                 else index = {}; handlers[event] = index; end
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         end;
33         local function add_handler(event, handler, priority)
34                 local map = event_map[event];
35                 if map then
36                         map[handler] = priority or 0;
37                 else
38                         map = {[handler] = priority or 0};
39                         event_map[event] = map;
40                 end
41                 _rebuild_index(event);
42         end;
43         local function remove_handler(event, handler)
44                 local map = event_map[event];
45                 if map then
46                         map[handler] = nil;
47                         _rebuild_index(event);
48                 end
49         end;
50         local function add_handlers(handlers)
51                 for event, handler in pairs(handlers) do
52                         add_handler(event, handler);
53                 end
54         end;
55         local function remove_handlers(handlers)
56                 for event, handler in pairs(handlers) do
57                         remove_handler(event, handler);
58                 end
59         end;
60         local function _create_dispatcher(event) -- FIXME duplicate code in fire_event
61                 local h = handlers[event];
62                 if not h then h = {}; handlers[event] = h; end
63                 local dispatcher = function(...)
64                         for i=1,#h do
65                                 local ret = h[i](...);
66                                 if ret ~= nil then return ret; end
67                         end
68                 end;
69                 dispatchers[event] = dispatcher;
70                 return dispatcher;
71         end;
72         local function get_dispatcher(event)
73                 return dispatchers[event] or _create_dispatcher(event);
74         end;
75         local function fire_event(event, ...) -- FIXME duplicates dispatcher code
76                 local h = handlers[event];
77                 if h then
78                         for i=1,#h do
79                                 local ret = h[i](...);
80                                 if ret ~= nil then return ret; end
81                         end
82                 end
83         end;
84         local function get_named_arg_dispatcher(event, ...)
85                 local dispatcher = get_dispatcher(event);
86                 local keys = {...};
87                 local data = {};
88                 return function(...)
89                         for i, key in ipairs(keys) do data[key] = select(i, ...); end
90                         dispatcher(data);
91                 end;
92         end;
93         return {
94                 add_handler = add_handler;
95                 remove_handler = remove_handler;
96                 add_plugin = add_plugin;
97                 remove_plugin = remove_plugin;
98                 get_dispatcher = get_dispatcher;
99                 fire_event = fire_event;
100                 get_named_arg_dispatcher = get_named_arg_dispatcher;
101                 _dispatchers = dispatchers;
102                 _handlers = handlers;
103                 _event_map = event_map;
104         };
105 end
106
107 return _M;