]> git.mxchange.org Git - core.git/blob - framework/main/classes/stacker/class_BaseStacker.php
d823829dbdf056acec015cd08e37b7e7cc0115ed
[core.git] / framework / main / classes / stacker / class_BaseStacker.php
1 <?php
2 // Own namespace
3 namespace Org\Mxchange\CoreFramework\Stack;
4
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Bootstrap\FrameworkBootstrap;
7 use Org\Mxchange\CoreFramework\Object\BaseFrameworkSystem;
8
9 // Import SPL stuff
10 use \BadMethodCallException;
11 use \InvalidArgumentException;
12
13 /**
14  * A general Stacker
15  *
16  * @author              Roland Haeder <webmaster@shipsimu.org>
17  * @version             0.0.0
18  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2022 Core Developer Team
19  * @license             GNU GPL 3.0 or any newer version
20  * @link                http://www.shipsimu.org
21  *
22  * This program is free software: you can redistribute it and/or modify
23  * it under the terms of the GNU General Public License as published by
24  * the Free Software Foundation, either version 3 of the License, or
25  * (at your option) any later version.
26  *
27  * This program is distributed in the hope that it will be useful,
28  * but WITHOUT ANY WARRANTY; without even the implied warranty of
29  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30  * GNU General Public License for more details.
31  *
32  * You should have received a copy of the GNU General Public License
33  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
34  */
35 abstract class BaseStacker extends BaseFrameworkSystem {
36         // Exception codes
37         const EXCEPTION_STACKER_ALREADY_INITIALIZED = 0x050;
38         const EXCEPTION_STACKER_IS_FULL             = 0x051;
39         const EXCEPTION_NO_STACKER_FOUND            = 0x052;
40         const EXCEPTION_STACKER_IS_EMPTY            = 0x053;
41
42         /**
43          * Array "caches" configuration entries for saving "expensive" method
44          * invocations
45          */
46         private $cachedMaxStackSizes = [];
47
48         /**
49          * Protected constructor
50          *
51          * @param       $className      Name of the class
52          * @return      void
53          */
54         protected function __construct (string $className) {
55                 // Call parent constructor
56                 parent::__construct($className);
57         }
58
59         /**
60          * Initializes given stacker
61          *
62          * @param       $stackerName    Name of the stack
63          * @param       $forceReInit    Force re-initialization
64          * @return      void
65          * @throws      InvalidArgumentException        If a parameter is invalid
66          * @throws      AlreadyInitializedStackerException      If the stack is already initialized
67          */
68         public function initStack (string $stackerName, bool $forceReInit = false) {
69                 // Validate parameter
70                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s,forceReInit=%d - CALLED!', $stackerName, intval($forceReInit)));
71                 if (empty($stackerName)) {
72                         // No empty stack name
73                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
74                 } elseif (($forceReInit === false) && ($this->isStackInitialized($stackerName))) {
75                         // Then throw the exception
76                         // @TODO Change to BMCE
77                         throw new AlreadyInitializedStackerException(array($this, $stackerName, $forceReInit), self::EXCEPTION_STACKER_ALREADY_INITIALIZED);
78                 }
79
80                 // Initialize the given stack and "cache" configuration entry
81                 $this->initGenericArrayKey('stacks', $stackerName, 'entries', $forceReInit);
82                 $this->cachedMaxStackSizes[$stackerName] = FrameworkBootstrap::getConfigurationInstance()->getConfigEntry(sprintf('stacker_%s_max_size', $stackerName));
83
84                 // Trace message
85                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-STACKER: EXIT!');
86         }
87
88         /**
89          * Initializes all stacks
90          *
91          * @return      void
92          * @throws      InvalidArgumentException        If a parameter is invalid
93          */
94         public function initStacks (array $stacks, bool $forceReInit = false) {
95                 // Validate parameter
96                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stacks()=%d,forceReInit=%d - CALLED!', count($stacks), intval($forceReInit)));
97                 if (count($stacks) == 0) {
98                         // No empty stack name
99                         throw new InvalidArgumentException('Array "stacks" is empty');
100                 }
101
102                 // "Walk" through all (more will be added as needed
103                 foreach ($stacks as $stackerName) {
104                         // Init this stack
105                         //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: Calling this->initStack(%s,%d) ...', $stackerName, intval($forceReInit)));
106                         $this->initStack($stackerName, $forceReInit);
107                 }
108
109                 // Trace message
110                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-STACKER: EXIT!');
111         }
112
113         /**
114          * Checks whether the given stack is initialized (set in array $stackers)
115          *
116          * @param       $stackerName    Name of the stack
117          * @return      $isInitialized  Whether the stack is initialized
118          * @throws      InvalidArgumentException        If a parameter is invalid
119          */
120         public function isStackInitialized (string $stackerName) {
121                 // Validate parameter
122                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
123                 if (empty($stackerName)) {
124                         // No empty stack name
125                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
126                 }
127
128                 // Is is there?
129                 $isInitialized = ($this->isValidGenericArrayKey('stacks', $stackerName, 'entries'));
130
131                 // Return result
132                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: isInitialized=%d - EXIT!', intval($isInitialized)));
133                 return $isInitialized;
134         }
135
136         /**
137          * Checks whether the given stack is full
138          *
139          * @param       $stackerName    Name of the stack
140          * @return      $isFull                 Whether the stack is full
141          * @throws      InvalidArgumentException        If a parameter is invalid
142          * @throws      BadMethodCallException  If given stack is missing
143          */
144         protected function isStackFull (string $stackerName) {
145                 // Validate parameter
146                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
147                 if (empty($stackerName)) {
148                         // No empty stack name
149                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
150                 } elseif (!$this->isStackInitialized($stackerName)) {
151                         // Throw an exception
152                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
153                 }
154
155                 // So, is the stack full?
156                 $isFull = (($this->getStackCount($stackerName)) == $this->cachedMaxStackSizes[$stackerName]);
157
158                 // Return result
159                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: isFull=%d - EXIT!', intval($isFull)));
160                 return $isFull;
161         }
162
163         /**
164          * Checks whether the given stack is empty
165          *
166          * @param       $stackerName            Name of the stack
167          * @return      $isEmpty                        Whether the stack is empty
168          * @throws      InvalidArgumentException        If a parameter is invalid
169          * @throws      BadMethodCallException  If given stack is missing
170          */
171         public function isStackEmpty (string $stackerName) {
172                 // Validate parameter
173                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
174                 if (empty($stackerName)) {
175                         // No empty stack name
176                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
177                 } elseif (!$this->isStackInitialized($stackerName)) {
178                         // Throw an exception
179                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
180                 }
181
182                 // So, is the stack empty?
183                 $isEmpty = (($this->getStackCount($stackerName)) == 0);
184
185                 // Return result
186                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: isEmpty=%d - EXIT!', intval($isEmpty)));
187                 return $isEmpty;
188         }
189
190         /**
191          * Getter for size of given stack (array count)
192          *
193          * @param       $stackerName    Name of the stack
194          * @return      $count                  Size of stack (array count)
195          * @throws      InvalidArgumentException        If a parameter is invalid
196          * @throws      BadMethodCallException  If given stack is missing
197          */
198         public function getStackCount (string $stackerName) {
199                 // Validate parameter
200                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
201                 if (empty($stackerName)) {
202                         // No empty stack name
203                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
204                 } elseif (!$this->isStackInitialized($stackerName)) {
205                         // Throw an exception
206                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
207                 }
208
209                 // Now, count the array of entries
210                 $count = $this->countGenericArrayElements('stacks', $stackerName, 'entries');
211
212                 // Return result
213                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: count=%d - EXIT!', $count));
214                 return $count;
215         }
216
217         /**
218          * Adds a value to given stack
219          *
220          * @param       $stackerName    Name of the stack
221          * @param       $value                  Value to add to this stacker
222          * @return      void
223          * @throws      InvalidArgumentException        If a parameter is invalid
224          * @throws      BadMethodCallException  If given stack is missing
225          * @throws      FullStackerException    Thrown if the stack is full
226          */
227         protected function addValueToStack (string $stackerName, $value) {
228                 // Validate parameter
229                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s,value[]=%s - CALLED!', $stackerName, gettype($value)));
230                 if (empty($stackerName)) {
231                         // No empty stack name
232                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
233                 } elseif (!$this->isStackInitialized($stackerName)) {
234                         // Throw an exception
235                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
236                 } elseif ($this->isStackFull($stackerName)) {
237                         // Stacker is full
238                         throw new FullStackerException([$this, $stackerName, $value], self::EXCEPTION_STACKER_IS_FULL);
239                 }
240
241                 // Now add the value to the stack
242                 $this->pushValueToGenericArrayKey('stacks', $stackerName, 'entries', $value);
243
244                 // Trace message
245                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-STACKER: EXIT!');
246         }
247
248         /**
249          * Get last value from named stacker
250          *
251          * @param       $stackerName    Name of the stack
252          * @return      $value                  Value of last added value
253          * @throws      InvalidArgumentException        If a parameter is invalid
254          * @throws      BadMethodCallException  If the named stacker was not found
255          * @throws      BadMethodCallException  If the named stacker is empty
256          */
257         protected function getLastValue (string $stackerName) {
258                 // Validate parameter
259                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
260                 if (empty($stackerName)) {
261                         // No empty stack name
262                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
263                 } elseif (!$this->isStackInitialized($stackerName)) {
264                         // Throw an exception
265                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
266                 } elseif ($this->isStackEmpty($stackerName)) {
267                         // Throw an exception
268                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
269                 }
270
271                 // Now get the last value
272                 $value = $this->getGenericArrayElement('stacks', $stackerName, 'entries', $this->getStackCount($stackerName) - 1);
273
274                 // Return it
275                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));
276                 return $value;
277         }
278
279         /**
280          * Get first value from named stacker
281          *
282          * @param       $stackerName    Name of the stack
283          * @return      $value                  Value of last added value
284          * @throws      InvalidArgumentException        If a parameter is invalid
285          * @throws      BadMethodCallException  If the named stacker was not found
286          * @throws      BadMethodCallException  If the named stacker is empty
287          */
288         protected function getFirstValue (string $stackerName) {
289                 // Validate parameter
290                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
291                 if (empty($stackerName)) {
292                         // No empty stack name
293                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
294                 } elseif (!$this->isStackInitialized($stackerName)) {
295                         // Throw an exception
296                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
297                 } elseif ($this->isStackEmpty($stackerName)) {
298                         // Throw an exception
299                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
300                 }
301
302                 // Now get the first value
303                 $value = $this->getGenericArrayElement('stacks', $stackerName, 'entries', 0);
304
305                 // Return it
306                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));
307                 return $value;
308         }
309
310         /**
311          * "Pops" last entry from stack
312          *
313          * @param       $stackerName    Name of the stack
314          * @return      $value                  Value "poped" from array
315          * @throws      InvalidArgumentException        If a parameter is invalid
316          * @throws      BadMethodCallException  If the named stacker was not found
317          * @throws      BadMethodCallException  If the named stacker is empty
318          */
319         protected function popLast (string $stackerName) {
320                 // Validate parameter
321                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
322                 if (empty($stackerName)) {
323                         // No empty stack name
324                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
325                 } elseif (!$this->isStackInitialized($stackerName)) {
326                         // Throw an exception
327                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
328                 } elseif ($this->isStackEmpty($stackerName)) {
329                         // Throw an exception
330                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
331                 }
332
333                 // Now, remove the last entry, we don't care about the return value here, see elseif() block above
334                 $value = $this->popGenericArrayElement('stacks', $stackerName, 'entries');
335
336                 // Return it
337                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));
338                 return $value;
339         }
340
341         /**
342          * "Pops" first entry from stack
343          *
344          * @param       $stackerName    Name of the stack
345          * @return      $value                  Value "shifted" from array
346          * @throws      InvalidArgumentException        If a parameter is invalid
347          * @throws      BadMethodCallException  If the named stacker was not found
348          * @throws      BadMethodCallException  If the named stacker is empty
349          */
350         protected function popFirst (string $stackerName) {
351                 // Validate parameter
352                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
353                 if (empty($stackerName)) {
354                         // No empty stack name
355                         throw new InvalidArgumentException('Parameter "stackerName" is empty');
356                 } elseif (!$this->isStackInitialized($stackerName)) {
357                         // Throw an exception
358                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
359                 } elseif ($this->isStackEmpty($stackerName)) {
360                         // Throw an exception
361                         throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
362                 }
363
364                 // Now, remove the last entry, we don't care about the return value here, see elseif() block above
365                 $value = $this->shiftGenericArrayElement('stacks', $stackerName, 'entries');
366
367                 // Return it
368                 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));
369                 return $value;
370         }
371
372 }