]> git.mxchange.org Git - core.git/blob - framework/main/classes/class_BaseFrameworkSystem.php
Continued:
[core.git] / framework / main / classes / class_BaseFrameworkSystem.php
1 <?php
2 // Own namespace
3 namespace Org\Mxchange\CoreFramework\Object;
4
5 // Import framework stuff
6 use Org\Mxchange\CoreFramework\Bootstrap\FrameworkBootstrap;
7 use Org\Mxchange\CoreFramework\EntryPoint\ApplicationEntryPoint;
8 use Org\Mxchange\CoreFramework\Factory\Object\ObjectFactory;
9 use Org\Mxchange\CoreFramework\Filesystem\FileIoException;
10 use Org\Mxchange\CoreFramework\Filesystem\PathWriteProtectedException;
11 use Org\Mxchange\CoreFramework\Generic\FrameworkInterface;
12 use Org\Mxchange\CoreFramework\Generic\NullPointerException;
13 use Org\Mxchange\CoreFramework\Generic\UnsupportedOperationException;
14 use Org\Mxchange\CoreFramework\Helper\Application\ApplicationHelper;
15 use Org\Mxchange\CoreFramework\Loader\ClassLoader;
16 use Org\Mxchange\CoreFramework\Manager\ManageableApplication;
17 use Org\Mxchange\CoreFramework\Middleware\Debug\DebugMiddleware;
18 use Org\Mxchange\CoreFramework\Registry\GenericRegistry;
19 use Org\Mxchange\CoreFramework\Result\Database\CachedDatabaseResult;
20 use Org\Mxchange\CoreFramework\State\Stateable;
21 use Org\Mxchange\CoreFramework\Stream\Output\OutputStreamer;
22 use Org\Mxchange\CoreFramework\Utils\Strings\StringUtils;
23
24 // Import SPL stuff
25 use \BadMethodCallException;
26 use \InvalidArgumentException;
27 use \ReflectionClass;
28 use \SplFileInfo;
29 use \stdClass;
30
31 /**
32  * The simulator system class is the super class of all other classes. This
33  * class handles saving of games etc.
34  *
35  * @author              Roland Haeder <webmaster@shipsimu.org>
36  * @version             0.0.0
37  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 - 2023 Core Developer Team
38  * @license             GNU GPL 3.0 or any newer version
39  * @link                http://www.shipsimu.org
40  *
41  * This program is free software: you can redistribute it and/or modify
42  * it under the terms of the GNU General Public License as published by
43  * the Free Software Foundation, either version 3 of the License, or
44  * (at your option) any later version.
45  *
46  * This program is distributed in the hope that it will be useful,
47  * but WITHOUT ANY WARRANTY; without even the implied warranty of
48  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
49  * GNU General Public License for more details.
50  *
51  * You should have received a copy of the GNU General Public License
52  * along with this program. If not, see <http://www.gnu.org/licenses/>.
53  */
54 abstract class BaseFrameworkSystem extends stdClass implements FrameworkInterface {
55         /**
56          * Self-referencing instance
57          */
58         private static $selfInstance = NULL;
59
60         /**
61          * Debug instance
62          */
63         private static $debugInstance = NULL;
64
65         /**
66          * Stub methods
67          */
68         private static $stubMethods = [
69                 'partialStub' => true,
70                 '__call' => true,
71                 '__callStatic' => true,
72         ];
73
74         /**
75          * The real class name
76          */
77         private $realClass = __CLASS__;
78
79         /**
80          * Call-back instance
81          */
82         private $callbackInstance = NULL;
83
84         /**
85          * Generic array
86          */
87         private $genericArray = [];
88
89         /***********************
90          * Exception codes.... *
91          ***********************/
92
93         // @todo Try to clean these constants up
94         const EXCEPTION_IS_NULL_POINTER              = 0x001;
95         const EXCEPTION_IS_NO_OBJECT                 = 0x002;
96         const EXCEPTION_IS_NO_ARRAY                  = 0x003;
97         const EXCEPTION_MISSING_METHOD               = 0x004;
98         const EXCEPTION_CLASSES_NOT_MATCHING         = 0x005;
99         const EXCEPTION_INDEX_OUT_OF_BOUNDS          = 0x006;
100         const EXCEPTION_DIMENSION_ARRAY_INVALID      = 0x007;
101         const EXCEPTION_ITEM_NOT_TRADEABLE           = 0x008;
102         const EXCEPTION_ITEM_NOT_IN_PRICE_LIST       = 0x009;
103         const EXCEPTION_GENDER_IS_WRONG              = 0x00a;
104         const EXCEPTION_BIRTH_DATE_IS_INVALID        = 0x00b;
105         const EXCEPTION_EMPTY_STRUCTURES_ARRAY       = 0x00c;
106         const EXCEPTION_HAS_ALREADY_PERSONELL_LIST   = 0x00d;
107         const EXCEPTION_NOT_ENOUGTH_UNEMPLOYEES      = 0x00e;
108         const EXCEPTION_TOTAL_PRICE_NOT_CALCULATED   = 0x00f;
109         const EXCEPTION_HARBOR_HAS_NO_SHIPYARDS      = 0x010;
110         const EXCEPTION_CONTRACT_PARTNER_INVALID     = 0x011;
111         const EXCEPTION_CONTRACT_PARTNER_MISMATCH    = 0x012;
112         const EXCEPTION_CONTRACT_ALREADY_SIGNED      = 0x013;
113         const EXCEPTION_UNEXPECTED_EMPTY_STRING      = 0x014;
114         const EXCEPTION_PATH_NOT_FOUND               = 0x015;
115         const EXCEPTION_INVALID_PATH_NAME            = 0x016;
116         const EXCEPTION_READ_PROTECED_PATH           = 0x017;
117         const EXCEPTION_WRITE_PROTECED_PATH          = 0x018;
118         const EXCEPTION_DIR_POINTER_INVALID          = 0x019;
119         const EXCEPTION_FILE_POINTER_INVALID         = 0x01a;
120         const EXCEPTION_INVALID_RESOURCE             = 0x01b;
121         const EXCEPTION_UNEXPECTED_OBJECT            = 0x01c;
122         const EXCEPTION_LIMIT_ELEMENT_IS_UNSUPPORTED = 0x01d;
123         const EXCEPTION_GETTER_IS_MISSING            = 0x01e;
124         const EXCEPTION_ARRAY_EXPECTED               = 0x01f;
125         const EXCEPTION_ARRAY_HAS_INVALID_COUNT      = 0x020;
126         const EXCEPTION_ID_IS_INVALID_FORMAT         = 0x021;
127         const EXCEPTION_MD5_CHECKSUMS_MISMATCH       = 0x022;
128         const EXCEPTION_UNEXPECTED_STRING_SIZE       = 0x023;
129         const EXCEPTION_SIMULATOR_ID_INVALID         = 0x024;
130         const EXCEPTION_MISMATCHING_COMPRESSORS      = 0x025;
131         const EXCEPTION_CONTAINER_ITEM_IS_NULL       = 0x026;
132         const EXCEPTION_ITEM_IS_NO_ARRAY             = 0x027;
133         const EXCEPTION_CONTAINER_MAYBE_DAMAGED      = 0x028;
134         const EXCEPTION_INVALID_STRING               = 0x029;
135         const EXCEPTION_VARIABLE_NOT_SET             = 0x02a;
136         const EXCEPTION_ATTRIBUTES_ARE_MISSING       = 0x02b;
137         const EXCEPTION_ARRAY_ELEMENTS_MISSING       = 0x02c;
138         const EXCEPTION_TEMPLATE_ENGINE_UNSUPPORTED  = 0x02d;
139         const EXCEPTION_FACTORY_REQUIRE_PARAMETER    = 0x02e;
140         const EXCEPTION_MISSING_ELEMENT              = 0x02f;
141         const EXCEPTION_HEADERS_ALREADY_SENT         = 0x030;
142         const EXCEPTION_DEFAULT_CONTROLLER_GONE      = 0x031;
143         const EXCEPTION_CLASS_NOT_FOUND              = 0x032;
144         const EXCEPTION_REQUIRED_INTERFACE_MISSING   = 0x033;
145         const EXCEPTION_FATAL_ERROR                  = 0x034;
146         const EXCEPTION_FILE_NOT_FOUND               = 0x035;
147         const EXCEPTION_ASSERTION_FAILED             = 0x036;
148         const EXCEPTION_FILE_NOT_REACHABLE           = 0x037;
149         const EXCEPTION_FILE_CANNOT_BE_READ          = 0x038;
150         const EXCEPTION_FILE_CANNOT_BE_WRITTEN       = 0x039;
151         const EXCEPTION_PATH_CANNOT_BE_WRITTEN       = 0x03a;
152         const EXCEPTION_DATABASE_UPDATED_NOT_ALLOWED = 0x03b;
153         const EXCEPTION_FILTER_CHAIN_INTERCEPTED     = 0x03c;
154         const EXCEPTION_INVALID_SOCKET               = 0x03d;
155         const EXCEPTION_SELF_INSTANCE                = 0x03e;
156
157         /**
158          * Startup time in miliseconds
159          */
160         private static $startupTime = 0;
161
162         /**
163          * Protected super constructor
164          *
165          * @param       $className      Name of the class
166          * @return      void
167          */
168         protected function __construct (string $className) {
169                 // Set real class
170                 $this->setRealClass($className);
171
172                 // Is the startup time set? (0 cannot be true anymore)
173                 if (self::$startupTime == 0) {
174                         // Then set it
175                         self::$startupTime = microtime(true);
176                 }
177         }
178
179         /**
180          * Destructor for all classes. You should not call this method on your own.
181          *
182          * @return      void
183          */
184         public function __destruct () {
185                 // Is this object already destroyed?
186                 if ($this->__toString() != 'DestructedObject') {
187                         // Destroy all informations about this class but keep some text about it alive
188                         $this->setRealClass('DestructedObject');
189                 } elseif ((defined('DEBUG_DESTRUCTOR')) && (is_object($this->getDebugInstance()))) {
190                         // Already destructed object
191                         self::createDebugInstance(__CLASS__, __LINE__)->warningMessage(sprintf('The object <span class="object_name">%s</span> is already destroyed.',
192                                 $this->__toString()
193                         ));
194                 } else {
195                         // Do not call this twice
196                         trigger_error(__METHOD__ . ': Called twice.');
197                         exit(255);
198                 }
199         }
200
201         /**
202          * The __call() method where all non-implemented methods end up
203          *
204          * @param       $methodName             Name of the missing method
205          * @args        $args                   Arguments passed to the method
206          * @return      void
207          */
208         public final function __call (string $methodName, array $args = NULL) {
209                 // Set self-instance
210                 self::$selfInstance = $this;
211
212                 // Call static method
213                 self::__callStatic($methodName, $args);
214
215                 // Clear self-instance
216                 self::$selfInstance = NULL;
217         }
218
219         /**
220          * The __callStatic() method where all non-implemented static methods end up
221          *
222          * @param       $methodName             Name of the missing method
223          * @param       $args                   Arguments passed to the method
224          * @return      void
225          * @throws      InvalidArgumentException If self::$selfInstance is not a framework's own object
226          */
227         public static final function __callStatic (string $methodName, array $args = NULL) {
228                 // Init argument string and class name
229                 //* PRINT-DEBUG: */ printf('[%s:%d]: methodName=%s,args[]=%s - CALLED!' . PHP_EOL, __METHOD__, __LINE__, $methodName, gettype($args));
230                 $argsString = '';
231                 $className = 'unknown';
232
233                 // Is self-instance set?
234                 if (self::$selfInstance instanceof FrameworkInterface) {
235                         // Framework's own instance
236                         $className = self::$selfInstance->__toString();
237                 } elseif (!is_null(self::$selfInstance)) {
238                         // Invalid argument!
239                         throw new InvalidArgumentException(sprintf('self::instance[%s] is not expected.', gettype(self::$selfInstance)), self::EXCEPTION_SELF_INSTANCE);
240                 }
241
242                 // Is it NULL, empty or an array?
243                 if (is_null($args)) {
244                         // No arguments
245                         $argsString = 'NULL';
246                 } elseif (is_array($args)) {
247                         // Start braces
248                         $argsString = '(';
249
250                         // Some arguments are there
251                         foreach ($args as $arg) {
252                                 // Add data about the argument
253                                 $argsString .= gettype($arg) . ':';
254
255                                 if (is_null($arg)) {
256                                         // Found a NULL argument
257                                         $argsString .= 'NULL';
258                                 } elseif (is_string($arg)) {
259                                         // Add length for strings
260                                         $argsString .= strlen($arg);
261                                 } elseif ((is_int($arg)) || (is_float($arg))) {
262                                         // ... integer/float
263                                         $argsString .= $arg;
264                                 } elseif (is_array($arg)) {
265                                         // .. or size if array
266                                         $argsString .= count($arg);
267                                 } elseif (is_object($arg)) {
268                                         // Get reflection
269                                         $reflection = new ReflectionClass($arg);
270
271                                         // Is an other object, maybe no __toString() available
272                                         $argsString .= $reflection->getName();
273                                 } elseif ($arg === true) {
274                                         // ... is boolean 'true'
275                                         $argsString .= 'true';
276                                 } elseif ($arg === false) {
277                                         // ... is boolean 'false'
278                                         $argsString .= 'false';
279                                 }
280
281                                 // Comma for next one
282                                 $argsString .= ', ';
283                         }
284
285                         // Last comma found?
286                         if (substr($argsString, -2, 1) == ',') {
287                                 // Remove last comma
288                                 $argsString = substr($argsString, 0, -2);
289                         }
290
291                         // Close braces
292                         $argsString .= ')';
293                 }
294
295                 // Output stub message
296                 // @TODO __CLASS__ does always return BaseFrameworkSystem but not the extending (=child) class
297                 self::createDebugInstance(__CLASS__, __LINE__)->warningMessage(sprintf('[%s::%s]: Stub! Args: %s',
298                         $className,
299                         $methodName,
300                         $argsString
301                 ));
302
303                 // Return nothing
304                 return NULL;
305         }
306
307         /**
308          * Getter for $realClass
309          *
310          * @return      $realClass The name of the real class (not BaseFrameworkSystem)
311          */
312         public function __toString () {
313                 return $this->realClass;
314         }
315
316         /**
317          * Magic method to catch setting of missing but set class fields/attributes
318          *
319          * @param       $name   Name of the field/attribute
320          * @param       $value  Value to store
321          * @return      void
322          */
323         public final function __set (string $name, $value) {
324                 $this->debugBackTrace(sprintf('Tried to set a missing field. name=%s, value[%s]=%s',
325                         $name,
326                         gettype($value),
327                         print_r($value, true)
328                 ));
329         }
330
331         /**
332          * Magic method to catch getting of missing fields/attributes
333          *
334          * @param       $name   Name of the field/attribute
335          * @return      void
336          */
337         public final function __get (string $name) {
338                 $this->debugBackTrace(sprintf('Tried to get a missing field. name=%s',
339                         $name
340                 ));
341         }
342
343         /**
344          * Magic method to catch unsetting of missing fields/attributes
345          *
346          * @param       $name   Name of the field/attribute
347          * @return      void
348          */
349         public final function __unset (string $name) {
350                 $this->debugBackTrace(sprintf('Tried to unset a missing field. name=%s',
351                         $name
352                 ));
353         }
354
355         /**
356          * Magic method to catch object serialization
357          *
358          * @return      $unsupported    Unsupported method
359          * @throws      UnsupportedOperationException   Objects of this framework cannot be serialized
360          */
361         public final function __sleep () {
362                 throw new UnsupportedOperationException([$this, __FUNCTION__], FrameworkInterface::EXCEPTION_UNSPPORTED_OPERATION);
363         }
364
365         /**
366          * Magic method to catch object deserialization
367          *
368          * @return      $unsupported    Unsupported method
369          * @throws      UnsupportedOperationException   Objects of this framework cannot be serialized
370          */
371         public final function __wakeup () {
372                 throw new UnsupportedOperationException([$this, __FUNCTION__], FrameworkInterface::EXCEPTION_UNSPPORTED_OPERATION);
373         }
374
375         /**
376          * Magic method to catch calls when an object instance is called
377          *
378          * @return      $unsupported    Unsupported method
379          * @throws      UnsupportedOperationException   Objects of this framework cannot be serialized
380          */
381         public final function __invoke () {
382                 throw new UnsupportedOperationException([$this, __FUNCTION__], FrameworkInterface::EXCEPTION_UNSPPORTED_OPERATION);
383         }
384
385         /**
386          * Setter for the real class name
387          *
388          * @param       $realClass      Class name (string)
389          * @return      void
390          */
391         public final function setRealClass (string $realClass) {
392                 // Set real class
393                 $this->realClass = $realClass;
394         }
395
396         /**
397          * Setter for debug instance
398          *
399          * @param       $debugInstance  The instance for debug output class
400          * @return      void
401          */
402         public final function setDebugInstance (DebugMiddleware $debugInstance) {
403                 self::$debugInstance = $debugInstance;
404         }
405
406         /**
407          * Getter for debug instance
408          *
409          * @return      $debugInstance  Instance to class DebugConsoleOutput or DebugWebOutput
410          */
411         public final function getDebugInstance () {
412                 return self::$debugInstance;
413         }
414
415         /**
416          * Setter for web output instance
417          *
418          * @param       $webInstance    The instance for web output class
419          * @return      void
420          */
421         public final function setWebOutputInstance (OutputStreamer $webInstance) {
422                 GenericRegistry::getRegistry()->addInstance('web_output', $webInstance);
423         }
424
425         /**
426          * Getter for web output instance
427          *
428          * @return      $webOutputInstance - Instance to class WebOutput
429          */
430         public final function getWebOutputInstance () {
431                 return GenericRegistry::getRegistry()->getInstance('web_output');
432         }
433
434         /**
435          * Setter for call-back instance
436          *
437          * @param       $callbackInstance       An instance of a FrameworkInterface class
438          * @return      void
439          */
440         public final function setCallbackInstance (FrameworkInterface $callbackInstance) {
441                 $this->callbackInstance = $callbackInstance;
442         }
443
444         /**
445          * Getter for call-back instance
446          *
447          * @return      $callbackInstance       An instance of a FrameworkInterface class
448          */
449         protected final function getCallbackInstance () {
450                 return $this->callbackInstance;
451         }
452
453         /**
454          * Checks whether an object equals this object. You should overwrite this
455          * method to implement own equality checks
456          *
457          * @param       $objectInstance         An instance of a FrameworkInterface object
458          * @return      $equals                         Whether both objects equals
459          */
460         public function equals (FrameworkInterface $objectInstance) {
461                 // Now test it
462                 $equals = ((
463                         $this->__toString() == $objectInstance->__toString()
464                 ) && (
465                         $this->hashCode() == $objectInstance->hashCode()
466                 ));
467
468                 // Return the result
469                 return $equals;
470         }
471
472         /**
473          * Generates a generic hash code of this class. You should really overwrite
474          * this method with your own hash code generator code. But keep KISS in mind.
475          *
476          * @return      $hashCode       A generic hash code respresenting this whole class
477          */
478         public function hashCode () {
479                 // Simple hash code
480                 return crc32($this->__toString());
481         }
482
483         /**
484          * Appends a trailing slash to a string
485          *
486          * @param       $str    A string (maybe) without trailing slash
487          * @return      $str    A string with an auto-appended trailing slash
488          */
489         public final function addMissingTrailingSlash (string $str) {
490                 // Is there a trailing slash?
491                 if (substr($str, -1, 1) != '/') {
492                         $str .= '/';
493                 }
494
495                 // Return string with trailing slash
496                 return $str;
497         }
498
499         /**
500          * Debugs this instance by putting out it's full content
501          *
502          * @param       $message        Optional message to show in debug output
503          * @return      void
504          */
505         public final function debugInstance (string $message = '') {
506                 // Restore the error handler to avoid trouble with missing array elements or undeclared variables
507                 restore_error_handler();
508
509                 // Init content
510                 $content = '';
511
512                 // Is a message set?
513                 if (!empty($message)) {
514                         // Construct message
515                         $content = sprintf('<div class="debug_message">
516         Message: %s
517 </div>' . PHP_EOL, $message);
518                 }
519
520                 // Generate the output
521                 $content .= sprintf('<pre>%s</pre>',
522                         trim(
523                                 htmlentities(
524                                         print_r($this, true)
525                                 )
526                         )
527                 );
528
529                 // Output it
530                 ApplicationEntryPoint::exitApplication(sprintf('<div class="debug_header">
531         %s debug output:
532 </div>
533 <div class="debug_content">
534         %s
535 </div>
536 Loaded includes:
537 <div class="debug_include_list">
538         %s
539 </div>',
540                         $this->__toString(),
541                         $content,
542                         ClassLoader::getSelfInstance()->getPrintableIncludeList()
543                 ));
544         }
545
546         /**
547          * Outputs a debug backtrace and stops further script execution
548          *
549          * @param       $message        An optional message to output
550          * @param       $doExit         Whether exit the program (true is default)
551          * @return      void
552          */
553         public function debugBackTrace (string $message = '', bool $doExit = true) {
554                 // Sorry, there is no other way getting this nice backtrace
555                 if (!empty($message)) {
556                         // Output message
557                         printf('Message: %s<br />' . PHP_EOL, $message);
558                 }
559
560                 print('<pre>');
561                 debug_print_backtrace();
562                 print('</pre>');
563
564                 // Exit program?
565                 if ($doExit === true) {
566                         exit();
567                 }
568         }
569
570         /**
571          * Creates an instance of a debugger instance
572          *
573          * @param       $className              Name of the class (currently unsupported)
574          * @param       $lineNumber             Line number where the call was made
575          * @return      $debugInstance  An instance of a debugger class
576          * @throws      InvalidArgumentException        If a parameter has an invalid value
577          * @deprecated  Not fully, as the new Logger facilities are not finished yet.
578          */
579         public final static function createDebugInstance (string $className, int $lineNumber = NULL) {
580                 // Validate parameter
581                 //* NOISY-DEBUG: */ printf('[%s:%d]: className=%s,lineNumber[%s]=%d - CALLED!' . PHP_EOL, __METHOD__, __LINE__, $className, gettype($lineNumber), $lineNumber);
582                 if (empty($className)) {
583                         // Throw IAE
584                         throw new InvalidArgumentException('Parameter "className" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
585                 }
586
587                 // Is the debug instance set?
588                 //* NOISY-DEBUG: */ printf('[%s:%d]: self::debugInstance[]=%s' . PHP_EOL, __METHOD__, __LINE__, gettype(self::$debugInstance));
589                 if (is_null(self::$debugInstance)) {
590                         // Init debug instance
591                         self::$debugInstance = NULL;
592
593                         // Try it
594                         try {
595                                 // Get a debugger instance
596                                 //* NOISY-DEBUG: */ printf('[%s:%d]: className=%s' . PHP_EOL, __METHOD__, __LINE__, $className);
597                                 self::$debugInstance = DebugMiddleware::createDebugMiddleware(FrameworkBootstrap::getConfigurationInstance()->getConfigEntry('debug_' . FrameworkBootstrap::getRequestTypeFromSystem() . '_class'), $className);
598                         } catch (NullPointerException $e) {
599                                 // Didn't work, no instance there
600                                 exit(sprintf('[%s:%d]: Cannot create debugInstance! Exception=%s,message=%s,className=%s,lineNumber=%d' . PHP_EOL, __METHOD__, __LINE__, $e->__toString(), $e->getMessage(), $className, $lineNumber));
601                         }
602                 }
603
604                 // Return it
605                 //* NOISY-DEBUG: */ printf('[%s:%d]: self::debugInstance=%s - EXIT!' . PHP_EOL, __METHOD__, __LINE__, self::$debugInstance->__toString());
606                 return self::$debugInstance;
607         }
608
609         /**
610          * Simple output of a message with line-break
611          *
612          * @param       $message        Message to output
613          * @return      void
614          */
615         public function outputLine (string $message) {
616                 // Simply output it
617                 print($message . PHP_EOL);
618         }
619
620         /**
621          * Marks up the code by adding e.g. line numbers
622          *
623          * @param       $phpCode                Unmarked PHP code
624          * @return      $markedCode             Marked PHP code
625          */
626         public function markupCode (string $phpCode) {
627                 // Init marked code
628                 $markedCode = '';
629
630                 // Get last error
631                 $errorArray = error_get_last();
632
633                 // Init the code with error message
634                 if (is_array($errorArray)) {
635                         // Get error infos
636                         $markedCode = sprintf('<div id="error_header">File: <span id="error_data">%s</span>, Line: <span id="error_data">%s</span>, Message: <span id="error_data">%s</span>, Type: <span id="error_data">%s</span></div>',
637                                 basename($errorArray['file']),
638                                 $errorArray['line'],
639                                 $errorArray['message'],
640                                 $errorArray['type']
641                         );
642                 }
643
644                 // Add line number to the code
645                 foreach (explode(chr(10), $phpCode) as $lineNo => $code) {
646                         // Add line numbers
647                         $markedCode .= sprintf('<span id="code_line">%s</span>: %s' . PHP_EOL,
648                                 ($lineNo + 1),
649                                 htmlentities($code, ENT_QUOTES)
650                         );
651                 }
652
653                 // Return the code
654                 return $markedCode;
655         }
656
657         /**
658          * "Getter" for databse entry
659          *
660          * @return      $entry  An array with database entries
661          * @throws      NullPointerException    If the database result is not found
662          * @throws      InvalidDatabaseResultException  If the database result is invalid
663          * @deprecated  Monolithic method, should be moved to proper classes
664          */
665         protected final function getDatabaseEntry () {
666                 // This method is deprecated
667                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('BASE-FRAMEWORK-SYSTEM: CALLED!');
668                 $this->deprecationWarning('Monolithic method, should be moved to proper classes');
669
670                 // Is there an instance?
671                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('BASE-FRAMEWORK-SYSTEM: this->resultInstance[]=%s', gettype($this->getResultInstance())));
672                 if (!$this->getResultInstance() instanceof SearchableResult) {
673                         // Throw an exception here
674                         throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
675                 }
676
677                 // Rewind it
678                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('BASE-FRAMEWORK-SYSTEM: Invoking this->resultInstance->rewind() ...');
679                 $this->getResultInstance()->rewind();
680
681                 // Do we have an entry?
682                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('BASE-FRAMEWORK-SYSTEM: this->resultInstance->isValid()=%d', intval($this->getResultInstance()->isValid())));
683                 if ($this->getResultInstance()->valid() === false) {
684                         // @TODO Move the constant to e.g. BaseDatabaseResult when there is a non-cached database result available
685                         throw new InvalidDatabaseResultException(array($this, $this->getResultInstance()), CachedDatabaseResult::EXCEPTION_INVALID_DATABASE_RESULT);
686                 }
687
688                 // Get next entry
689                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage('BASE-FRAMEWORK-SYSTEM: Invoking this->resultInstance->next() ...');
690                 $this->getResultInstance()->next();
691
692                 // Fetch it
693                 $entry = $this->getResultInstance()->current();
694
695                 // And return it
696                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('BASE-FRAMEWORK-SYSTEM: entry[]=%s - EXIT!', gettype($entry)));
697                 return $entry;
698         }
699
700         /**
701          * Getter for field name
702          *
703          * @param       $fieldName              Field name which we shall get
704          * @return      $fieldValue             Field value from the user
705          * @throws      NullPointerException    If the result instance is null
706          * @throws      InvalidArgumentException        If a parameter is not valid
707          * @deprecated  Monolithic method, should be moved to proper classes
708          */
709         public final function getField (string $fieldName) {
710                 // Check parameter
711                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('BASE-FRAMEWORK-SYSTEM: fieldName=%s - CALLED!', $fieldName));
712                 if (empty($fieldName)) {
713                         // Throw IAE
714                         throw new InvalidArgumentException('Parameter "fieldName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
715                 }
716
717                 // This method is deprecated
718                 $this->deprecationWarning('Monolithic method, should be moved to proper classes');
719
720                 // Default field value
721                 $fieldValue = NULL;
722
723                 // Get result instance
724                 $resultInstance = $this->getResultInstance();
725
726                 // Is this instance null?
727                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('BASE-FRAMEWORK-SYSTEM: resultInstance[]=%s', gettype($resultInstance)));
728                 if (is_null($resultInstance)) {
729                         // Then the user instance is no longer valid (expired cookies?)
730                         throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
731                 }
732
733                 // Get current array
734                 $fieldArray = $resultInstance->current();
735
736                 // Convert dashes to underscore
737                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('BASE-FRAMEWORK-SYSTEM: fieldArray()=%d', count($fieldArray)));
738                 $fieldName2 = StringUtils::convertDashesToUnderscores($fieldName);
739
740                 // Does the field exist?
741                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('BASE-FRAMEWORK-SYSTEM: fieldName2=%s', $fieldName2));
742                 if ($this->isFieldSet($fieldName)) {
743                         // Get it
744                         $fieldValue = $fieldArray[$fieldName2];
745                 } elseif (FrameworkBootstrap::getConfigurationInstance()->isEnabled('developer_mode')) {
746                         // Missing field entry, may require debugging
747                         self::createDebugInstance(__CLASS__, __LINE__)->warningMessage('BASE-FRAMEWORK-SYSTEM: fieldArray<pre>=' . print_r($fieldArray, true) . '</pre>,fieldName=' . $fieldName . ' not found!');
748                 } else {
749                         // Missing field entry, may require debugging
750                         self::createDebugInstance(__CLASS__, __LINE__)->warningMessage('BASE-FRAMEWORK-SYSTEM: fieldName=' . $fieldName . ' not found!');
751                 }
752
753                 // Return it
754                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('BASE-FRAMEWORK-SYSTEM: fieldValue[]=%s - EXIT!', gettype($fieldValue)));
755                 return $fieldValue;
756         }
757
758         /**
759          * Checks if given field is set
760          *
761          * @param       $fieldName      Field name to check
762          * @return      $isSet          Whether the given field name is set
763          * @throws      NullPointerException    If the result instance is null
764          * @throws      InvalidArgumentException        If a parameter is not valid
765          */
766         public function isFieldSet (string $fieldName) {
767                 // Check parameter
768                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('BASE-FRAMEWORK-SYSTEM: fieldName=%s - CALLED!', $fieldName));
769                 if (empty($fieldName)) {
770                         // Throw IAE
771                         throw new InvalidArgumentException('Parameter "fieldName" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
772                 }
773
774                 // Get result instance
775                 $resultInstance = $this->getResultInstance();
776
777                 // Is this instance null?
778                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('BASE-FRAMEWORK-SYSTEM: resultInstance[]=%s', gettype($resultInstance)));
779                 if (is_null($resultInstance)) {
780                         // Then the user instance is no longer valid (expired cookies?)
781                         throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
782                 }
783
784                 // Get current array
785                 $fieldArray = $resultInstance->current();
786
787                 // Convert dashes to underscore
788                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('BASE-FRAMEWORK-SYSTEM: fieldArray()=%d,fieldName=%s - BEFORE!', count($fieldArray), $fieldName));
789                 $fieldName = StringUtils::convertDashesToUnderscores($fieldName);
790
791                 // Determine it
792                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->debugMessage(sprintf('BASE-FRAMEWORK-SYSTEM: fieldName=%s - AFTER!', $fieldName));
793                 $isset = isset($fieldArray[$fieldName]);
794
795                 // Return result
796                 /* NOISY-DEBUG: */ self::createDebugInstance(__CLASS__, __LINE__)->traceMessage(sprintf('BASE-FRAMEWORK-SYSTEM: isset=%d - EXIT!', intval($isset)));
797                 return $isset;
798         }
799
800         /**
801          * Outputs a deprecation warning to the developer.
802          *
803          * @param       $message        The message we shall output to the developer
804          * @return      void
805          * @todo        Write a logging mechanism for productive mode
806          */
807         public function deprecationWarning (string $message) {
808                 // Is developer mode active?
809                 if (FrameworkBootstrap::getConfigurationInstance()->isEnabled('developer_mode')) {
810                         // Debug instance is there?
811                         if (!is_null($this->getDebugInstance())) {
812                                 // Output stub message
813                                 self::createDebugInstance(__CLASS__, __LINE__)->warningMessage($message);
814                         } else {
815                                 // Trigger an error
816                                 trigger_error($message . "<br />\n");
817                                 exit(255);
818                         }
819                 } else {
820                         // @TODO Finish this part!
821                         DebugMiddleware::getSelfInstance()->partialStub('Developer mode inactive. Message:' . $message);
822                 }
823         }
824
825         /**
826          * Checks whether the given PHP extension is loaded
827          *
828          * @param       $phpExtension   The PHP extension we shall check
829          * @return      $isLoaded       Whether the PHP extension is loaded
830          * @throws      InvalidArgumentException        If a parameter is not valid
831          */
832         public final function isPhpExtensionLoaded (string $phpExtension) {
833                 // Check parameter
834                 if (empty($phpExtension)) {
835                         // Throw IAE
836                         throw new InvalidArgumentException('Parameter "phpExtension" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
837                 }
838
839                 // Is it loaded?
840                 $isLoaded = in_array($phpExtension, get_loaded_extensions());
841
842                 // Return result
843                 return $isLoaded;
844         }
845
846         /**
847          * "Getter" as a time() replacement but with milliseconds. You should use this
848          * method instead of the encapsulated getimeofday() function.
849          *
850          * @return      $milliTime      Timestamp with milliseconds
851          */
852         public function getMilliTime () {
853                 // Get the time of day as float
854                 $milliTime = gettimeofday(true);
855
856                 // Return it
857                 return $milliTime;
858         }
859
860         /**
861          * Idles (sleeps) for given milliseconds
862          *
863          * @return      $hasSlept       Whether it goes fine
864          * @throws      InvalidArgumentException        If a parameter is not valid
865          */
866         public function idle (int $milliSeconds) {
867                 // Check parameter
868                 if ($milliSeconds < 1) {
869                         // Throw IAE
870                         throw new InvalidArgumentException(sprintf('milliSeconds=%d are not a reasonable value to idle', $milliSeconds));
871                 }
872
873                 // Sleep is fine by default
874                 $hasSlept = true;
875
876                 // Idle so long with found function
877                 if (function_exists('time_sleep_until')) {
878                         // Get current time and add idle time
879                         $sleepUntil = $this->getMilliTime() + abs($milliSeconds) / 1000;
880
881                         // New PHP 5.1.0 function found, ignore errors
882                         $hasSlept = @time_sleep_until($sleepUntil);
883                 } else {
884                         /*
885                          * My Sun station doesn't have that function even with latest PHP
886                          * package. :(
887                          */
888                         usleep($milliSeconds * 1000);
889                 }
890
891                 // Return result
892                 return $hasSlept;
893         }
894
895         /**
896          * Checks whether the given encoded data was encoded with Base64
897          *
898          * @param       $encodedData    Encoded data we shall check
899          * @return      $isBase64               Whether the encoded data is Base64
900          * @throws      InvalidArgumentException        If a parameter is not valid
901          */
902         protected function isBase64Encoded (string $encodedData) {
903                 // Check parameter
904                 if (empty($encodedData)) {
905                         // Throw IAE
906                         throw new InvalidArgumentException('Parameter "encodedData" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
907                 }
908
909                 // Determine it
910                 $isBase64 = (@base64_decode($encodedData, true) !== false);
911
912                 // Return it
913                 return $isBase64;
914         }
915
916         /**
917          * Getter for startup time in miliseconds
918          *
919          * @return      $startupTime    Startup time in miliseconds
920          */
921         protected function getStartupTime () {
922                 return self::$startupTime;
923         }
924
925         /**
926          * "Getter" for a printable currently execution time in nice braces
927          *
928          * @return      $executionTime  Current execution time in nice braces
929          */
930         protected function getPrintableExecutionTime () {
931                 // Calculate execution time and pack it in nice braces
932                 $executionTime = sprintf('[ %01.5f ] ', (microtime(true) - $this->getStartupTime()));
933
934                 // And return it
935                 return $executionTime;
936         }
937
938         /**
939          * Determines if an element is set in the generic array
940          *
941          * @param       $keyGroup       Main group for the key
942          * @param       $subGroup       Sub group for the key
943          * @param       $key            Key to check
944          * @param       $element        Element to check
945          * @return      $isset          Whether the given key is set
946          * @throws      InvalidArgumentException        If a parameter is not valid
947          */
948         protected final function isGenericArrayElementSet (string $keyGroup, string $subGroup, string $key, string $element) {
949                 // Check parameter
950                 if (empty($keyGroup)) {
951                         // Throw IAE
952                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
953                 } elseif (empty($subGroup)) {
954                         // Throw IAE
955                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
956                 } elseif (empty($key)) {
957                         // Throw IAE
958                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
959                 } elseif ($element === '') {
960                         // Throw IAE
961                         throw new InvalidArgumentException('Parameter "element" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
962                 }
963
964                 // Is it there?
965                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element);
966                 $isset = isset($this->genericArray[$keyGroup][$subGroup][$key][$element]);
967
968                 // Return it
969                 return $isset;
970         }
971         /**
972          * Determines if a key is set in the generic array
973          *
974          * @param       $keyGroup       Main group for the key
975          * @param       $subGroup       Sub group for the key
976          * @param       $key            Key to check
977          * @return      $isset          Whether the given key is set
978          * @throws      InvalidArgumentException        If a parameter is not valid
979          */
980         protected final function isGenericArrayKeySet (string $keyGroup, string $subGroup, string $key) {
981                 // Check parameter
982                 if (empty($keyGroup)) {
983                         // Throw IAE
984                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
985                 } elseif (empty($subGroup)) {
986                         // Throw IAE
987                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
988                 } elseif (empty($key)) {
989                         // Throw IAE
990                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
991                 }
992
993                 // Is it there?
994                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key);
995                 $isset = isset($this->genericArray[$keyGroup][$subGroup][$key]);
996
997                 // Return it
998                 return $isset;
999         }
1000
1001         /**
1002          * Determines if a group is set in the generic array
1003          *
1004          * @param       $keyGroup       Main group
1005          * @param       $subGroup       Sub group
1006          * @return      $isset          Whether the given group is set
1007          * @throws      InvalidArgumentException        If a parameter is not valid
1008          */
1009         protected final function isGenericArrayGroupSet (string $keyGroup, string $subGroup) {
1010                 // Check parameter
1011                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup);
1012                 if (empty($keyGroup)) {
1013                         // Throw IAE
1014                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1015                 } elseif (empty($subGroup)) {
1016                         // Throw IAE
1017                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1018                 }
1019
1020                 // Is it there?
1021                 $isset = isset($this->genericArray[$keyGroup][$subGroup]);
1022
1023                 // Return it
1024                 return $isset;
1025         }
1026
1027         /**
1028          * Getter for sub key group
1029          *
1030          * @param       $keyGroup       Main key group
1031          * @param       $subGroup       Sub key group
1032          * @return      $array          An array with all array elements
1033          * @throws      InvalidArgumentException        If a parameter is not valid
1034          * @throws      BadMethodCallException  If key/sub group isn't there but this method is invoked
1035          */
1036         protected final function getGenericSubArray (string $keyGroup, string $subGroup) {
1037                 // Check parameter
1038                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',value=' . print_r($this->genericArray[$keyGroup][$subGroup], true));
1039                 if (empty($keyGroup)) {
1040                         // Throw IAE
1041                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1042                 } elseif (empty($subGroup)) {
1043                         // Throw IAE
1044                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1045                 } elseif (!$this->isGenericArrayGroupSet($keyGroup, $subGroup)) {
1046                         // No, then abort here
1047                         throw new BadMethodCallException(sprintf('keyGroup=%s,subGroup=%s not found.', $keyGroup, $subGroup), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
1048                 }
1049
1050                 // Return it
1051                 return $this->genericArray[$keyGroup][$subGroup];
1052         }
1053
1054         /**
1055          * Unsets a given key in generic array
1056          *
1057          * @param       $keyGroup       Main group for the key
1058          * @param       $subGroup       Sub group for the key
1059          * @param       $key            Key to unset
1060          * @return      void
1061          * @throws      InvalidArgumentException        If a parameter is not valid
1062          */
1063         protected final function unsetGenericArrayKey (string $keyGroup, string $subGroup, string $key) {
1064                 // Check parameter
1065                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key);
1066                 if (empty($keyGroup)) {
1067                         // Throw IAE
1068                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1069                 } elseif (empty($subGroup)) {
1070                         // Throw IAE
1071                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1072                 } elseif (empty($key)) {
1073                         // Throw IAE
1074                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1075                 }
1076
1077                 // Remove it
1078                 unset($this->genericArray[$keyGroup][$subGroup][$key]);
1079         }
1080
1081         /**
1082          * Unsets a given element in generic array
1083          *
1084          * @param       $keyGroup       Main group for the key
1085          * @param       $subGroup       Sub group for the key
1086          * @param       $key            Key to unset
1087          * @param       $element        Element to unset
1088          * @return      void
1089          * @throws      InvalidArgumentException        If a parameter is not valid
1090          */
1091         protected final function unsetGenericArrayElement (string $keyGroup, string $subGroup, string $key, string $element) {
1092                 // Check parameter
1093                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element);
1094                 if (empty($keyGroup)) {
1095                         // Throw IAE
1096                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1097                 } elseif (empty($subGroup)) {
1098                         // Throw IAE
1099                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1100                 } elseif (empty($key)) {
1101                         // Throw IAE
1102                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1103                 } elseif ($element === '') {
1104                         // Throw IAE
1105                         throw new InvalidArgumentException('Parameter "element" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1106                 }
1107
1108                 // Remove it
1109                 unset($this->genericArray[$keyGroup][$subGroup][$key][$element]);
1110         }
1111
1112         /**
1113          * Append a string to a given generic array key
1114          *
1115          * @param       $keyGroup       Main group for the key
1116          * @param       $subGroup       Sub group for the key
1117          * @param       $key            Key to unset
1118          * @param       $value          Value to add/append
1119          * @return      void
1120          * @throws      InvalidArgumentException        If a parameter is not valid
1121          */
1122         protected final function appendStringToGenericArrayKey (string $keyGroup, string $subGroup, $key, string $value, string $appendGlue = '') {
1123                 // Check parameter
1124                 //* NOISY-DEBUG: */ if (!is_object($value)) $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',value[' . gettype($value) . ']=' . print_r($value, true) . ',appendGlue=' . $appendGlue);
1125                 if (empty($keyGroup)) {
1126                         // Throw IAE
1127                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1128                 } elseif (empty($subGroup)) {
1129                         // Throw IAE
1130                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1131                 } elseif (empty($key)) {
1132                         // Throw IAE
1133                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1134                 }
1135
1136                 // Is it already there?
1137                 if ($this->isGenericArrayKeySet($keyGroup, $subGroup, $key)) {
1138                         // Append it
1139                         $this->genericArray[$keyGroup][$subGroup][$key] .= $appendGlue . $value;
1140                 } else {
1141                         // Add it
1142                         $this->genericArray[$keyGroup][$subGroup][$key] = $value;
1143                 }
1144         }
1145
1146         /**
1147          * Append a string to a given generic array element
1148          *
1149          * @param       $keyGroup       Main group for the key
1150          * @param       $subGroup       Sub group for the key
1151          * @param       $key            Key to unset
1152          * @param       $element        Element to check
1153          * @param       $value          Value to add/append
1154          * @return      void
1155          * @throws      InvalidArgumentException        If a parameter is not valid
1156          */
1157         protected final function appendStringToGenericArrayElement (string $keyGroup, string $subGroup, string $key, string $element, string $value, string $appendGlue = '') {
1158                 // Check parameter
1159                 //* NOISY-DEBUG: */ if (!is_object($value)) $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element . ',value[' . gettype($value) . ']=' . print_r($value, true) . ',appendGlue=' . $appendGlue);
1160                 if (empty($keyGroup)) {
1161                         // Throw IAE
1162                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1163                 } elseif (empty($subGroup)) {
1164                         // Throw IAE
1165                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1166                 } elseif (empty($key)) {
1167                         // Throw IAE
1168                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1169                 } elseif ($element === '') {
1170                         // Throw IAE
1171                         throw new InvalidArgumentException('Parameter "element" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1172                 }
1173
1174                 // Is it already there?
1175                 if ($this->isGenericArrayElementSet($keyGroup, $subGroup, $key, $element)) {
1176                         // Append it
1177                         $this->genericArray[$keyGroup][$subGroup][$key][$element] .= $appendGlue . $value;
1178                 } else {
1179                         // Add it
1180                         $this->setGenericArrayElement($keyGroup, $subGroup, $key, $element, $value);
1181                 }
1182         }
1183
1184         /**
1185          * Initializes given generic array group
1186          *
1187          * @param       $keyGroup       Main group for the key
1188          * @param       $subGroup       Sub group for the key
1189          * @param       $key            Key to use
1190          * @param       $forceInit      Optionally force initialization
1191          * @return      void
1192          * @throws      InvalidArgumentException        If a parameter is not valid
1193          * @throws      BadMethodCallException  If key/sub group has already been initialized
1194          */
1195         protected final function initGenericArrayGroup (string $keyGroup, string $subGroup, bool $forceInit = false) {
1196                 // Check parameter
1197                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',forceInit=' . intval($forceInit));
1198                 if (empty($keyGroup)) {
1199                         // Throw IAE
1200                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1201                 } elseif (empty($subGroup)) {
1202                         // Throw IAE
1203                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1204                 } elseif (($forceInit === false) && ($this->isGenericArrayGroupSet($keyGroup, $subGroup))) {
1205                         // Already initialized
1206                         throw new BadMethodCallException(sprintf('keyGroup=%s,subGroup=%s already initialized.', $keyGroup, $subGroup), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
1207                 }
1208
1209                 // Initialize it
1210                 $this->genericArray[$keyGroup][$subGroup] = [];
1211         }
1212
1213         /**
1214          * Initializes given generic array key
1215          *
1216          * @param       $keyGroup       Main group for the key
1217          * @param       $subGroup       Sub group for the key
1218          * @param       $key            Key to use
1219          * @param       $forceInit      Optionally force initialization
1220          * @return      void
1221          * @throws      InvalidArgumentException        If a parameter is not valid
1222          * @throws      BadMethodCallException  If key/sub group has already been initialized
1223          */
1224         protected final function initGenericArrayKey (string $keyGroup, string $subGroup, $key, bool $forceInit = false) {
1225                 // Check parameter
1226                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',forceInit=' . intval($forceInit));
1227                 if (empty($keyGroup)) {
1228                         // Throw IAE
1229                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1230                 } elseif (empty($subGroup)) {
1231                         // Throw IAE
1232                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1233                 } elseif (empty($key)) {
1234                         // Throw IAE
1235                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1236                 } elseif (($forceInit === false) && ($this->isGenericArrayKeySet($keyGroup, $subGroup, $key))) {
1237                         // Already initialized
1238                         throw new BadMethodCallException(sprintf('keyGroup=%s,subGroup=%s,key[%s]=%s already initialized.', $keyGroup, $subGroup, gettype($key), $key), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
1239                 }
1240
1241                 // Initialize it
1242                 $this->genericArray[$keyGroup][$subGroup][$key] = [];
1243         }
1244
1245         /**
1246          * Initializes given generic array element
1247          *
1248          * @param       $keyGroup       Main group for the key
1249          * @param       $subGroup       Sub group for the key
1250          * @param       $key            Key to use
1251          * @param       $element        Element to use
1252          * @param       $forceInit      Optionally force initialization
1253          * @return      void
1254          * @throws      InvalidArgumentException        If a parameter is not valid
1255          * @throws      BadMethodCallException  If key/sub group isn't there but this method is invoked
1256          */
1257         protected final function initGenericArrayElement (string $keyGroup, string $subGroup, string $key, string $element, bool $forceInit = false) {
1258                 // Check parameter
1259                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element . ',forceInit=' . intval($forceInit));
1260                 if (empty($keyGroup)) {
1261                         // Throw IAE
1262                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1263                 } elseif (empty($subGroup)) {
1264                         // Throw IAE
1265                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1266                 } elseif (empty($key)) {
1267                         // Throw IAE
1268                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1269                 } elseif ($element === '') {
1270                         // Throw IAE
1271                         throw new InvalidArgumentException('Parameter "element" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1272                 } elseif (($forceInit === false) && ($this->isGenericArrayElementSet($keyGroup, $subGroup, $key, $element))) {
1273                         // Already initialized
1274                         throw new BadMethodCallException(sprintf('keyGroup=%s,subGroup=%s,key[%s]=%s,element[%s]=%s already initialized.', $keyGroup, $subGroup, gettype($key), $key, gettype($element), $element), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
1275                 }
1276
1277                 // Initialize it
1278                 $this->genericArray[$keyGroup][$subGroup][$key][$element] = [];
1279         }
1280
1281         /**
1282          * Pushes an element to a generic key. If the key isn't found, it will be initialized.
1283          *
1284          * @param       $keyGroup       Main group for the key
1285          * @param       $subGroup       Sub group for the key
1286          * @param       $key            Key to use
1287          * @param       $value          Value to add/append
1288          * @return      $count          Number of array elements
1289          * @throws      InvalidArgumentException        If a parameter is not valid
1290          */
1291         protected final function pushValueToGenericArrayKey (string $keyGroup, string $subGroup, string $key, $value) {
1292                 // Check parameter
1293                 //* NOISY-DEBUG: */ if (!is_object($value)) $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',value[' . gettype($value) . ']=' . print_r($value, true));
1294                 if (empty($keyGroup)) {
1295                         // Throw IAE
1296                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1297                 } elseif (empty($subGroup)) {
1298                         // Throw IAE
1299                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1300                 } elseif (empty($key)) {
1301                         // Throw IAE
1302                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1303                 } elseif (!$this->isGenericArrayKeySet($keyGroup, $subGroup, $key)) {
1304                         // Initialize array
1305                         $this->initGenericArrayKey($keyGroup, $subGroup, $key);
1306                 }
1307
1308                 // Then push it
1309                 $count = array_push($this->genericArray[$keyGroup][$subGroup][$key], $value);
1310
1311                 // Return count
1312                 //* DEBUG: */ print(__METHOD__ . ': genericArray=' . print_r($this->genericArray[$keyGroup][$subGroup][$key], true));
1313                 //* DEBUG: */ print(__METHOD__ . ': count=' . $count . PHP_EOL);
1314                 return $count;
1315         }
1316
1317         /**
1318          * Pushes an element to a generic array element. If the key isn't found, it will be initialized.
1319          *
1320          * @param       $keyGroup       Main group for the key
1321          * @param       $subGroup       Sub group for the key
1322          * @param       $key            Key to use
1323          * @param       $element        Element to check
1324          * @param       $value          Value to add/append
1325          * @return      $count          Number of array elements
1326          * @throws      InvalidArgumentException        If a parameter is not valid
1327          */
1328         protected final function pushValueToGenericArrayElement (string $keyGroup, string $subGroup, string $key, string $element, $value) {
1329                 // Check parameter
1330                 //* NOISY-DEBUG: */ if (!is_object($value)) $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element . ',value[' . gettype($value) . ']=' . print_r($value, true));
1331                 if (empty($keyGroup)) {
1332                         // Throw IAE
1333                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1334                 } elseif (empty($subGroup)) {
1335                         // Throw IAE
1336                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1337                 } elseif (empty($key)) {
1338                         // Throw IAE
1339                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1340                 } elseif ($element === '') {
1341                         // Throw IAE
1342                         throw new InvalidArgumentException('Parameter "element" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1343                 } elseif (!$this->isGenericArrayElementSet($keyGroup, $subGroup, $key, $element)) {
1344                         // Initialize array
1345                         $this->initGenericArrayElement($keyGroup, $subGroup, $key, $element);
1346                 }
1347
1348                 // Then push it
1349                 $count = array_push($this->genericArray[$keyGroup][$subGroup][$key][$element], $value);
1350
1351                 // Return count
1352                 //* DEBUG: */ print(__METHOD__ . ': genericArray=' . print_r($this->genericArray[$keyGroup][$subGroup][$key], true));
1353                 //* DEBUG: */ print(__METHOD__ . ': count=' . $count . PHP_EOL);
1354                 return $count;
1355         }
1356
1357         /**
1358          * Pops an element from  a generic group
1359          *
1360          * @param       $keyGroup       Main group for the key
1361          * @param       $subGroup       Sub group for the key
1362          * @param       $key            Key to unset
1363          * @return      $value          Last "popped" value
1364          * @throws      InvalidArgumentException        If a parameter is not valid
1365          * @throws      BadMethodCallException  If key/sub group isn't there but this method is invoked
1366          */
1367         protected final function popGenericArrayElement (string $keyGroup, string $subGroup, string $key) {
1368                 // Check parameter
1369                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key);
1370                 if (empty($keyGroup)) {
1371                         // Throw IAE
1372                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1373                 } elseif (empty($subGroup)) {
1374                         // Throw IAE
1375                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1376                 } elseif (empty($key)) {
1377                         // Throw IAE
1378                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1379                 } elseif (!$this->isGenericArrayKeySet($keyGroup, $subGroup, $key)) {
1380                         // Not found
1381                         throw new BadMethodCallException(sprintf('keyGroup=%s,subGroup=%s,key[%s]=%s not found.', $keyGroup, $subGroup, gettype($key), $key), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
1382                 }
1383
1384                 // Then "pop" it
1385                 $value = array_pop($this->genericArray[$keyGroup][$subGroup][$key]);
1386
1387                 // Return value
1388                 //* DEBUG: */ print(__METHOD__ . ': genericArray=' . print_r($this->genericArray[$keyGroup][$subGroup][$key], true));
1389                 //* DEBUG: */ print(__METHOD__ . ': value[' . gettype($value) . ']=' . print_r($value, true) . PHP_EOL);
1390                 return $value;
1391         }
1392
1393         /**
1394          * Shifts an element from  a generic group
1395          *
1396          * @param       $keyGroup       Main group for the key
1397          * @param       $subGroup       Sub group for the key
1398          * @param       $key            Key to unset
1399          * @return      $value          Last "shifted" value
1400          * @throws      InvalidArgumentException        If a parameter is not valid
1401          * @throws      BadMethodCallException  If key/sub group isn't there but this method is invoked
1402          */
1403         protected final function shiftGenericArrayElement (string $keyGroup, string $subGroup, string $key) {
1404                 // Check parameter
1405                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key);
1406                 if (empty($keyGroup)) {
1407                         // Throw IAE
1408                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1409                 } elseif (empty($subGroup)) {
1410                         // Throw IAE
1411                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1412                 } elseif (empty($key)) {
1413                         // Throw IAE
1414                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1415                 } elseif (!$this->isGenericArrayKeySet($keyGroup, $subGroup, $key)) {
1416                         // Not found
1417                         throw new BadMethodCallException(sprintf('keyGroup=%s,subGroup=%s,key[%s]=%s not found.', $keyGroup, $subGroup, gettype($key), $key), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
1418                 }
1419
1420                 // Then "shift" it
1421                 $value = array_shift($this->genericArray[$keyGroup][$subGroup][$key]);
1422
1423                 // Return value
1424                 //* DEBUG: */ print(__METHOD__ . ': genericArray=' . print_r($this->genericArray[$keyGroup][$subGroup][$key], true));
1425                 //* DEBUG: */ print(__METHOD__ . ': value[' . gettype($value) . ']=' . print_r($value, true) . PHP_EOL);
1426                 return $value;
1427         }
1428
1429         /**
1430          * Count generic array group
1431          *
1432          * @param       $keyGroup       Main group for the key
1433          * @return      $count          Count of given group
1434          * @throws      InvalidArgumentException        If a parameter is not valid
1435          * @throws      BadMethodCallException  If key group isn't there but this method is invoked
1436          */
1437         protected final function countGenericArray (string $keyGroup) {
1438                 // Check parameter
1439                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup);
1440                 if (empty($keyGroup)) {
1441                         // Throw IAE
1442                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1443                 } elseif (!isset($this->genericArray[$keyGroup])) {
1444                         // Not found
1445                         throw new BadMethodCallException(sprintf('keyGroup=%s not found.', $keyGroup), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
1446                 }
1447
1448                 // Then count it
1449                 $count = count($this->genericArray[$keyGroup]);
1450
1451                 // Return it
1452                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',count=' . $count);
1453                 return $count;
1454         }
1455
1456         /**
1457          * Count generic array sub group
1458          *
1459          * @param       $keyGroup       Main group for the key
1460          * @param       $subGroup       Sub group for the key
1461          * @return      $count          Count of given group
1462          * @throws      InvalidArgumentException        If a parameter is not valid
1463          * @throws      BadMethodCallException  If key/sub group isn't there but this method is invoked
1464          */
1465         protected final function countGenericArrayGroup (string $keyGroup, string $subGroup) {
1466                 // Check parameter
1467                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup);
1468                 if (empty($keyGroup)) {
1469                         // Throw IAE
1470                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1471                 } elseif (empty($subGroup)) {
1472                         // Throw IAE
1473                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1474                 } elseif (!$this->isGenericArrayGroupSet($keyGroup, $subGroup)) {
1475                         // Abort here
1476                         throw new BadMethodCallException(sprintf('keyGroup=%s,subGroup=%s not found.', $keyGroup, $subGroup), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
1477                 }
1478
1479                 // Then count it
1480                 $count = count($this->genericArray[$keyGroup][$subGroup]);
1481
1482                 // Return it
1483                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',count=' . $count);
1484                 return $count;
1485         }
1486
1487         /**
1488          * Count generic array elements
1489          *
1490          * @param       $keyGroup       Main group for the key
1491          * @param       $subGroup       Sub group for the key
1492          * @param       $key            Key to count
1493          * @return      $count          Count of given key
1494          * @throws      InvalidArgumentException        If a parameter is not valid
1495          * @throws      BadMethodCallException  If key/sub group isn't there but this method is invoked
1496          */
1497         protected final function countGenericArrayElements (string $keyGroup, string $subGroup, string $key) {
1498                 // Check parameter
1499                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key);
1500                 if (empty($keyGroup)) {
1501                         // Throw IAE
1502                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1503                 } elseif (empty($subGroup)) {
1504                         // Throw IAE
1505                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1506                 } elseif (empty($key)) {
1507                         // Throw IAE
1508                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1509                 } elseif (!$this->isGenericArrayKeySet($keyGroup, $subGroup, $key)) {
1510                         // Abort here
1511                         throw new BadMethodCallException(sprintf('keyGroup=%s,subGroup=%s,key[%s]=%s not found.', $keyGroup, $subGroup, gettype($key), $key), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
1512                 } elseif (!$this->isValidGenericArrayGroup($keyGroup, $subGroup)) {
1513                         // Not valid
1514                         throw new BadMethodCallException(sprintf('keyGroup=%s,subGroup=%s is not a valid key/sub group.', $keyGroup, $subGroup), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
1515                 }
1516
1517                 // Then count it
1518                 $count = count($this->genericArray[$keyGroup][$subGroup][$key]);
1519
1520                 // Return it
1521                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',count=' . $count);
1522                 return $count;
1523         }
1524
1525         /**
1526          * Getter for whole generic group array
1527          *
1528          * @param       $keyGroup       Key group to get
1529          * @return      $array          Whole generic array group
1530          * @throws      InvalidArgumentException        If a parameter is not valid
1531          * @throws      BadMethodCallException  If key/sub group isn't there but this method is invoked
1532          */
1533         protected final function getGenericArray (string $keyGroup) {
1534                 // Check parameters
1535                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup);
1536                 if (empty($keyGroup)) {
1537                         // Throw IAE
1538                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1539                 } elseif (!isset($this->genericArray[$keyGroup])) {
1540                         // Then abort here
1541                         throw new BadMethodCallException(sprintf('keyGroup=%s not found', $keyGroup), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
1542                 }
1543
1544                 // Return it
1545                 return $this->genericArray[$keyGroup];
1546         }
1547
1548         /**
1549          * Setter for generic array key
1550          *
1551          * @param       $keyGroup       Key group to get
1552          * @param       $subGroup       Sub group for the key
1553          * @param       $key            Key to unset
1554          * @param       $value          Mixed value from generic array element
1555          * @return      void
1556          * @throws      InvalidArgumentException        If a parameter is not valid
1557          * @throws      BadMethodCallException  If key/sub group isn't there but this method is invoked
1558          */
1559         protected final function setGenericArrayKey (string $keyGroup, string $subGroup, string $key, $value) {
1560                 // Check parameters
1561                 //* NOISY-DEBUG: */ if (!is_object($value)) $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',value[' . gettype($value) . ']=' . print_r($value, true));
1562                 if (empty($keyGroup)) {
1563                         // Throw IAE
1564                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1565                 } elseif (empty($subGroup)) {
1566                         // Throw IAE
1567                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1568                 } elseif (empty($key)) {
1569                         // Throw IAE
1570                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1571                 } elseif (!$this->isValidGenericArrayGroup($keyGroup, $subGroup)) {
1572                         // Then abort here
1573                         throw new BadMethodCallException(sprintf('keyGroup=%s,subGroup=%s not found', $keyGroup), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
1574                 }
1575
1576                 // Set value here
1577                 $this->genericArray[$keyGroup][$subGroup][$key] = $value;
1578         }
1579
1580         /**
1581          * Getter for generic array key
1582          *
1583          * @param       $keyGroup       Key group to get
1584          * @param       $subGroup       Sub group for the key
1585          * @param       $key            Key to unset
1586          * @return      $value          Mixed value from generic array element
1587          * @throws      InvalidArgumentException        If a parameter is not valid
1588          * @throws      BadMethodCallException  If key/sub group isn't there but this method is invoked
1589          */
1590         protected final function getGenericArrayKey (string $keyGroup, string $subGroup, string $key) {
1591                 // Check parameters
1592                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key);
1593                 if (empty($keyGroup)) {
1594                         // Throw IAE
1595                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1596                 } elseif (empty($subGroup)) {
1597                         // Throw IAE
1598                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1599                 } elseif (empty($key)) {
1600                         // Throw IAE
1601                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1602                 } elseif (!$this->isGenericArrayKeySet($keyGroup, $subGroup, $key)) {
1603                         // Then abort here
1604                         throw new BadMethodCallException(sprintf('keyGroup=%s,subGroup=%s,key[%s]=%s not found.', $keyGroup, $subGroup, gettype($key), $key), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
1605                 }
1606
1607                 // Return it
1608                 return $this->genericArray[$keyGroup][$subGroup][$key];
1609         }
1610
1611         /**
1612          * Sets a value in given generic array key/element
1613          *
1614          * @param       $keyGroup       Main group for the key
1615          * @param       $subGroup       Sub group for the key
1616          * @param       $key            Key to set
1617          * @param       $element        Element to set
1618          * @param       $value          Value to set
1619          * @return      void
1620          * @throws      InvalidArgumentException        If a parameter is not valid
1621          */
1622         protected final function setGenericArrayElement (string $keyGroup, string $subGroup, string $key, string $element, $value) {
1623                 // Check parameter
1624                 //* NOISY-DEBUG: */ if (!is_object($value)) $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element . ',value[' . gettype($value) . ']=' . print_r($value, true));
1625                 if (empty($keyGroup)) {
1626                         // Throw IAE
1627                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1628                 } elseif (empty($subGroup)) {
1629                         // Throw IAE
1630                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1631                 } elseif (empty($key)) {
1632                         // Throw IAE
1633                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1634                 } elseif ($element === '') {
1635                         // Throw IAE
1636                         throw new InvalidArgumentException('Parameter "element" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1637                 } elseif (!$this->isGenericArrayElementSet($keyGroup, $subGroup, $key, $element)) {
1638                         // Initialize array
1639                         $this->initGenericArrayElement($keyGroup, $subGroup, $key, $element);
1640                 }
1641
1642                 // Then set it
1643                 $this->genericArray[$keyGroup][$subGroup][$key][$element] = $value;
1644         }
1645
1646         /**
1647          * Getter for generic array element
1648          *
1649          * @param       $keyGroup       Key group to get
1650          * @param       $subGroup       Sub group for the key
1651          * @param       $key            Key to look for
1652          * @param       $element        Element to look for
1653          * @return      $value          Mixed value from generic array element
1654          * @throws      InvalidArgumentException        If a parameter is not valid
1655          * @throws      BadMethodCallException  If key/sub group isn't there but this method is invoked
1656          */
1657         protected final function getGenericArrayElement (string $keyGroup, string $subGroup, string $key, string $element) {
1658                 // Check parameter
1659                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key . ',element=' . $element);
1660                 if (empty($keyGroup)) {
1661                         // Throw IAE
1662                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1663                 } elseif (empty($subGroup)) {
1664                         // Throw IAE
1665                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1666                 } elseif (empty($key)) {
1667                         // Throw IAE
1668                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1669                 } elseif ($element === '') {
1670                         // Throw IAE
1671                         throw new InvalidArgumentException('Parameter "element" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1672                 } elseif (!$this->isGenericArrayElementSet($keyGroup, $subGroup, $key, $element)) {
1673                         // Then abort here
1674                         throw new BadMethodCallException(sprintf('keyGroup=%s,subGroup=%s,key[%s]=%s,element[%s]=%s not found.', $keyGroup, $subGroup, gettype($key), $key, gettype($element), $element), FrameworkInterface::EXCEPTION_BAD_METHOD_CALL);
1675                 }
1676
1677                 // Return it
1678                 return $this->genericArray[$keyGroup][$subGroup][$key][$element];
1679         }
1680
1681         /**
1682          * Checks if a given sub group is valid (array)
1683          *
1684          * @param       $keyGroup       Key group to get
1685          * @param       $subGroup       Sub group for the key
1686          * @return      $isValid        Whether given sub group is valid
1687          * @throws      InvalidArgumentException        If a parameter is not valid
1688          */
1689         protected final function isValidGenericArrayGroup (string $keyGroup, string $subGroup) {
1690                 // Check parameter
1691                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup);
1692                 if (empty($keyGroup)) {
1693                         // Throw IAE
1694                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1695                 } elseif (empty($subGroup)) {
1696                         // Throw IAE
1697                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1698                 }
1699
1700                 // Determine it
1701                 $isValid = (($this->isGenericArrayGroupSet($keyGroup, $subGroup)) && (is_array($this->getGenericSubArray($keyGroup, $subGroup))));
1702
1703                 // Return it
1704                 return $isValid;
1705         }
1706
1707         /**
1708          * Checks if a given key is valid (array)
1709          *
1710          * @param       $keyGroup       Key group to get
1711          * @param       $subGroup       Sub group for the key
1712          * @param       $key            Key to check
1713          * @return      $isValid        Whether given sub group is valid
1714          */
1715         protected final function isValidGenericArrayKey (string $keyGroup, string $subGroup, string $key) {
1716                 // Check parameters
1717                 //* NOISY-DEBUG: */ $this->outputLine('[' . __METHOD__ . ':' . __LINE__ . '] keyGroup=' . $keyGroup . ',subGroup=' . $subGroup . ',key=' . $key);
1718                 if (empty($keyGroup)) {
1719                         // Throw IAE
1720                         throw new InvalidArgumentException('Parameter "keyGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1721                 } elseif (empty($subGroup)) {
1722                         // Throw IAE
1723                         throw new InvalidArgumentException('Parameter "subGroup" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1724                 } elseif (empty($key)) {
1725                         // Throw IAE
1726                         throw new InvalidArgumentException('Parameter "key" is empty', FrameworkInterface::EXCEPTION_INVALID_ARGUMENT);
1727                 }
1728
1729                 // Determine it
1730                 $isValid = (($this->isGenericArrayKeySet($keyGroup, $subGroup, $key)) && (is_array($this->getGenericArrayKey($keyGroup, $subGroup, $key))));
1731
1732                 // Return it
1733                 return $isValid;
1734         }
1735
1736         /**
1737          * Initializes the web output instance
1738          *
1739          * @return      void
1740          */
1741         protected function initWebOutputInstance () {
1742                 // Init web output instance
1743                 $outputInstance = ObjectFactory::createObjectByConfiguredName('output_class');
1744
1745                 // Set it locally
1746                 $this->setWebOutputInstance($outputInstance);
1747         }
1748
1749         /**
1750          * Translates boolean true to 'Y' and false to 'N'
1751          *
1752          * @param       $boolean                Boolean value
1753          * @return      $translated             Translated boolean value
1754          */
1755         public static final function translateBooleanToYesNo (bool $boolean) {
1756                 // "Translate" it
1757                 $translated = ($boolean === true) ? 'Y' : 'N';
1758
1759                 // ... and return it
1760                 return $translated;
1761         }
1762
1763         /**
1764          * Creates a full-qualified file name (FQFN) for given file name by adding
1765          * a configured temporary file path to it.
1766          *
1767          * @param       $infoInstance   An instance of a SplFileInfo class
1768          * @return      $tempInstance   An instance of a SplFileInfo class (temporary file)
1769          * @throw       PathWriteProtectedException If the path in 'temp_file_path' is write-protected
1770          * @throws      FileIoException If the file cannot be written
1771          */
1772          protected static function createTempPathForFile (SplFileInfo $infoInstance) {
1773                 // Get config entry
1774                 $basePath = FrameworkBootstrap::getConfigurationInstance()->getConfigEntry('temp_file_path');
1775
1776                 // Is the path writeable?
1777                 if (!is_writable($basePath)) {
1778                         // Path is write-protected
1779                         throw new PathWriteProtectedException($infoInstance, self::EXCEPTION_PATH_CANNOT_BE_WRITTEN);
1780                 }
1781
1782                 // Add it
1783                 $tempInstance = new SplFileInfo($basePath . DIRECTORY_SEPARATOR . $infoInstance->getBasename());
1784
1785                 // Is it reachable?
1786                 if (!FrameworkBootstrap::isReachableFilePath($tempInstance)) {
1787                         // Not reachable
1788                         throw new FileIoException($tempInstance, self::EXCEPTION_FILE_NOT_REACHABLE);
1789                 }
1790
1791                 // Return it
1792                 return $tempInstance;
1793          }
1794
1795         /**
1796          * "Getter" for a printable state name
1797          *
1798          * @return      $stateName      Name of the node's state in a printable format
1799          * @todo        Move this class away from this monolithic place (not whole class is monolithic)
1800          */
1801         public final function getPrintableState () {
1802                 // Default is 'null'
1803                 $stateName = 'null';
1804
1805                 // Get the state instance
1806                 $stateInstance = $this->getStateInstance();
1807
1808                 // Is it an instance of Stateable?
1809                 if ($stateInstance instanceof Stateable) {
1810                         // Then use that state name
1811                         $stateName = $stateInstance->getStateName();
1812                 }
1813
1814                 // Return result
1815                 return $stateName;
1816         }
1817
1818 }