1 public final class ModuleRegistry: Sequence {
2   public typealias Element = ModuleHolder
3 
4   private weak var appContext: AppContext?
5 
6   private var registry: [String: ModuleHolder] = [:]
7 
8   init(appContext: AppContext) {
9     self.appContext = appContext
10   }
11 
12   /**
13    Registers an instance of module holder.
14    */
15   internal func register(holder: ModuleHolder) {
16     log.info("Registering module '\(holder.name)'")
17     registry[holder.name] = holder
18   }
19 
20   /**
21    Registers a module by its type.
22    */
23   public func register(moduleType: AnyModule.Type) {
24     guard let appContext = appContext else {
25       return
26     }
27     let module = moduleType.init(appContext: appContext)
28     let holder = ModuleHolder(appContext: appContext, module: module)
29     register(holder: holder)
30   }
31 
32   /**
33    Registers modules exported by given modules provider.
34    */
35   public func register(fromProvider provider: ModulesProviderProtocol) {
36     provider.getModuleClasses().forEach { moduleType in
37       register(moduleType: moduleType)
38     }
39   }
40 
41   /**
42    Unregisters given module from the registry.
43    */
44   public func unregister(module: AnyModule) {
45     if let index = registry.firstIndex(where: { $1.module === module }) {
46       registry.remove(at: index)
47     }
48   }
49 
50   public func unregister(moduleName: String) {
51     if registry[moduleName] != nil {
52       log.info("Unregistering module '\(moduleName)'")
53       registry[moduleName] = nil
54     }
55   }
56 
57   public func has(moduleWithName moduleName: String) -> Bool {
58     return registry[moduleName] != nil
59   }
60 
61   public func get(moduleHolderForName moduleName: String) -> ModuleHolder? {
62     return registry[moduleName]
63   }
64 
65   public func get(moduleWithName moduleName: String) -> AnyModule? {
66     return registry[moduleName]?.module
67   }
68 
69   public func getModuleNames() -> [String] {
70     return Array(registry.keys)
71   }
72 
73   public func makeIterator() -> IndexingIterator<[ModuleHolder]> {
74     return registry.map({ $1 }).makeIterator()
75   }
76 
77   internal func post(event: EventName) {
78     log.info("Posting '\(event)' event to registered modules")
79     forEach { holder in
80       holder.post(event: event)
81     }
82   }
83 
84   internal func post<PayloadType>(event: EventName, payload: PayloadType? = nil) {
85     log.info("Posting '\(event)' event to registered modules")
86     forEach { holder in
87       holder.post(event: event, payload: payload)
88     }
89   }
90 }
91