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