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