1 #pragma once
2 
3 #include "button_config.hpp"
4 #include "button_interface.hpp"
5 
6 #include <phosphor-logging/elog-errors.hpp>
7 
8 #include <unordered_map>
9 
10 using buttonIfCreatorMethod = std::function<std::unique_ptr<ButtonIface>(
11     sdbusplus::bus_t& bus, EventPtr& event, ButtonConfig& buttonCfg)>;
12 
13 /**
14  * @brief This is abstract factory for the creating phosphor buttons objects
15  * based on the button  / formfactor type given.
16  */
17 
18 class ButtonFactory
19 {
20   public:
instance()21     static ButtonFactory& instance()
22     {
23         static ButtonFactory buttonFactoryObj;
24         return buttonFactoryObj;
25     }
26 
27     /**
28      * @brief this method creates a key and value pair element
29      * for the given button interface where key is the form factor
30      * name and the value is lambda method to return
31      * the instance of the button interface.
32      * This key value pair is stored in the Map buttonIfaceRegistry.
33      */
34 
35     template <typename T>
addToRegistry()36     void addToRegistry()
37     {
38         buttonIfaceRegistry[T::getFormFactorName()] =
39             [](sdbusplus::bus_t& bus, EventPtr& event,
40                ButtonConfig& buttonCfg) {
41                 return std::make_unique<T>(bus, T::getDbusObjectPath().c_str(),
42                                            event, buttonCfg);
43             };
44     }
45 
46     template <typename T>
addToRegistry(size_t index)47     void addToRegistry(size_t index)
48     {
49         auto indexStr = std::to_string(index);
50         buttonIfaceRegistry[T::getFormFactorName() + indexStr] =
51             [=](sdbusplus::bus_t& bus, EventPtr& event,
52                 ButtonConfig& buttonCfg) {
53                 return std::make_unique<T>(
54                     bus, (T::getDbusObjectPath() + indexStr).c_str(), event,
55                     buttonCfg);
56             };
57     }
58 
59     /**
60      * @brief this method returns the button interface object
61      *    corresponding to the button formfactor name provided
62      */
63     std::unique_ptr<ButtonIface>
createInstance(const std::string & name,sdbusplus::bus_t & bus,EventPtr & event,ButtonConfig & buttonCfg)64         createInstance(const std::string& name, sdbusplus::bus_t& bus,
65                        EventPtr& event, ButtonConfig& buttonCfg)
66     {
67         // find matching name in the registry and call factory method.
68         auto objectIter = buttonIfaceRegistry.find(name);
69         if (objectIter != buttonIfaceRegistry.end())
70         {
71             return objectIter->second(bus, event, buttonCfg);
72         }
73         else
74         {
75             return nullptr;
76         }
77     }
78 
79   private:
80     // This map is the registry for keeping supported button interface types.
81     std::unordered_map<std::string, buttonIfCreatorMethod> buttonIfaceRegistry;
82 };
83 
84 template <class T>
85 class ButtonIFRegister
86 {
87   public:
ButtonIFRegister()88     ButtonIFRegister()
89     {
90         // register the class factory function
91         ButtonFactory::instance().addToRegistry<T>();
92     }
93 
ButtonIFRegister(size_t count)94     explicit ButtonIFRegister(size_t count)
95     {
96         // register the class factory function
97         // The index, 'countIter', starts at 1 and increments,
98         // representing slot_1 through slot_N.
99         for (size_t countIter = 1; countIter <= count; countIter++)
100         {
101             ButtonFactory::instance().addToRegistry<T>(countIter);
102         }
103     }
104 };
105