Attribute listInstance is now cored
[core.git] / inc / classes / main / class_BaseFrameworkSystem.php
1 <?php
2 /**
3  * The simulator system class is the super class of all other classes. This
4  * class handles saving of games etc.
5  *
6  * @author              Roland Haeder <webmaster@ship-simu.org>
7  * @version             0.0.0
8  * @copyright   Copyright (c) 2007, 2008 Roland Haeder, 2009 Core Developer Team
9  * @license             GNU GPL 3.0 or any newer version
10  * @link                http://www.ship-simu.org
11  *
12  * This program is free software: you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation, either version 3 of the License, or
15  * (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program. If not, see <http://www.gnu.org/licenses/>.
24  */
25 class BaseFrameworkSystem extends stdClass implements FrameworkInterface {
26         /**
27          * Instance of a request class
28          */
29         private $requestInstance = null;
30
31         /**
32          * Instance of a response class
33          */
34         private $responseInstance = null;
35
36         /**
37          * Search criteria instance
38          */
39         private $searchInstance = null;
40
41         /**
42          * Update criteria instance
43          */
44         private $updateInstance = null;
45
46         /**
47          * The file I/O instance for the template loader
48          */
49         private $fileIoInstance = null;
50
51         /**
52          * Resolver instance
53          */
54         private $resolverInstance = null;
55
56         /**
57          * Template engine instance
58          */
59         private $templateInstance = null;
60
61         /**
62          * Database result instance
63          */
64         private $resultInstance = null;
65
66         /**
67          * Instance for user class
68          */
69         private $userInstance = null;
70
71         /**
72          * A controller instance
73          */
74         private $controllerInstance = null;
75
76         /**
77          * Instance of a RNG
78          */
79         private $rngInstance = null;
80
81         /**
82          * Instance of an Iterator class
83          */
84         private $iteratorInstance = null;
85
86         /**
87          * Instance of the list
88          */
89         private $listInstance = null;
90
91         /**
92          * The real class name
93          */
94         private $realClass      = 'BaseFrameworkSystem';
95
96         /**
97          * Thousands seperator
98          */
99         private $thousands = '.'; // German
100
101         /**
102          * Decimal seperator
103          */
104         private $decimals  = ','; // German
105
106         /***********************
107          * Exception codes.... *
108          ***********************/
109         // @todo Try to clean these constants up
110         const EXCEPTION_IS_NULL_POINTER              = 0x001;
111         const EXCEPTION_IS_NO_OBJECT                 = 0x002;
112         const EXCEPTION_IS_NO_ARRAY                  = 0x003;
113         const EXCEPTION_MISSING_METHOD               = 0x004;
114         const EXCEPTION_CLASSES_NOT_MATCHING         = 0x005;
115         const EXCEPTION_INDEX_OUT_OF_BOUNDS          = 0x006;
116         const EXCEPTION_DIMENSION_ARRAY_INVALID      = 0x007;
117         const EXCEPTION_ITEM_NOT_TRADEABLE           = 0x008;
118         const EXCEPTION_ITEM_NOT_IN_PRICE_LIST       = 0x009;
119         const EXCEPTION_GENDER_IS_WRONG              = 0x00a;
120         const EXCEPTION_BIRTH_DATE_IS_INVALID        = 0x00b;
121         const EXCEPTION_EMPTY_STRUCTURES_ARRAY       = 0x00c;
122         const EXCEPTION_HAS_ALREADY_PERSONELL_LIST   = 0x00d;
123         const EXCEPTION_NOT_ENOUGTH_UNEMPLOYEES      = 0x00e;
124         const EXCEPTION_TOTAL_PRICE_NOT_CALCULATED   = 0x00f;
125         const EXCEPTION_HARBOR_HAS_NO_SHIPYARDS      = 0x010;
126         const EXCEPTION_CONTRACT_PARTNER_INVALID     = 0x011;
127         const EXCEPTION_CONTRACT_PARTNER_MISMATCH    = 0x012;
128         const EXCEPTION_CONTRACT_ALREADY_SIGNED      = 0x013;
129         const EXCEPTION_UNEXPECTED_EMPTY_STRING      = 0x014;
130         const EXCEPTION_PATH_NOT_FOUND               = 0x015;
131         const EXCEPTION_INVALID_PATH_NAME            = 0x016;
132         const EXCEPTION_READ_PROTECED_PATH           = 0x017;
133         const EXCEPTION_WRITE_PROTECED_PATH          = 0x018;
134         const EXCEPTION_DIR_POINTER_INVALID          = 0x019;
135         const EXCEPTION_FILE_POINTER_INVALID         = 0x01a;
136         const EXCEPTION_INVALID_RESOURCE             = 0x01b;
137         const EXCEPTION_UNEXPECTED_OBJECT            = 0x01c;
138         const EXCEPTION_LIMIT_ELEMENT_IS_UNSUPPORTED = 0x01d;
139         const EXCEPTION_GETTER_IS_MISSING            = 0x01e;
140         const EXCEPTION_ARRAY_EXPECTED               = 0x01f;
141         const EXCEPTION_ARRAY_HAS_INVALID_COUNT      = 0x020;
142         const EXCEPTION_ID_IS_INVALID_FORMAT         = 0x021;
143         const EXCEPTION_MD5_CHECKSUMS_MISMATCH       = 0x022;
144         const EXCEPTION_UNEXPECTED_STRING_SIZE       = 0x023;
145         const EXCEPTION_SIMULATOR_ID_INVALID         = 0x024;
146         const EXCEPTION_MISMATCHING_COMPRESSORS      = 0x025;
147         const EXCEPTION_CONTAINER_ITEM_IS_NULL       = 0x026;
148         const EXCEPTION_ITEM_IS_NO_ARRAY             = 0x027;
149         const EXCEPTION_CONTAINER_MAYBE_DAMAGED      = 0x028;
150         const EXCEPTION_INVALID_STRING               = 0x029;
151         const EXCEPTION_VARIABLE_NOT_SET             = 0x02a;
152         const EXCEPTION_ATTRIBUTES_ARE_MISSING       = 0x02b;
153         const EXCEPTION_ARRAY_ELEMENTS_MISSING       = 0x02c;
154         const EXCEPTION_TEMPLATE_ENGINE_UNSUPPORTED  = 0x02d;
155         const EXCEPTION_MISSING_LANGUAGE_HANDLER     = 0x02e;
156         const EXCEPTION_MISSING_FILE_IO_HANDLER      = 0x02f;
157         const EXCEPTION_MISSING_ELEMENT              = 0x030;
158         const EXCEPTION_HEADERS_ALREADY_SENT         = 0x031;
159         const EXCEPTION_DEFAULT_CONTROLLER_GONE      = 0x032;
160         const EXCEPTION_CLASS_NOT_FOUND              = 0x033;
161         const EXCEPTION_REQUIRED_INTERFACE_MISSING   = 0x034;
162         const EXCEPTION_FATAL_ERROR                  = 0x035;
163         const EXCEPTION_FILE_NOT_FOUND               = 0x036;
164         const EXCEPTION_ASSERTION_FAILED             = 0x037;
165         const EXCEPTION_FILE_CANNOT_BE_READ          = 0x038;
166         const EXCEPTION_DATABASE_UPDATED_NOT_ALLOWED = 0x039;
167         const EXCEPTION_FILTER_CHAIN_INTERCEPTED     = 0x040;
168
169         /**
170          * Protected super constructor
171          *
172          * @param       $className      Name of the class
173          * @return      void
174          */
175         protected function __construct ($className) {
176                 // Set real class
177                 $this->setRealClass($className);
178
179                 // Set configuration instance if no registry
180                 if (!$this instanceof Register) {
181                         // Because registries doesn't need to be configured
182                         $this->setConfigInstance(FrameworkConfiguration::getInstance());
183                 } // END - if
184         }
185
186         /**
187          * Destructor reached...
188          *
189          * @return      void
190          * @todo        This is old code. Do we still need this old lost code?
191          */
192         public function __destruct() {
193                 // Flush any updated entries to the database
194                 $this->flushPendingUpdates();
195
196                 // Is this object already destroyed?
197                 if ($this->__toString() != 'DestructedObject') {
198                         // Destroy all informations about this class but keep some text about it alive
199                         $this->setRealClass('DestructedObject');
200                 } elseif ((defined('DEBUG_DESTRUCTOR')) && (is_object($this->getDebugInstance()))) {
201                         // Already destructed object
202                         $this->debugOutput(sprintf("[%s:] The object <span class=\"object_name\">%s</span> is already destroyed.",
203                                 __CLASS__,
204                                 $this->__toString()
205                         ));
206                 }
207         }
208
209         /**
210          * The call method where all non-implemented methods end up
211          *
212          * @return      void
213          */
214         public final function __call ($methodName, $args) {
215                 // Implode all given arguments
216                 $argsString = '';
217                 if (empty($args)) {
218                         // No arguments
219                         $argsString = 'NULL';
220                 } elseif (is_array($args)) {
221                         // Some arguments are there
222                         foreach ($args as $arg) {
223                                 // Add the type
224                                 $argsString .= $arg . ' (' . gettype($arg);
225
226                                 // Add length if type is string
227                                 if (gettype($arg) == 'string') $argsString .= ', '.strlen($arg);
228
229                                 // Closing bracket
230                                 $argsString .= '), ';
231                         } // END - foreach
232
233                         // Remove last comma
234                         if (substr($argsString, -2, 1) == ',') {
235                                 $argsString = substr($argsString, 0, -2);
236                         } // END - if
237                 } else {
238                         // Invalid arguments!
239                         $argsString = '!INVALID:' . gettype($args) . '!';
240                 }
241
242                 // Output stub message
243                 $this->debugOutput(sprintf("[%s-&gt;%s] Stub! Args: %s",
244                         $this->__toString(),
245                         $methodName,
246                         $argsString
247                 ));
248
249                 // Return nothing
250                 return null;
251         }
252
253         /**
254          * Setter for database result instance
255          *
256          * @param       $resultInstance         An instance of a database result class
257          * @return      void
258          * @todo        SearchableResult and UpdateableResult shall have a super interface to use here
259          */
260         protected final function setResultInstance (SearchableResult $resultInstance) {
261                 $this->resultInstance =  $resultInstance;
262         }
263
264         /**
265          * Getter for database result instance
266          *
267          * @return      $resultInstance         An instance of a database result class
268          */
269         public final function getResultInstance () {
270                 return $this->resultInstance;
271         }
272
273         /**
274          * Setter for template engine instances
275          *
276          * @param       $templateInstance       An instance of a template engine class
277          * @return      void
278          */
279         protected final function setTemplateInstance (CompileableTemplate $templateInstance) {
280                 $this->templateInstance = $templateInstance;
281         }
282
283         /**
284          * Getter for template engine instances
285          *
286          * @return      $templateInstance       An instance of a template engine class
287          */
288         protected final function getTemplateInstance () {
289                 return $this->templateInstance;
290         }
291
292         /**
293          * Setter for search instance
294          *
295          * @param       $searchInstance         Searchable criteria instance
296          * @return      void
297          */
298         public final function setSearchInstance (LocalSearchCriteria $searchInstance) {
299                 $this->searchInstance = $searchInstance;
300         }
301
302         /**
303          * Getter for search instance
304          *
305          * @return      $searchInstance         Searchable criteria instance
306          */
307         public final function getSearchInstance () {
308                 return $this->searchInstance;
309         }
310
311         /**
312          * Setter for update instance
313          *
314          * @param       $updateInstance         Searchable criteria instance
315          * @return      void
316          */
317         public final function setUpdateInstance (LocalUpdateCriteria $updateInstance) {
318                 $this->updateInstance = $updateInstance;
319         }
320
321         /**
322          * Getter for update instance
323          *
324          * @return      $updateInstance         Updateable criteria instance
325          */
326         public final function getUpdateInstance () {
327                 return $this->updateInstance;
328         }
329
330         /**
331          * Setter for resolver instance
332          *
333          * @param       $resolverInstance               Instance of a command resolver class
334          * @return      void
335          */
336         public final function setResolverInstance (Resolver $resolverInstance) {
337                 $this->resolverInstance = $resolverInstance;
338         }
339
340         /**
341          * Getter for resolver instance
342          *
343          * @return      $resolverInstance               Instance of a command resolver class
344          */
345         public final function getResolverInstance () {
346                 return $this->resolverInstance;
347         }
348
349         /**
350          * Setter for language instance
351          *
352          * @param       $configInstance         The configuration instance which shall
353          *                                                              be FrameworkConfiguration
354          * @return      void
355          */
356         public final function setConfigInstance (FrameworkConfiguration $configInstance) {
357                 Registry::getRegistry()->addInstance('config', $configInstance);
358         }
359
360         /**
361          * Getter for configuration instance
362          *
363          * @return      $configInstance         Configuration instance
364          */
365         public final function getConfigInstance () {
366                 $configInstance = Registry::getRegistry()->getInstance('config');
367                 return $configInstance;
368         }
369
370         /**
371          * Setter for debug instance
372          *
373          * @param       $debugInstance  The instance for debug output class
374          * @return      void
375          */
376         public final function setDebugInstance (DebugMiddleware $debugInstance) {
377                 Registry::getRegistry()->addInstance('debug', $debugInstance);
378         }
379
380         /**
381          * Getter for debug instance
382          *
383          * @return      $debugInstance  Instance to class DebugConsoleOutput or DebugWebOutput
384          */
385         public final function getDebugInstance () {
386                 // Get debug instance
387                 $debugInstance = Registry::getRegistry()->getInstance('debug');
388
389                 // Return it
390                 return $debugInstance;
391         }
392
393         /**
394          * Setter for web output instance
395          *
396          * @param               $webInstance    The instance for web output class
397          * @return      void
398          */
399         public final function setWebOutputInstance (OutputStreamer $webInstance) {
400                 Registry::getRegistry()->addInstance('web_output', $webInstance);
401         }
402
403         /**
404          * Getter for web output instance
405          *
406          * @return      $webOutputInstance - Instance to class WebOutput
407          */
408         public final function getWebOutputInstance () {
409                 $webOutputInstance = Registry::getRegistry()->getInstance('web_output');
410                 return $webOutputInstance;
411         }
412
413         /**
414          * Setter for database instance
415          *
416          * @param               $dbInstance     The instance for the database connection
417          *                                      (forced DatabaseConnection)
418          * @return      void
419          */
420         public final function setDatabaseInstance (DatabaseConnection $dbInstance) {
421                 Registry::getRegistry()->addInstance('db_instance', $dbInstance);
422         }
423
424         /**
425          * Getter for database layer
426          *
427          * @return      $dbInstance     The database layer instance
428          */
429         public final function getDatabaseInstance () {
430                 // Get instance
431                 $dbInstance = Registry::getRegistry()->getInstance('db_instance');
432
433                 // Return instance
434                 return $dbInstance;
435         }
436
437         /**
438          * Setter for compressor channel
439          *
440          * @param               $compressorInstance             An instance of CompressorChannel
441          * @return      void
442          */
443         public final function setCompressorChannel (CompressorChannel $compressorInstance) {
444                 Registry::getRegistry()->addInstance('compressor', $compressorInstance);
445         }
446
447         /**
448          * Getter for compressor channel
449          *
450          * @return      $compressorInstance             The compressor channel
451          */
452         public final function getCompressorChannel () {
453                 $compressorInstance = Registry::getRegistry()->getInstance('compressor');
454                 return $compressorInstance;
455         }
456
457         /**
458          * Protected getter for a manageable application helper class
459          *
460          * @return      $applicationInstance    An instance of a manageable application helper class
461          */
462         protected final function getApplicationInstance () {
463                 $applicationInstance = Registry::getRegistry()->getInstance('application');
464                 return $applicationInstance;
465         }
466
467         /**
468          * Setter for a manageable application helper class
469          *
470          * @param       $applicationInstance    An instance of a manageable application helper class
471          * @return      void
472          */
473         public final function setApplicationInstance (ManageableApplication $applicationInstance) {
474                 Registry::getRegistry()->addInstance('application', $applicationInstance);
475         }
476
477         /**
478          * Setter for request instance
479          *
480          * @param       $requestInstance        An instance of a Requestable class
481          * @return      void
482          */
483         public final function setRequestInstance (Requestable $requestInstance) {
484                 $this->requestInstance = $requestInstance;
485         }
486
487         /**
488          * Getter for request instance
489          *
490          * @return      $requestInstance        An instance of a Requestable class
491          */
492         public final function getRequestInstance () {
493                 return $this->requestInstance;
494         }
495
496         /**
497          * Setter for response instance
498          *
499          * @param       $responseInstance       An instance of a Responseable class
500          * @return      void
501          */
502         public final function setResponseInstance (Responseable $responseInstance) {
503                 $this->responseInstance = $responseInstance;
504         }
505
506         /**
507          * Getter for response instance
508          *
509          * @return      $responseInstance       An instance of a Responseable class
510          */
511         public final function getResponseInstance () {
512                 return $this->responseInstance;
513         }
514
515         /**
516          * Getter for $realClass
517          *
518          * @return      $realClass The name of the real class (not BaseFrameworkSystem)
519          */
520         public final function __toString () {
521                 return $this->realClass;
522         }
523
524         /**
525          * Setter for the real class name
526          *
527          * @param               $realClass      Class name (string)
528          * @return      void
529          */
530         public final function setRealClass ($realClass) {
531                 // Cast to string
532                 $realClass = (string) $realClass;
533
534                 // Set real class
535                 $this->realClass = $realClass;
536         }
537
538         /**
539          * Checks wether an object equals this object. You should overwrite this
540          * method to implement own equality checks
541          *
542          * @param       $objectInstance         An instance of a FrameworkInterface object
543          * @return      $equals                         Wether both objects equals
544          */
545         public function equals (FrameworkInterface $objectInstance) {
546                 // Now test it
547                 $equals = ((
548                         $this->__toString() == $objectInstance->__toString()
549                 ) && (
550                         $this->hashCode() == $objectInstance->hashCode()
551                 ));
552
553                 // Return the result
554                 return $result;
555         }
556
557         /**
558          * Formats computer generated price values into human-understandable formats
559          * with thousand and decimal seperators.
560          *
561          * @param       $value          The in computer format value for a price
562          * @param       $currency       The currency symbol (use HTML-valid characters!)
563          * @param       $decNum         Number of decimals after commata
564          * @return      $price          The for the current language formated price string
565          * @throws      MissingDecimalsThousandsSeperatorException      If decimals or
566          *                                                                                              thousands seperator
567          *                                                                                              is missing
568          */
569         public function formatCurrency ($value, $currency = '&euro;', $decNum = 2) {
570                 // Are all required attriutes set?
571                 if ((!isset($this->decimals)) || (!isset($this->thousands))) {
572                         // Throw an exception
573                         throw new MissingDecimalsThousandsSeperatorException($this, self::EXCEPTION_ATTRIBUTES_ARE_MISSING);
574                 }
575
576                 // Cast the number
577                 $value = (float) $value;
578
579                 // Reformat the US number
580                 $price = number_format($value, $decNum, $this->decimals, $this->thousands) . $currency;
581
582                 // Return as string...
583                 return $price;
584         }
585
586         /**
587          * Private getter for language instance
588          *
589          * @return      $langInstance   An instance to the language sub-system
590          */
591         protected final function getLanguageInstance () {
592                 $langInstance = Registry::getRegistry()->getInstance('language');
593                 return $langInstance;
594         }
595
596         /**
597          * Setter for language instance
598          *
599          * @param       $langInstance   An instance to the language sub-system
600          * @return      void
601          * @see         LanguageSystem
602          */
603         public final function setLanguageInstance (ManageableLanguage $langInstance) {
604                 Registry::getRegistry()->addInstance('language', $langInstance);
605         }
606
607         /**
608          * Appends a trailing slash to a string
609          *
610          * @param       $str            A string (maybe) without trailing slash
611          * @return      $str            A string with an auto-appended trailing slash
612          */
613         public final function addMissingTrailingSlash ($str) {
614                 // Is there a trailing slash?
615                 if (substr($str, -1, 1) != '/') $str .= '/';
616                 return $str;
617         }
618
619         /**
620          * Private getter for file IO instance
621          *
622          * @return      $fileIoInstance An instance to the file I/O sub-system
623          */
624         protected final function getFileIoInstance () {
625                 return $this->fileIoInstance;
626         }
627
628         /**
629          * Setter for file I/O instance
630          *
631          * @param       $fileIoInstance An instance to the file I/O sub-system
632          * @return      void
633          */
634         public final function setFileIoInstance (FileIoHandler $fileIoInstance) {
635                 $this->fileIoInstance = $fileIoInstance;
636         }
637
638         /**
639          * Prepare the template engine (WebTemplateEngine by default) for a given
640          * application helper instance (ApplicationHelper by default).
641          *
642          * @param               $appInstance                    An application helper instance or
643          *                                                                              null if we shall use the default
644          * @return              $templateInstance                               The template engine instance
645          * @throws              NullPointerException    If the template engine could not
646          *                                                                              be initialized
647          * @throws              UnsupportedTemplateEngineException      If $templateInstance is an
648          *                                                                              unsupported template engine
649          * @throws              MissingLanguageHandlerException If the language sub-system
650          *                                                                              is not yet initialized
651          * @throws              NullPointerException    If the discovered application
652          *                                                                              instance is still null
653          */
654         protected function prepareTemplateInstance (FrameworkInterface $appInstance=null) {
655                 // Is the application instance set?
656                 if (is_null($appInstance)) {
657                         // Get the current instance
658                         $appInstance = $this->getApplicationInstance();
659
660                         // Still null?
661                         if (is_null($appInstance)) {
662                                 // Thrown an exception
663                                 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
664                         } // END - if
665                 } // END - if
666
667                 // Are both instances set?
668                 if ($appInstance->getLanguageInstance() === null) {
669                         // Invalid language instance
670                         throw new MissingLanguageHandlerException($appInstance, self::EXCEPTION_MISSING_LANGUAGE_HANDLER);
671                 } elseif ($appInstance->getFileIoInstance() === null) {
672                         // Invalid language instance
673                         throw new MissingFileIoHandlerException($appInstance, self::EXCEPTION_MISSING_FILE_IO_HANDLER);
674                 }
675
676                 // Initialize the template engine
677                 $templateInstance = ObjectFactory::createObjectByConfiguredName('template_class', array($appInstance));
678
679                 // Return the prepared instance
680                 return $templateInstance;
681         }
682
683         /**
684          * Debugs this instance by putting out it's full content
685          *
686          * @param       $message        Optional message to show in debug output
687          * @return      void
688          */
689         public final function debugInstance ($message = '') {
690                 // Restore the error handler to avoid trouble with missing array elements or undeclared variables
691                 restore_error_handler();
692
693                 // Init content
694                 $content = '';
695
696                 // Is a message set?
697                 if (!empty($message)) {
698                         // Construct message
699                         $content = sprintf("<div class=\"debug_message\">Message: %s</div>\n", $message);
700                 } // END - if
701
702                 // Generate the output
703                 $content .= sprintf("<pre>%s</pre>",
704                         trim(
705                                 htmlentities(
706                                         print_r($this, true)
707                                 )
708                         )
709                 );
710
711                 // Output it
712                 ApplicationEntryPoint::app_die(sprintf("<div class=\"debug_header\">%s debug output:</div><div class=\"debug_content\">%s</div>\nLoaded includes: <div class=\"debug_include_list\">%s</div>",
713                         $this->__toString(),
714                         $content,
715                         ClassLoader::getInstance()->getPrintableIncludeList()
716                 ));
717         }
718
719         /**
720          * Output a partial stub message for the caller method
721          *
722          * @param       $message        An optional message to display
723          * @return      void
724          */
725         protected function partialStub ($message = '') {
726                 // Get the backtrace
727                 $backtrace = debug_backtrace();
728
729                 // Generate the class::method string
730                 $methodName = 'UnknownClass-&gt;unknownMethod';
731                 if ((isset($backtrace[1]['class'])) && (isset($backtrace[1]['function']))) {
732                         $methodName = $backtrace[1]['class']."-&gt;".$backtrace[1]['function'];
733                 } // END - if
734
735                 // Construct the full message
736                 $stubMessage = sprintf("[%s:] Partial stub!",
737                         $methodName
738                 );
739
740                 // Is the extra message given?
741                 if (!empty($message)) {
742                         // Then add it as well
743                         $stubMessage .= sprintf(" Message: <span id=\"stub_message\">%s</span>", $message);
744                 } // END - if
745
746                 // Debug instance is there?
747                 if (!is_null($this->getDebugInstance())) {
748                         // Output stub message
749                         $this->debugOutput($stubMessage);
750                 } else {
751                         // Trigger an error
752                         trigger_error($stubMessage."<br />\n");
753                 }
754         }
755
756         /**
757          * Outputs a debug backtrace and stops further script execution
758          *
759          * @return      void
760          */
761         public function debugBackTrace () {
762                 // Sorry, there is no other way getting this nice backtrace
763                 print("<pre>\n");
764                 debug_print_backtrace();
765                 print("</pre>");
766                 exit();
767         }
768
769         /**
770          * Outputs a debug message wether to debug instance (should be set!) or dies with or pints the message
771          *
772          * @param       $message        Message we shall send out...
773          * @param       $doPrint        Wether we shall print or die here which first is the default
774          * @return      void
775          */
776         public function debugOutput ($message, $doPrint = true) {
777                 // Get debug instance
778                 $debugInstance = $this->getDebugInstance();
779
780                 // Is the debug instance there?
781                 if (is_object($debugInstance)) {
782                         // Use debug output handler
783                         $debugInstance->output($message);
784                         if ($doPrint === false) die(); // Die here if not printed
785                 } else {
786                         // Put directly out
787                         if ($doPrint === true) {
788                                 print($message);
789                         } else {
790                                 // DO NOT REWRITE THIS TO app_die() !!!
791                                 die($message);
792                         }
793                 }
794         }
795
796         /**
797          * Converts e.g. a command from URL to a valid class by keeping out bad characters
798          *
799          * @param       $str            The string, what ever it is needs to be converted
800          * @return      $className      Generated class name
801          */
802         public function convertToClassName ($str) {
803                 // Init class name
804                 $className = '';
805
806                 // Convert all dashes in underscores
807                 $str = $this->convertDashesToUnderscores($str);
808
809                 // Now use that underscores to get classname parts for hungarian style
810                 foreach (explode('_', $str) as $strPart) {
811                         // Make the class name part lower case and first upper case
812                         $className .= ucfirst(strtolower($strPart));
813                 } // END - foreach
814
815                 // Return class name
816                 return $className;
817         }
818
819         /**
820          * Converts dashes to underscores, e.g. useable for configuration entries
821          *
822          * @param       $str    The string with maybe dashes inside
823          * @return      $str    The converted string with no dashed, but underscores
824          */
825         public final function convertDashesToUnderscores ($str) {
826                 // Convert them all
827                 $str = str_replace('-', '_', $str);
828
829                 // Return converted string
830                 return $str;
831         }
832
833         /**
834          * Marks up the code by adding e.g. line numbers
835          *
836          * @param       $phpCode                Unmarked PHP code
837          * @return      $markedCode             Marked PHP code
838          */
839         public function markupCode ($phpCode) {
840                 // Init marked code
841                 $markedCode = '';
842
843                 // Get last error
844                 $errorArray = error_get_last();
845
846                 // Init the code with error message
847                 if (is_array($errorArray)) {
848                         // Get error infos
849                         $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>",
850                                 basename($errorArray['file']),
851                                 $errorArray['line'],
852                                 $errorArray['message'],
853                                 $errorArray['type']
854                         );
855                 } // END - if
856
857                 // Add line number to the code
858                 foreach (explode("\n", $phpCode) as $lineNo => $code) {
859                         // Add line numbers
860                         $markedCode .= sprintf("<span id=\"code_line\">%s</span>: %s\n",
861                                 ($lineNo + 1),
862                                 htmlentities($code, ENT_QUOTES)
863                         );
864                 } // END - foreach
865
866                 // Return the code
867                 return $markedCode;
868         }
869
870         /**
871          * Filter a given GMT timestamp (non Uni* stamp!) to make it look more
872          * beatiful for web-based front-ends. If null is given a message id
873          * null_timestamp will be resolved and returned.
874          *
875          * @param       $timestamp      Timestamp to prepare (filter) for display
876          * @return      $readable       A readable timestamp
877          */
878         public function doFilterFormatTimestamp ($timestamp) {
879                 // Default value to return
880                 $readable = '???';
881
882                 // Is the timestamp null?
883                 if (is_null($timestamp)) {
884                         // Get a message string
885                         $readable = $this->getLanguageInstance()->getMessage('null_timestamp');
886                 } else {
887                         switch ($this->getLanguageInstance()->getLanguageCode()) {
888                                 case "de": // German format is a bit different to default
889                                         // Split the GMT stamp up
890                                         $dateTime  = explode(' ', $timestamp  );
891                                         $dateArray = explode('-', $dateTime[0]);
892                                         $timeArray = explode(':', $dateTime[1]);
893
894                                         // Construct the timestamp
895                                         $readable = sprintf($this->getConfigInstance()->getConfigEntry('german_date_time'),
896                                                 $dateArray[0],
897                                                 $dateArray[1],
898                                                 $dateArray[2],
899                                                 $timeArray[0],
900                                                 $timeArray[1],
901                                                 $timeArray[2]
902                                         );
903                                         break;
904
905                                 default: // Default is pass-through
906                                         $readable = $timestamp;
907                                         break;
908                         }
909                 }
910
911                 // Return the stamp
912                 return $readable;
913         }
914
915         /**
916          * "Getter" for databse entry
917          *
918          * @return      $entry  An array with database entries
919          * @throws      NullPointerException    If the database result is not found
920          * @throws      InvalidDatabaseResultException  If the database result is invalid
921          */
922         protected final function getDatabaseEntry () {
923                 // Is there an instance?
924                 if (is_null($this->getResultInstance())) {
925                         // Throw an exception here
926                         throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
927                 } // END - if
928
929                 // Rewind it
930                 $this->getResultInstance()->rewind();
931
932                 // Do we have an entry?
933                 if ($this->getResultInstance()->valid() === false) {
934                         throw new InvalidDatabaseResultException(array($this, $this->getResultInstance()), DatabaseResult::EXCEPTION_INVALID_DATABASE_RESULT);
935                 } // END - if
936
937                 // Get next entry
938                 $this->getResultInstance()->next();
939
940                 // Fetch it
941                 $entry = $this->getResultInstance()->current();
942
943                 // And return it
944                 return $entry;
945         }
946
947         /**
948          * Getter for field name
949          *
950          * @param       $fieldName              Field name which we shall get
951          * @return      $fieldValue             Field value from the user
952          * @throws      NullPointerException    If the result instance is null
953          */
954         public final function getField ($fieldName) {
955                 // Default field value
956                 $fieldValue = null;
957
958                 // Get result instance
959                 $resultInstance = $this->getResultInstance();
960
961                 // Is this instance null?
962                 if (is_null($resultInstance)) {
963                         // Then the user instance is no longer valid (expired cookies?)
964                         throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
965                 } // END - if
966
967                 // Get current array
968                 $fieldArray = $resultInstance->current();
969
970                 // Does the field exist?
971                 if (isset($fieldArray[$fieldName])) {
972                         // Get it
973                         $fieldValue = $fieldArray[$fieldName];
974                 } // END - if
975
976                 // Return it
977                 return $fieldValue;
978         }
979
980         /**
981          * Protected setter for user instance
982          *
983          * @param       $userInstance   An instance of a user class
984          * @return      void
985          */
986         protected final function setUserInstance (ManageableAccount $userInstance) {
987                 $this->userInstance = $userInstance;
988         }
989
990         /**
991          * Getter for user instance
992          *
993          * @return      $userInstance   An instance of a user class
994          */
995         public final function getUserInstance () {
996                 return $this->userInstance;
997         }
998
999         /**
1000          * Setter for controller instance (this surely breaks a bit the MVC patterm)
1001          *
1002          * @param       $controllerInstance             An instance of the controller
1003          * @return      void
1004          */
1005         public final function setControllerInstance (Controller $controllerInstance) {
1006                 $this->controllerInstance = $controllerInstance;
1007         }
1008
1009         /**
1010          * Getter for controller instance (this surely breaks a bit the MVC patterm)
1011          *
1012          * @return      $controllerInstance             An instance of the controller
1013          */
1014         public final function getControllerInstance () {
1015                 return $this->controllerInstance;
1016         }
1017
1018         /**
1019          * Flushs all pending updates to the database layer
1020          *
1021          * @return      void
1022          */
1023         public function flushPendingUpdates () {
1024                 // Get result instance
1025                 $resultInstance = $this->getResultInstance();
1026
1027                 // Do we have data to update?
1028                 if ((is_object($resultInstance)) && ($resultInstance->ifDataNeedsFlush())) {
1029                         // Get wrapper class name config entry
1030                         $configEntry = $resultInstance->getUpdateInstance()->getWrapperConfigEntry();
1031
1032                         // Create object instance
1033                         $wrapperInstance = ObjectFactory::createObjectByConfiguredName($configEntry);
1034
1035                         // Yes, then send the whole result to the database layer
1036                         $wrapperInstance->doUpdateByResult($this->getResultInstance());
1037                 } // END - if
1038         }
1039
1040         /**
1041          * Outputs a deprecation warning to the developer.
1042          *
1043          * @param       $message        The message we shall output to the developer
1044          * @return      void
1045          * @todo        Write a logging mechanism for productive mode
1046          */
1047         public function deprecationWarning ($message) {
1048                 // Is developer mode active?
1049                 if (defined('DEVELOPER')) {
1050                         // Debug instance is there?
1051                         if (!is_null($this->getDebugInstance())) {
1052                                 // Output stub message
1053                                 $this->debugOutput($message);
1054                         } else {
1055                                 // Trigger an error
1056                                 trigger_error($message."<br />\n");
1057                         }
1058                 } else {
1059                         // @TODO Finish this part!
1060                         $this->partialStub('Developer mode inactive. Message:' . $message);
1061                 }
1062         }
1063
1064         /**
1065          * Generates a generic hash code of this class. You should really overwrite
1066          * this method with your own hash code generator code. But keep KISS in mind.
1067          *
1068          * @return      $hashCode       A generic hash code respresenting this whole class
1069          */
1070         public function hashCode () {
1071                 // Simple hash code
1072                 return crc32($this->__toString());
1073         }
1074
1075         /**
1076          * Checks wether the given PHP extension is loaded
1077          *
1078          * @param       $phpExtension   The PHP extension we shall check
1079          * @return      $isLoaded       Wether the PHP extension is loaded
1080          */
1081         public final function isPhpExtensionLoaded ($phpExtension) {
1082                 // Is it loaded?
1083                 $isLoaded = in_array($phpExtension, get_loaded_extensions());
1084
1085                 // Return result
1086                 return $isLoaded;
1087         }
1088
1089         /**
1090          * Setter for RNG instance
1091          *
1092          * @param       $rngInstance    An instance of a random number generator (RNG)
1093          * @return      void
1094          */
1095         protected final function setRngInstance (RandomNumberGenerator $rngInstance) {
1096                 $this->rngInstance = $rngInstance;
1097         }
1098
1099         /**
1100          * Getter for RNG instance
1101          *
1102          * @return      $rngInstance    An instance of a random number generator (RNG)
1103          */
1104         public final function getRngInstance () {
1105                 return $this->rngInstance;
1106         }
1107
1108         /**
1109          * Setter for Iterator instance
1110          *
1111          * @param       $iteratorInstance       An instance of an Iterator
1112          * @return      void
1113          */
1114         protected final function setIteratorInstance (Iterator $iteratorInstance) {
1115                 $this->iteratorInstance = $iteratorInstance;
1116         }
1117
1118         /**
1119          * Getter for Iterator instance
1120          *
1121          * @return      $iteratorInstance       An instance of an Iterator
1122          */
1123         public final function getIteratorInstance () {
1124                 return $this->iteratorInstance;
1125         }
1126
1127         /**
1128          * "Getter" as a time() replacement but with milliseconds. You should use this
1129          * method instead of the encapsulated getimeofday() function.
1130          *
1131          * @return      $milliTime      Timestamp with milliseconds
1132          */
1133         public function getMilliTime () {
1134                 // Get the time of day as float
1135                 $milliTime = gettimeofday(true);
1136
1137                 // Return it
1138                 return $milliTime;
1139         }
1140
1141         /**
1142          * Idles (sleeps) for given milliseconds
1143          *
1144          * @return      $hasSlept       Wether it goes fine
1145          */
1146         public function idle ($milliSeconds) {
1147                 // Sleep is fine by default
1148                 $hasSlept = true;
1149
1150                 // Idle so long with found function
1151                 if (function_exists('time_sleep_until')) {
1152                         // Get current time and add idle time
1153                         $sleepUntil = $this->getMilliTime() + abs($milliSeconds) / 1000;
1154
1155                         // New PHP 5.1.0 function found
1156                         $hasSlept = time_sleep_until($sleepUntil);
1157                 } else {
1158                         // My Sun Station doesn't have that function even with latest PHP
1159                         // package. :(
1160                         usleep($milliSeconds * 1000);
1161                 }
1162
1163                 // Return result
1164                 return $hasSlept;
1165         }
1166
1167         /**
1168          * Setter for the list instance
1169          *
1170          * @param       $listInstance   A list of Listable
1171          * @return      void
1172          */
1173         protected final function setListInstance (Listable $listInstance) {
1174                 $this->listInstance = $listInstance;
1175         }
1176
1177         /**
1178          * Getter for the list instance
1179          *
1180          * @return      $listInstance   A list of Listable
1181          */
1182         protected final function getListInstance () {
1183                 return $this->listInstance;
1184         }
1185 }
1186
1187 // [EOF]
1188 ?>