1<?php
2/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
3
4namespace Icinga\Module\Setup;
5
6use LogicException;
7
8abstract class Requirement
9{
10    /**
11     * The state of this requirement
12     *
13     * @var bool
14     */
15    protected $state;
16
17    /**
18     * A descriptive text representing the current state of this requirement
19     *
20     * @var string
21     */
22    protected $stateText;
23
24    /**
25     * The descriptions of this requirement
26     *
27     * @var array
28     */
29    protected $descriptions;
30
31    /**
32     * The title of this requirement
33     *
34     * @var string
35     */
36    protected $title;
37
38    /**
39     * The condition of this requirement
40     *
41     * @var mixed
42     */
43    protected $condition;
44
45    /**
46     * Whether this requirement is optional
47     *
48     * @var bool
49     */
50    protected $optional;
51
52    /**
53     * The alias to display the condition with in a human readable way
54     *
55     * @var string
56     */
57    protected $alias;
58
59    /**
60     * The text to display if the given requirement is fulfilled
61     *
62     * @var string
63     */
64    protected $textAvailable;
65
66    /**
67     * The text to display if the given requirement is not fulfilled
68     *
69     * @var string
70     */
71    protected $textMissing;
72
73    /**
74     * Create a new requirement
75     *
76     * @param   array   $options
77     *
78     * @throws  LogicException  In case there exists no setter for an option's key
79     */
80    public function __construct(array $options = array())
81    {
82        $this->optional = false;
83        $this->descriptions = array();
84
85        foreach ($options as $key => $value) {
86            $setMethod = 'set' . ucfirst($key);
87            $addMethod = 'add' . ucfirst($key);
88            if (method_exists($this, $setMethod)) {
89                $this->$setMethod($value);
90            } elseif (method_exists($this, $addMethod)) {
91                $this->$addMethod($value);
92            } else {
93                throw LogicException('No setter found for option key: ' . $key);
94            }
95        }
96    }
97
98    /**
99     * Set the state of this requirement
100     *
101     * @param   bool    $state
102     *
103     * @return  Requirement
104     */
105    public function setState($state)
106    {
107        $this->state = (bool) $state;
108        return $this;
109    }
110
111    /**
112     * Return the state of this requirement
113     *
114     * Evaluates the requirement in case there is no state set yet.
115     *
116     * @return  int
117     */
118    public function getState()
119    {
120        if ($this->state === null) {
121            $this->state = $this->evaluate();
122        }
123
124        return $this->state;
125    }
126
127    /**
128     * Set a descriptive text for this requirement's current state
129     *
130     * @param   string  $text
131     *
132     * @return  Requirement
133     */
134    public function setStateText($text)
135    {
136        $this->stateText = $text;
137        return $this;
138    }
139
140    /**
141     * Return a descriptive text for this requirement's current state
142     *
143     * @return  string
144     */
145    public function getStateText()
146    {
147        $state = $this->getState();
148        if ($this->stateText === null) {
149            return $state ? $this->getTextAvailable() : $this->getTextMissing();
150        }
151        return $this->stateText;
152    }
153
154    /**
155     * Add a description for this requirement
156     *
157     * @param   string  $description
158     *
159     * @return  Requirement
160     */
161    public function addDescription($description)
162    {
163        $this->descriptions[] = $description;
164        return $this;
165    }
166
167    /**
168     * Return the descriptions of this wizard
169     *
170     * @return  array
171     */
172    public function getDescriptions()
173    {
174        return $this->descriptions;
175    }
176
177    /**
178     * Set the title for this requirement
179     *
180     * @param   string  $title
181     *
182     * @return  Requirement
183     */
184    public function setTitle($title)
185    {
186        $this->title = $title;
187        return $this;
188    }
189
190    /**
191     * Return the title of this requirement
192     *
193     * In case there is no title set the alias is returned instead.
194     *
195     * @return  string
196     */
197    public function getTitle()
198    {
199        if ($this->title === null) {
200            return $this->getAlias();
201        }
202
203        return $this->title;
204    }
205
206    /**
207     * Set the condition for this requirement
208     *
209     * @param   mixed   $condition
210     *
211     * @return  Requirement
212     */
213    public function setCondition($condition)
214    {
215        $this->condition = $condition;
216        return $this;
217    }
218
219    /**
220     * Return the condition of this requirement
221     *
222     * @return  mixed
223     */
224    public function getCondition()
225    {
226        return $this->condition;
227    }
228
229    /**
230     * Set whether this requirement is optional
231     *
232     * @param   bool    $state
233     *
234     * @return  Requirement
235     */
236    public function setOptional($state = true)
237    {
238        $this->optional = (bool) $state;
239        return $this;
240    }
241
242    /**
243     * Return whether this requirement is optional
244     *
245     * @return  bool
246     */
247    public function isOptional()
248    {
249        return $this->optional;
250    }
251
252    /**
253     * Set the alias to display the condition with in a human readable way
254     *
255     * @param   string  $alias
256     *
257     * @return  Requirement
258     */
259    public function setAlias($alias)
260    {
261        $this->alias = $alias;
262        return $this;
263    }
264
265    /**
266     * Return the alias to display the condition with in a human readable way
267     *
268     * @return  string
269     */
270    public function getAlias()
271    {
272        return $this->alias;
273    }
274
275    /**
276     * Set the text to display if the given requirement is fulfilled
277     *
278     * @param   string  $textAvailable
279     *
280     * @return  Requirement
281     */
282    public function setTextAvailable($textAvailable)
283    {
284        $this->textAvailable = $textAvailable;
285        return $this;
286    }
287
288    /**
289     * Get the text to display if the given requirement is fulfilled
290     *
291     * @return  string
292     */
293    public function getTextAvailable()
294    {
295        return $this->textAvailable;
296    }
297
298    /**
299     * Set the text to display if the given requirement is not fulfilled
300     *
301     * @param   string  $textMissing
302     *
303     * @return  Requirement
304     */
305    public function setTextMissing($textMissing)
306    {
307        $this->textMissing = $textMissing;
308        return $this;
309    }
310
311    /**
312     * Get the text to display if the given requirement is not fulfilled
313     *
314     * @return  string
315     */
316    public function getTextMissing()
317    {
318        return $this->textMissing;
319    }
320
321    /**
322     * Evaluate this requirement and return whether it is fulfilled
323     *
324     * @return  bool
325     */
326    abstract protected function evaluate();
327
328    /**
329     * Return whether the given requirement equals this one
330     *
331     * @param   Requirement     $requirement
332     *
333     * @return  bool
334     */
335    public function equals(Requirement $requirement)
336    {
337        if ($requirement instanceof static) {
338            return $this->getCondition() === $requirement->getCondition();
339        }
340
341        return false;
342    }
343}
344