3 namespace Org\Mxchange\CoreFramework\Stack;
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Bootstrap\FrameworkBootstrap;
7 use Org\Mxchange\CoreFramework\Object\BaseFrameworkSystem;
10 use \BadMethodCallException;
11 use \InvalidArgumentException;
16 * @author Roland Haeder <webmaster@shipsimu.org>
18 * @copyright Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2020 Core Developer Team
19 * @license GNU GPL 3.0 or any newer version
20 * @link http://www.shipsimu.org
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.
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.
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/>.
35 abstract class BaseStacker extends BaseFrameworkSystem {
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;
43 * Protected constructor
45 * @param $className Name of the class
48 protected function __construct (string $className) {
49 // Call parent constructor
50 parent::__construct($className);
54 * Initializes given stacker
56 * @param $stackerName Name of the stack
57 * @param $forceReInit Force re-initialization
59 * @throws InvalidArgumentException If a parameter is invalid
60 * @throws AlreadyInitializedStackerException If the stack is already initialized
62 public function initStack (string $stackerName, bool $forceReInit = false) {
64 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s,forceReInit=%d - CALLED!', $stackerName, intval($forceReInit)));
65 if (empty($stackerName)) {
66 // No empty stack name
67 throw new InvalidArgumentException('Parameter "stackerName" is empty');
68 } elseif (($forceReInit === false) && ($this->isStackInitialized($stackerName))) {
69 // Then throw the exception
70 // @TODO Change to BMCE
71 throw new AlreadyInitializedStackerException(array($this, $stackerName, $forceReInit), self::EXCEPTION_STACKER_ALREADY_INITIALIZED);
74 // Initialize the given stack
75 $this->initGenericArrayKey('stacks', $stackerName, 'entries', $forceReInit);
78 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-STACKER: EXIT!');
82 * Initializes all stacks
85 * @throws InvalidArgumentException If a parameter is invalid
87 public function initStacks (array $stacks, bool $forceReInit = false) {
89 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stacks()=%d,forceReInit=%d - CALLED!', count($stacks), intval($forceReInit)));
90 if (count($stacks) == 0) {
91 // No empty stack name
92 throw new InvalidArgumentException('Array "stacks" is empty');
95 // "Walk" through all (more will be added as needed
96 foreach ($stacks as $stackerName) {
98 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: Calling this->initStack(%s,%d) ...', $stackerName, intval($forceReInit)));
99 $this->initStack($stackerName, $forceReInit);
103 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-STACKER: EXIT!');
107 * Checks whether the given stack is initialized (set in array $stackers)
109 * @param $stackerName Name of the stack
110 * @return $isInitialized Whether the stack is initialized
111 * @throws InvalidArgumentException If a parameter is invalid
113 public function isStackInitialized (string $stackerName) {
114 // Validate parameter
115 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
116 if (empty($stackerName)) {
117 // No empty stack name
118 throw new InvalidArgumentException('Parameter "stackerName" is empty');
122 $isInitialized = ($this->isValidGenericArrayKey('stacks', $stackerName, 'entries'));
125 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: isInitialized=%d - EXIT!', intval($isInitialized)));
126 return $isInitialized;
130 * Checks whether the given stack is full
132 * @param $stackerName Name of the stack
133 * @return $isFull Whether the stack is full
134 * @throws InvalidArgumentException If a parameter is invalid
135 * @throws BadMethodCallException If given stack is missing
137 protected function isStackFull (string $stackerName) {
138 // Validate parameter
139 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
140 if (empty($stackerName)) {
141 // No empty stack name
142 throw new InvalidArgumentException('Parameter "stackerName" is empty');
143 } elseif (!$this->isStackInitialized($stackerName)) {
144 // Throw an exception
145 throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
148 // So, is the stack full?
149 $isFull = (($this->getStackCount($stackerName)) == FrameworkBootstrap::getConfigurationInstance()->getConfigEntry('stacker_' . $stackerName . '_max_size'));
152 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: isFull=%d - EXIT!', intval($isFull)));
157 * Checks whether the given stack is empty
159 * @param $stackerName Name of the stack
160 * @return $isEmpty Whether the stack is empty
161 * @throws InvalidArgumentException If a parameter is invalid
162 * @throws BadMethodCallException If given stack is missing
164 public function isStackEmpty (string $stackerName) {
165 // Validate parameter
166 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
167 if (empty($stackerName)) {
168 // No empty stack name
169 throw new InvalidArgumentException('Parameter "stackerName" is empty');
170 } elseif (!$this->isStackInitialized($stackerName)) {
171 // Throw an exception
172 throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
175 // So, is the stack empty?
176 $isEmpty = (($this->getStackCount($stackerName)) == 0);
179 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: isEmpty=%d - EXIT!', intval($isEmpty)));
184 * Getter for size of given stack (array count)
186 * @param $stackerName Name of the stack
187 * @return $count Size of stack (array count)
188 * @throws InvalidArgumentException If a parameter is invalid
189 * @throws BadMethodCallException If given stack is missing
191 public function getStackCount (string $stackerName) {
192 // Validate parameter
193 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
194 if (empty($stackerName)) {
195 // No empty stack name
196 throw new InvalidArgumentException('Parameter "stackerName" is empty');
197 } elseif (!$this->isStackInitialized($stackerName)) {
198 // Throw an exception
199 throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
202 // Now, count the array of entries
203 $count = $this->countGenericArrayElements('stacks', $stackerName, 'entries');
206 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: count=%d - EXIT!', $count));
211 * Adds a value to given stack
213 * @param $stackerName Name of the stack
214 * @param $value Value to add to this stacker
216 * @throws InvalidArgumentException If a parameter is invalid
217 * @throws BadMethodCallException If given stack is missing
218 * @throws FullStackerException Thrown if the stack is full
220 protected function addValue (string $stackerName, $value) {
221 // Validate parameter
222 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s,value[]=%s - CALLED!', $stackerName, gettype($value)));
223 if (empty($stackerName)) {
224 // No empty stack name
225 throw new InvalidArgumentException('Parameter "stackerName" is empty');
226 } elseif (!$this->isStackInitialized($stackerName)) {
227 // Throw an exception
228 throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
229 } elseif ($this->isStackFull($stackerName)) {
231 throw new FullStackerException([$this, $stackerName, $value], self::EXCEPTION_STACKER_IS_FULL);
234 // Now add the value to the stack
235 $this->pushValueToGenericArrayKey('stacks', $stackerName, 'entries', $value);
238 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput('BASE-STACKER: EXIT!');
242 * Get last value from named stacker
244 * @param $stackerName Name of the stack
245 * @return $value Value of last added value
246 * @throws InvalidArgumentException If a parameter is invalid
247 * @throws BadMethodCallException If the named stacker was not found
248 * @throws BadMethodCallException If the named stacker is empty
250 protected function getLastValue (string $stackerName) {
251 // Validate parameter
252 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
253 if (empty($stackerName)) {
254 // No empty stack name
255 throw new InvalidArgumentException('Parameter "stackerName" is empty');
256 } elseif (!$this->isStackInitialized($stackerName)) {
257 // Throw an exception
258 throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
259 } elseif ($this->isStackEmpty($stackerName)) {
260 // Throw an exception
261 throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
264 // Now get the last value
265 $value = $this->getGenericArrayElement('stacks', $stackerName, 'entries', $this->getStackCount($stackerName) - 1);
268 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));
273 * Get first value from named stacker
275 * @param $stackerName Name of the stack
276 * @return $value Value of last added value
277 * @throws InvalidArgumentException If a parameter is invalid
278 * @throws BadMethodCallException If the named stacker was not found
279 * @throws BadMethodCallException If the named stacker is empty
281 protected function getFirstValue (string $stackerName) {
282 // Validate parameter
283 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
284 if (empty($stackerName)) {
285 // No empty stack name
286 throw new InvalidArgumentException('Parameter "stackerName" is empty');
287 } elseif (!$this->isStackInitialized($stackerName)) {
288 // Throw an exception
289 throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
290 } elseif ($this->isStackEmpty($stackerName)) {
291 // Throw an exception
292 throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
295 // Now get the first value
296 $value = $this->getGenericArrayElement('stacks', $stackerName, 'entries', 0);
299 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));
304 * "Pops" last entry from stack
306 * @param $stackerName Name of the stack
307 * @return $value Value "poped" from array
308 * @throws InvalidArgumentException If a parameter is invalid
309 * @throws BadMethodCallException If the named stacker was not found
310 * @throws BadMethodCallException If the named stacker is empty
312 protected function popLast (string $stackerName) {
313 // Validate parameter
314 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
315 if (empty($stackerName)) {
316 // No empty stack name
317 throw new InvalidArgumentException('Parameter "stackerName" is empty');
318 } elseif (!$this->isStackInitialized($stackerName)) {
319 // Throw an exception
320 throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
321 } elseif ($this->isStackEmpty($stackerName)) {
322 // Throw an exception
323 throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
326 // Now, remove the last entry, we don't care about the return value here, see elseif() block above
327 $value = $this->popGenericArrayElement('stacks', $stackerName, 'entries');
330 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));
335 * "Pops" first entry from stack
337 * @param $stackerName Name of the stack
338 * @return $value Value "shifted" from array
339 * @throws InvalidArgumentException If a parameter is invalid
340 * @throws BadMethodCallException If the named stacker was not found
341 * @throws BadMethodCallException If the named stacker is empty
343 protected function popFirst (string $stackerName) {
344 // Validate parameter
345 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: stackerName=%s - CALLED!', $stackerName));
346 if (empty($stackerName)) {
347 // No empty stack name
348 throw new InvalidArgumentException('Parameter "stackerName" is empty');
349 } elseif (!$this->isStackInitialized($stackerName)) {
350 // Throw an exception
351 throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_NO_STACKER_FOUND);
352 } elseif ($this->isStackEmpty($stackerName)) {
353 // Throw an exception
354 throw new BadMethodCallException(sprintf('stackerName=%s not yet initialized but method called.', $stackerName), self::EXCEPTION_STACKER_IS_EMPTY);
357 // Now, remove the last entry, we don't care about the return value here, see elseif() block above
358 $value = $this->shiftGenericArrayElement('stacks', $stackerName, 'entries');
361 //* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugOutput(sprintf('BASE-STACKER: value[]=%s - EXIT!', gettype($value)));