Add Grouped behaviour.
[command.git] / include / grouped.h
1 #ifndef __COMMAND_GROUPED_H
2 #define __COMMAND_GROUPED_H
3
4 #include <iostream>
5 #include <vector>
6 #include <string>
7
8 #include "parameter.h"
9 #include "exception/missingRequiredParameter.h"
10
11 namespace command {
12     /**
13      * Grouped Parameters decorator. Allows Parameters to understand be grouped
14      * together.
15      *
16      * Example usage:
17      *  - ./myprog [ARGUMENT OPTION] [ARGUMENT OPTION] ...
18      */
19     class Grouped : public Parameter {
20     protected:
21         /**
22          * Parameters which will be treated as grouped together
23          */
24         std::vector<Parameter *> parameters;
25
26         std::vector<std::string> values;
27
28         std::vector<bool> understood;
29         std::vector<bool> all_used;
30
31     public:
32         /**
33          * Default constructor.
34          *
35          * @param params Parameters which will be treated as grouped together
36          */
37         Grouped(std::initializer_list<Parameter *> params, std::string description = "Grouped")
38             : Parameter(description), parameters(params) {
39             for (unsigned int i = 0; i < parameters.size(); i++) {
40                 understood.push_back(false);
41                 values.push_back("");
42             }
43         }
44
45         /**
46          * Default destructor. Releases allocated memory
47          */
48         virtual ~Grouped() {
49             releaseMemory();
50         }
51
52         /**
53          * Wrapper method around passed Parameter::handle().
54          *
55          * \inheritdoc
56          */
57         virtual void handle() {
58 //                 std::cout << this->describe() << " handles" << "\n";
59 //             if (!isUsed()) {
60                 for (unsigned int i = 0; i < parameters.size(); i++) {
61                     Parameter *param = parameters[i];
62                     if (understood[i] ||  param->hungryForValue()) {
63 //                     std::cout << param->describe() << "=" << values[i] << "\n";
64                         param->handle();
65                     }
66                 }
67 //             }
68             // @TODO: Nested required
69             for(Parameter *param : parameters) {
70                 if (param->isRequired() && !param->isUsed()) {
71                     throw MissingRequiredParameter(param->describe() + " is required");
72                 }
73             }
74         }
75
76         /**
77          * Wrapper method around passed Parameter::understand()
78          *
79          * @param argv command line value against which test will be made
80          *
81          * \inheritdoc
82          */
83         virtual bool understand(const std::string & value) {
84 //             std::cout << "[+] Grouped [" << this->describe() << "]\n";
85
86             bool _understand = false;
87
88 //             std::cout << "GMD\n" ;
89             for (unsigned int i = 0; i < parameters.size(); i++) {
90                 Parameter *param = parameters[i];
91
92 //                 std::cout << " > Grouped:Param [" << param->describe() << ", " << value << "]\n";
93                 if (!understood[i]) {
94                     _understand = param->understand(value);
95                     if (_understand) {
96 //                         std::cout << " > Understood [" << param->describe() << ", " << value << "]\n";
97                         understood[i] = _understand;
98                         values[i] = value;
99                         break;
100                     }
101                 }
102             }
103
104             bool all_understood = (understood.size() == parameters.size());
105             for (bool u : understood) {
106                 all_understood &= u;
107             }
108
109 //             std::cout << this->describe() << " understand: " << std::boolalpha << all_understood << "\n";
110
111             return all_understood;
112         }
113
114         /**
115          * Indicates if current Parameter has been already used
116          *
117          * @return true if current Parameter has been already used. False otherwise.
118          */
119 //         virtual bool isUsed() {
120 //             if (!used) {
121 // //                 bool used 
122 //                 for(Parameter *param : parameters) {
123 //                     param->isUsed();
124 //                 }
125 //             }
126 //         }
127
128         /**
129          * \inheritdoc
130          */
131         virtual bool hungryForValue() {
132             return true;
133         }
134
135         /**
136          * Wrapper method around passed Parameter::valuePosition().
137          *
138          * \inheritdoc
139          */
140         virtual unsigned int valuePosition(const std::string &) {
141             throw std::logic_error("Group does not have value part");
142         }
143
144         /**
145          * Releases acquired memory
146          */
147         void releaseMemory() {
148             for (Parameter * parameter : parameters) {
149                 if (parameter != NULL) {
150                     delete parameter;
151                 }
152             }
153             parameters.clear();
154             parameters.shrink_to_fit();
155         }
156     };
157 }
158
159 #endif /* __COMMAND_GROUPED_H */