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