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