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