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