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