Simple exception handler and error handler added, profile update added with stubs
[shipsimu.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, this is free software
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 to an application helper class
28          */
29         private static $applicationInstance = null;
30
31         /**
32          * The language instance for the template loader
33          */
34         private static $langInstance = null;
35
36         /**
37          * Instance of a request class
38          */
39         private $requestInstance = null;
40
41         /**
42          * Instance of a response class
43          */
44         private $responseInstance = null;
45
46         /**
47          * Search criteria instance
48          */
49         private $searchInstance = null;
50
51         /**
52          * The real class name
53          */
54         private $realClass      = "FrameworkSystem";
55
56         /**
57          * A human-readable description for this simulator part
58          */
59         private $objectDescription      = "Namenlose Framework-Einheit";
60
61         /**
62          * The unique ID string for identifying all type of classes
63          */
64         private $uniqueID = "";
65
66         /**
67          * Thousands seperator
68          */
69         private $thousands = "."; // German
70
71         /**
72          * Decimal seperator
73          */
74         private $decimals  = ","; // German
75
76         /**
77          * The file I/O instance for the template loader
78          */
79         private $fileIoInstance = null;
80
81         /***********************
82          * Exception codes.... *
83          ***********************/
84
85         const EXCEPTION_IS_NULL_POINTER              = 0x001;
86         const EXCEPTION_IS_NO_OBJECT                 = 0x002;
87         const EXCEPTION_IS_NO_ARRAY                  = 0x003;
88         const EXCEPTION_MISSING_METHOD               = 0x004;
89         const EXCEPTION_CLASSES_NOT_MATCHING         = 0x005;
90         const EXCEPTION_INDEX_OUT_OF_BOUNDS          = 0x006;
91         const EXCEPTION_DIMENSION_ARRAY_INVALID      = 0x007;
92         const EXCEPTION_ITEM_NOT_TRADEABLE           = 0x008;
93         const EXCEPTION_ITEM_NOT_IN_PRICE_LIST       = 0x009;
94         const EXCEPTION_GENDER_IS_WRONG              = 0x00a;
95         const EXCEPTION_BIRTH_DATE_IS_INVALID        = 0x00b;
96         const EXCEPTION_EMPTY_STRUCTURES_ARRAY       = 0x00c;
97         const EXCEPTION_HAS_ALREADY_PERSONELL_LIST   = 0x00d;
98         const EXCEPTION_NOT_ENOUGTH_UNEMPLOYEES      = 0x00e;
99         const EXCEPTION_TOTAL_PRICE_NOT_CALCULATED   = 0x00f;
100         const EXCEPTION_HARBOR_HAS_NO_SHIPYARDS      = 0x010;
101         const EXCEPTION_CONTRACT_PARTNER_INVALID     = 0x011;
102         const EXCEPTION_CONTRACT_PARTNER_MISMATCH    = 0x012;
103         const EXCEPTION_CONTRACT_ALREADY_SIGNED      = 0x013;
104         const EXCEPTION_UNEXPECTED_EMPTY_STRING      = 0x014;
105         const EXCEPTION_PATH_NOT_FOUND               = 0x015;
106         const EXCEPTION_INVALID_PATH_NAME            = 0x016;
107         const EXCEPTION_READ_PROTECED_PATH           = 0x017;
108         const EXCEPTION_WRITE_PROTECED_PATH          = 0x018;
109         const EXCEPTION_DIR_POINTER_INVALID          = 0x019;
110         const EXCEPTION_FILE_POINTER_INVALID         = 0x01a;
111         const EXCEPTION_INVALID_DIRECTORY_POINTER    = 0x01b;
112         const EXCEPTION_UNEXPECTED_OBJECT            = 0x01c;
113         const EXCEPTION_LIMIT_ELEMENT_IS_UNSUPPORTED = 0x01d;
114         const EXCEPTION_GETTER_IS_MISSING            = 0x01e;
115         const EXCEPTION_ARRAY_EXPECTED               = 0x01f;
116         const EXCEPTION_ARRAY_HAS_INVALID_COUNT      = 0x020;
117         const EXCEPTION_ID_IS_INVALID_FORMAT         = 0x021;
118         const EXCEPTION_MD5_CHECKSUMS_MISMATCH       = 0x022;
119         const EXCEPTION_UNEXPECTED_STRING_SIZE       = 0x023;
120         const EXCEPTION_SIMULATOR_ID_INVALID         = 0x024;
121         const EXCEPTION_MISMATCHING_COMPRESSORS      = 0x025;
122         const EXCEPTION_CONTAINER_ITEM_IS_NULL       = 0x026;
123         const EXCEPTION_ITEM_IS_NO_ARRAY             = 0x027;
124         const EXCEPTION_CONTAINER_MAYBE_DAMAGED      = 0x028;
125         const EXCEPTION_INVALID_STRING               = 0x029;
126         const EXCEPTION_VARIABLE_NOT_SET             = 0x02a;
127         const EXCEPTION_ATTRIBUTES_ARE_MISSING       = 0x02b;
128         const EXCEPTION_ARRAY_ELEMENTS_MISSING       = 0x02c;
129         const EXCEPTION_TEMPLATE_ENGINE_UNSUPPORTED  = 0x02d;
130         const EXCEPTION_MISSING_LANGUAGE_HANDLER     = 0x02e;
131         const EXCEPTION_MISSING_FILE_IO_HANDLER      = 0x02f;
132         const EXCEPTION_MISSING_ELEMENT              = 0x030;
133         const EXCEPTION_INVALID_COMMAND              = 0x031;
134         const EXCEPTION_INVALID_CONTROLLER           = 0x032;
135         const EXCEPTION_HEADERS_ALREADY_SENT         = 0x033;
136         const EXCEPTION_DEFAUL_CONTROLLER_GONE       = 0x034;
137         const EXCEPTION_CLASS_NOT_FOUND              = 0x035;
138         const EXCEPTION_REQUIRED_INTERFACE_MISSING   = 0x036;
139         const EXCEPTION_FATAL_ERROR                  = 0x037;
140         const EXCEPTION_FILE_NOT_FOUND               = 0x038;
141
142         /**
143          * In the super constructor these system classes shall be ignored or else
144          * we would get an endless calling loop.
145          *
146          *--------------------------------------------------------------------*
147          * ATTENTION: IF YOU REMOVE ONE OF THEM YOU WILL SHOOT YOUR SERVER!!! *
148          *--------------------------------------------------------------------*
149          */
150         private $systemClasses = array(
151                 "DebugMiddleware",                              // Debug middleware output sub-system
152                 "Registry",                                             // Object registry
153                 "ObjectFactory",                                // Object factory
154                 "DebugWebOutput",                               // Debug web output sub-system
155                 "WebOutput",                                    // Web output sub-system
156                 "CompressorChannel",                    // Compressor sub-system
157                 "DebugConsoleOutput",                   // Debug console output sub-system
158                 "DebugErrorLogOutput",                  // Debug error_log() output sub-system
159                 "FrameworkDirectoryPointer",    // Directory handler sub-system
160                 "NullCompressor",                               // Null compressor
161                 "Bzip2Compressor",                              // BZIP2 compressor
162                 "GzipCompressor",                               // GZIP compressor
163         );
164
165         /* No longer used:
166         */
167
168         /**
169          * Private super constructor
170          *
171          * @return      void
172          */
173         protected function __construct ($class) {
174                 // Set real class
175                 $this->setRealClass($class);
176
177                 // Initialize the class if the registry is there
178                 if ((class_exists('Registry')) && (Registry::isInitialized() === false)) {
179                         $this->initInstance();
180                 }
181         }
182
183         /**
184          * Destructor reached...
185          *
186          * @return      void
187          */
188         public function __destruct() {
189                 // Is this object already destroyed?
190                 if ($this->__toString() != "DestructedObject") {
191                         // Debug message
192                         if ((defined('DEBUG_DESTRUCTOR')) && (is_object($this->getDebugInstance()))) {
193                                 $this->getDebugInstance()->output(sprintf("[%s:] Das Objekt <strong>%s</strong> wird zerst&ouml;rt.<br />\n",
194                                         __CLASS__, $this->__toString()
195                                 ));
196                         }
197
198                         // Destroy all informations about this class but keep some text about it alive
199                         $this->setObjectDescription(sprintf("Entferntes Objekt <em>%s</em>", $this->__toString()));
200                         $this->setRealClass("DestructedObject");
201                         $this->resetUniqueID();
202                 } elseif ((defined('DEBUG_DESTRUCTOR')) && (is_object($this->getDebugInstance()))) {
203                         // Already destructed object
204                         $this->getDebugInstance()->output(sprintf("[%s:] Das Objekt <strong>%s</strong> wurde bereits zerst&ouml;rt.<br />\n",
205                                 __CLASS__, $this->__toString()
206                         ));
207                 }
208         }
209
210         /**
211          * The call method where all non-implemented methods end up
212          *
213          * @return      void
214          */
215         public final function __call ($methodName, $args) {
216                 // Implode all given arguments
217                 $argsString = "";
218                 if (empty($args)) {
219                         // No arguments
220                         $argsString = "NULL";
221                 } elseif (is_array($args)) {
222                         // Some arguments are there
223                         foreach ($args as $arg) {
224                                 // Check the type
225                                 if (is_bool($arg)) {
226                                         // Boolean!
227                                         if ($arg) $argsString .= "true(bool)"; else $argsString .= "false(bool)";
228                                 } elseif (is_int($arg)) {
229                                         // Integer
230                                         $argsString .= $arg."(int)";
231                                 } elseif (is_float($arg)) {
232                                         // Floating point
233                                         $argsString .= $arg."(float)";
234                                 } elseif ($arg instanceof BaseFrameworkSystem) {
235                                         // Own object instance
236                                         $argsString .= $arg->__toString()."(Object)";
237                                 } elseif (is_object($arg)) {
238                                         // External object
239                                         $argsString .= "unknown object(!)";
240                                 } elseif (is_array($arg)) {
241                                         // Array
242                                         $argsString .= "Array(array)";
243                                 } elseif (is_string($arg)) {
244                                         // String
245                                         $argsString .= "\"".$arg."\"(string)";
246                                 } elseif (is_null($arg)) {
247                                         // Null
248                                         $argsString .= "(null)";
249                                 } else {
250                                         // Unknown type (please report!)
251                                         $argsString .= $arg."(unknown!)";
252                                 }
253
254                                 // Add comma
255                                 $argsString .= ", ";
256                         }
257
258                         // Remove last comma
259                         if (substr($argsString, -2, 1) === ",") $argsString = substr($argsString, 0, -2);
260                 } else {
261                         // Invalid arguments!
262                         $argsString = sprintf("!INVALID:%s!", $args);
263                 }
264
265                 $this->getDebugInstance()->output(sprintf("[%s::%s] Stub! Args: %s",
266                         $this->__toString(),
267                         $methodName,
268                         $argsString
269                 ));
270
271                 // Return nothing
272                 return null;
273         }
274
275         /**
276          * Private initializer for this class
277          *
278          * @return      void
279          */
280         private final function initInstance () {
281                 // Is this a system class?
282                 if (!in_array($this->__toString(), $this->systemClasses)) {
283                         // Add application helper to our class
284                         $this->systemclasses[] = $this->getConfigInstance()->readConfig('app_helper_class');
285
286                         // Set debug instance
287                         $this->setDebugInstance(DebugMiddleware::createDebugMiddleware($this->getConfigInstance()->readConfig('debug_class')));
288
289                         // Get output instance and set it
290                         $outputInstance = ObjectFactory::createObjectByConfiguredName('web_engine', array($this->getConfigInstance()->readConfig('web_content_type')));
291                         $this->setWebOutputInstance($outputInstance);
292
293                         // Set the compressor channel
294                         $this->setCompressorChannel(CompressorChannel::createCompressorChannel(sprintf("%s%s",
295                                 PATH,
296                                 $this->getConfigInstance()->readConfig('compressor_base_path')
297                         )));
298
299                         // Initialization done! :D
300                         Registry::isInitialized("OK");
301                 } elseif ($this->__toString() == "DebugMiddleware") {
302                         // Set configuration instance
303                         $this->setConfigInstance(FrameworkConfiguration::createFrameworkConfiguration());
304                 }
305         }
306
307         /**
308          * Setter for language instance
309          *
310          * @param       $configInstance         The configuration instance which shall
311          *                                                              be FrameworkConfiguration
312          * @return      void
313          */
314         public final function setConfigInstance (FrameworkConfiguration $configInstance) {
315                 Registry::getRegistry()->addInstance('config', $configInstance);
316         }
317
318         /**
319          * Getter for configuration instance
320          *
321          * @return      $cfhInstance - Configuration instance
322          */
323         protected final function getConfigInstance () {
324                 return Registry::getRegistry()->getInstance('config');
325         }
326
327         /**
328          * Setter for debug instance
329          *
330          * @param               $debugInstance  The instance for debug output class
331          * @return      void
332          */
333         public final function setDebugInstance (DebugMiddleware $debugInstance) {
334                 Registry::getRegistry()->addInstance('debug', $debugInstance);
335         }
336
337         /**
338          * Getter for debug instance
339          *
340          * @return      $debug - Instance to class DebugConsoleOutput or DebugWebOutput
341          */
342         public final function getDebugInstance () {
343                 return Registry::getRegistry()->getInstance('debug');
344         }
345
346         /**
347          * Setter for web output instance
348          *
349          * @param               $webInstance    The instance for web output class
350          * @return      void
351          */
352         public final function setWebOutputInstance (OutputStreamer $webInstance) {
353                 Registry::getRegistry()->addInstance('web_output', $webInstance);
354         }
355
356         /**
357          * Getter for web output instance
358          *
359          * @return      $webOutput - Instance to class WebOutput
360          */
361         public final function getWebOutputInstance () {
362                 return Registry::getRegistry()->getInstance('web_output');
363         }
364
365         /**
366          * Setter for database instance
367          *
368          * @param               $dbInstance     The instance for the database connection
369          *                                      (forced DatabaseConnection)
370          * @return      void
371          */
372         public final function setDatabaseInstance (DatabaseConnection $dbInstance) {
373                 Registry::getRegistry()->addInstance('dbInstance', $dbInstance);
374         }
375
376         /**
377          * Getter for database layer
378          *
379          * @return      $dbInstance     The database layer instance
380          */
381         public final function getDatabaseInstance () {
382                 if ((class_exists('Registry')) && (Registry::isInitialized() === true)) {
383                         return Registry::getRegistry()->getInstance('dbInstance');
384                 } else {
385                         return null;
386                 }
387         }
388
389         /**
390          * Setter for compressor channel
391          *
392          * @param               $compressorChannel      An instance of CompressorChannel
393          * @return      void
394          */
395         public final function setCompressorChannel (CompressorChannel $compressorChannel) {
396                 Registry::getRegistry()->addInstance('compressor', $compressorChannel);
397         }
398
399         /**
400          * Getter for compressor channel
401          *
402          * @return      $compressor     The compressor channel
403          */
404         public final function getCompressorChannel () {
405                 return Registry::getRegistry()->getInstance('compressor');
406         }
407
408         /**
409          * Protected getter for a manageable application helper class
410          *
411          * @return      $applicationInstance    An instance of a manageable application helper class
412          */
413         protected final function getApplicationInstance () {
414                 return self::$applicationInstance;
415         }
416
417         /**
418          * Setter for a manageable application helper class
419          *
420          * @param       $applicationInstance    An instance of a manageable application helper class
421          * @return      void
422          */
423         public final function setApplicationInstance (ManageableApplication $applicationInstance) {
424                 self::$applicationInstance = $applicationInstance;
425         }
426
427         /**
428          * Setter for request instance
429          *
430          * @param       $requestInstance        An instance of a Requestable class
431          * @return      void
432          */
433         public final function setRequestInstance (Requestable $requestInstance) {
434                 $this->requestInstance = $requestInstance;
435         }
436
437         /**
438          * Getter for request instance
439          *
440          * @return      $requestInstance        An instance of a Requestable class
441          */
442         public final function getRequestInstance () {
443                 return $this->requestInstance;
444         }
445
446         /**
447          * Setter for response instance
448          *
449          * @param       $responseInstance       An instance of a Responseable class
450          * @return      void
451          */
452         public final function setResponseInstance (Responseable $responseInstance) {
453                 $this->responseInstance = $responseInstance;
454         }
455
456         /**
457          * Getter for response instance
458          *
459          * @return      $responseInstance       An instance of a Responseable class
460          */
461         public final function getResponseInstance () {
462                 return $this->responseInstance;
463         }
464
465         /**
466          * Getter for $realClass
467          *
468          * @return      $realClass The name of the real class (not BaseFrameworkSystem)
469          */
470         public final function __toString () {
471                 return $this->realClass;
472         }
473
474         /**
475          * Setter for the real class name
476          *
477          * @param               $realClass      Class name (string)
478          * @return      void
479          */
480         public final function setRealClass ($realClass) {
481                 // Cast to string
482                 $realClass = (string) $realClass;
483
484                 // Set real class
485                 $this->realClass = $realClass;
486         }
487
488         /**
489          * Generate unique ID from a lot entropy
490          *
491          * @return      void
492          */
493         public final function generateUniqueId () {
494                 // Is the id set for this class?
495                 if (empty($this->uniqueID)) {
496
497                         // Correct missing class name
498                         $corrected = false;
499                         if ($this->__toString() == "") {
500                                 $this->setRealClass(__CLASS__);
501                                 $corrected = true;
502                         }
503
504                         // Cache datbase instance
505                         $db = $this->getDatabaseInstance();
506
507                         // Generate new id
508                         $tempID = false;
509                         while (true) {
510                                 // Generate a unique ID number
511                                 $tempID = $this->generateIdNumber();
512                                 $isUsed = false;
513
514                                 // Try to figure out if the ID number is not yet used
515                                 try {
516                                         // Is this a registry?
517                                         if ($this->__toString() == "Registry") {
518                                                 // Registry, then abort here
519                                                 break;
520                                         } elseif (is_object($db)) {
521                                                 $isUsed = $db->isUniqueIdUsed($tempID, true);
522                                         }
523                                 } catch (FrameworkException $e) {
524                                         // Catches all and ignores all ;-)
525                                 }
526
527                                 if (
528                                         (
529                                                 $tempID !== false
530                                         ) && (
531                                                 (
532                                                         $db === null
533                                                 ) || (
534                                                         (
535                                                                 is_object($db)
536                                                         ) && (
537                                                                 !$isUsed
538                                                         )
539                                                 )
540                                         )
541                                 ) {
542                                         // Abort the loop
543                                         break;
544                                 }
545                         } // END - while
546
547                         // Apply the new ID
548                         $this->setUniqueID($tempID);
549
550                         // Revert maybe corrected class name
551                         if ($corrected) {
552                                 $this->setRealClass("");
553                         }
554
555                         // Remove system classes if we are in a system class
556                         if ((isset($this->systemClasses)) && (in_array($this->__toString(), $this->systemClasses))) {
557                                 // This may save some RAM...
558                                 $this->removeSystemArray();
559                         }
560                 }
561         }
562
563         /**
564          * Generates a new ID number for classes based from the class' real name,
565          * the description and some random data
566          *
567          * @return      $tempID The new (temporary) ID number
568          */
569         private final function generateIdNumber () {
570                 return sprintf("%s@%s",
571                         $this->__toString(),
572                         md5(sprintf("%s:%s:%s:%s:%s:%s",
573                                 $this->__toString(),
574                                 $this->getObjectDescription(),
575                                 time(),
576                                 getenv('REMOTE_ADDR'),
577                                 getenv('SERVER_ADDR'),
578                                 mt_rand()
579                         ))
580                 );
581         }
582
583         /**
584          * Setter for unique ID
585          *
586          * @param               $uniqueID               The newly generated unique ID number
587          * @return      void
588          */
589         private final function setUniqueID ($uniqueID) {
590                 // Cast to string
591                 $uniqueID = (string) $uniqueID;
592
593                 // Set the ID number
594                 $this->uniqueID = $uniqueID;
595         }
596
597         /**
598          * Getter for unique ID
599          *
600          * @return      $uniqueID               The unique ID of this class
601          */
602         public final function getUniqueID () {
603                 return $this->uniqueID;
604         }
605
606         /**
607          * Resets or recreates the unique ID number
608          *
609          * @return      void
610          */
611         public final function resetUniqueID() {
612                 // Sweet and simple... ;-)
613                 $newUniqueID = $this->generateIdNumber();
614                 $this->setUniqueID($newUniqueID);
615         }
616
617         /**
618          * Getter for simulator description
619          *
620          * @return      $objectDescription      The description of this simulation part
621          */
622         public final function getObjectDescription () {
623                 if (isset($this->objectDescription)) {
624                         return $this->objectDescription;
625                 } else {
626                         return null;
627                 }
628         }
629
630         /**
631          * Setter for simulation part description
632          *
633          * @param               $objectDescription      The description as string for this simulation part
634          * @return      void
635          */
636         public final function setObjectDescription ($objectDescription) {
637                 $this->objectDescription = (String) $objectDescription;
638         }
639
640         /**
641          * Validate if given object is the same as current
642          *
643          * @param               $object An object instance for comparison with this class
644          * @return      boolean The result of comparing both's unique ID
645          */
646         public final function equals ($object) {
647                 return ($this->getUniqueID() == $object->getUniqueID());
648         }
649
650         /**
651          * Compare if both simulation part description and class name matches
652          * (shall be enougth)
653          *
654          * @param               $itemInstance   An object instance to an other class
655          * @return      boolean         The result of comparing class name simulation part description
656          */
657         public function itemMatches ($itemInstance) {
658                 return (
659                         (
660                                 $this->__toString()   == $itemInstance->__toString()
661                         ) && (
662                                 $this->getObjectDescription() == $itemInstance->getObjectDescription()
663                         )
664                 );
665         }
666
667         /**
668          * Compare class name of this and given class name
669          *
670          * @param               $class  The class name as string from the other class
671          * @return      boolean The result of comparing both class names
672          */
673         public final function isClass ($class) {
674                 return ($this->__toString() == $class);
675         }
676
677         /**
678          * Stub method (only real cabins shall override it)
679          *
680          * @return      boolean false = is no cabin, true = is a cabin
681          */
682         public function isCabin () {
683                 return false;
684         }
685
686         /**
687          * Stub method for tradeable objects
688          *
689          * @return      boolean false = is not tradeable by the Merchant class,
690          *                                      true  = is a tradeable object
691          */
692         public function isTradeable () {
693                 return false;
694         }
695
696         /**
697          * Formats computer generated price values into human-understandable formats
698          * with thousand and decimal seperators.
699          *
700          * @param       $value          The in computer format value for a price
701          * @param       $currency       The currency symbol (use HTML-valid characters!)
702          * @param       $decNum         Number of decimals after commata
703          * @return      $price          The for the current language formated price string
704          * @throws      MissingDecimalsThousandsSeperatorException      If decimals or
705          *                                                                                              thousands seperator
706          *                                                                                              is missing
707          */
708         public function formatCurrency ($value, $currency = "&euro;", $decNum = 2) {
709                 // Are all required attriutes set?
710                 if ((!isset($this->decimals)) || (!isset($this->thousands))) {
711                         // Throw an exception
712                         throw new MissingDecimalsThousandsSeperatorException($this, self::EXCEPTION_ATTRIBUTES_ARE_MISSING);
713                 }
714
715                 // Cast the number
716                 $value = (float) $value;
717
718                 // Reformat the US number
719                 $price = sprintf("%s %s",
720                         number_format($value, $decNum, $this->decimals, $this->thousands),
721                         $currency
722                 );
723
724                 // Return as string...
725                 return $price;
726         }
727
728         /**
729          * Removes number formating characters
730          *
731          * @return      void
732          */
733         public final function removeNumberFormaters () {
734                 unset($this->thousands);
735                 unset($this->decimals);
736         }
737
738         /**
739          * Private getter for language instance
740          *
741          * @return      $langInstance   An instance to the language sub-system
742          */
743         protected final function getLanguageInstance () {
744                 return self::$langInstance;
745         }
746
747         /**
748          * Setter for language instance
749          *
750          * @param       $langInstance   An instance to the language sub-system
751          * @return      void
752          * @see         LanguageSystem
753          */
754         public final function setLanguageInstance (ManageableLanguage $langInstance) {
755                 self::$langInstance = $langInstance;
756         }
757
758         /**
759          * Remove the $systemClasses array from memory
760          *
761          * @return      void
762          */
763         public final function removeSystemArray () {
764                 unset($this->systemClasses);
765         }
766
767         /**
768          * Create a file name and path name from the object's unique ID number.
769          * The left part of the ID shall always be a valid class name and the
770          * right part an ID number.
771          *
772          * @return      $pfn            The file name with a prepended path name
773          * @throws      NoArrayCreatedException If explode() fails to create an array
774          * @throws      InvalidArrayCountException      If the array contains less or
775          *                                                                      more than two elements
776          */
777         public final function getPathFileNameFromObject () {
778                 // Get the main object's unique ID. We use this as a path/filename combination
779                 $pathFile = $this->getUniqueID();
780
781                 // Split it up in path and file name
782                 $pathFile = explode("@", $pathFile);
783
784                 // Are there two elements? Index 0 is the path, 1 the file name + global extension
785                 if (!is_array($pathFile)) {
786                         // No array found
787                         throw new NoArrayCreatedException(array($this, "pathFile"), self::EXCEPTION_ARRAY_EXPECTED);
788                 } elseif (count($pathFile) != 2) {
789                         // Invalid ID returned!
790                         throw new InvalidArrayCountException(array($this, "pathFile", count($pathFile), 2), self::EXCEPTION_ARRAY_HAS_INVALID_COUNT);
791                 }
792
793                 // Auto-append missing trailing slash
794                 $pathFile[0] = $this->addMissingTrailingSlash($pathFile[0]);
795
796                 // Create the file name and return it
797                 $pfn = ($pathFile[0] . $pathFile[1]);
798                 return $pfn;
799         }
800
801         /**
802          * Appends a trailing slash to a string
803          *
804          * @param       $str            A string (maybe) without trailing slash
805          * @return      $str            A string with an auto-appended trailing slash
806          */
807         public final function addMissingTrailingSlash ($str) {
808                 // Is there a trailing slash?
809                 if (substr($str, -1, 1) != "/") $str .= "/";
810                 return $str;
811         }
812
813         /**
814          * Private getter for file IO instance
815          *
816          * @return      $fileIoInstance An instance to the file I/O sub-system
817          */
818         protected final function getFileIoInstance () {
819                 return $this->fileIoInstance;
820         }
821
822         /**
823          * Setter for file I/O instance
824          *
825          * @param       $fileIoInstance An instance to the file I/O sub-system
826          * @return      void
827          */
828         public final function setFileIoInstance (FileIoHandler $fileIoInstance) {
829                 $this->fileIoInstance = $fileIoInstance;
830         }
831
832         /**
833          * Prepare the template engine (TemplateEngine by default) for a given
834          * application helper instance (ApplicationHelper by default).
835          *
836          * @param               $appInstance                    An application helper instance or
837          *                                                                              null if we shall use the default
838          * @return              $tplEngine                              The template engine instance
839          * @throws              NullPointerException    If the template engine could not
840          *                                                                              be initialized
841          * @throws              UnsupportedTemplateEngineException      If $tplEngine is an
842          *                                                                              unsupported template engine
843          * @throws              MissingLanguageHandlerException If the language sub-system
844          *                                                                              is not yet initialized
845          * @throws              NullPointerException    If the discovered application
846          *                                                                              instance is still null
847          */
848         protected function prepareTemplateEngine (BaseFrameworkSystem $appInstance=null) {
849                 // Is the application instance set?
850                 if (is_null($appInstance)) {
851                         // Get the current instance
852                         $appInstance = $this->getApplicationInstance();
853
854                         // Still null?
855                         if (is_null($appInstance)) {
856                                 // Thrown an exception
857                                 throw new NullPointerException($this, self::EXCEPTION_IS_NULL_POINTER);
858                         }
859                 }
860
861                 // Generate FQFN for all application templates
862                 $fqfn = sprintf("%s%s/%s/%s",
863                         PATH,
864                         $this->getConfigInstance()->readConfig('application_path'),
865                         strtolower($appInstance->getAppShortName()),
866                         $this->getConfigInstance()->readConfig('tpl_base_path')
867                 );
868
869                 // Are both instances set?
870                 if ($appInstance->getLanguageInstance() === null) {
871                         // Invalid language instance
872                         throw new MissingLanguageHandlerException($appInstance, self::EXCEPTION_MISSING_LANGUAGE_HANDLER);
873                 } elseif ($appInstance->getFileIoInstance() === null) {
874                         // Invalid language instance
875                         throw new MissingFileIoHandlerException($appInstance, self::EXCEPTION_MISSING_FILE_IO_HANDLER);
876                 }
877
878                 // Initialize the template engine
879                 $tplEngine = ObjectFactory::createObjectByConfiguredName('template_class', array($fqfn, $appInstance->getLanguageInstance(), $appInstance->getFileIoInstance()));
880
881                 // Return the prepared instance
882                 return $tplEngine;
883         }
884
885         /**
886          * Debugs this instance by putting out it's full content
887          *
888          * @return      void
889          */
890         public final function debugInstance () {
891                 // Generate the output
892                 $content = sprintf("<pre>%s</pre>",
893                         trim(print_r($this, true))
894                 );
895
896                 // Output it
897                 ApplicationEntryPoint::app_die(sprintf("<strong>%s debug output:</strong>%s", $this->__toString(), $content));
898         }
899
900         /**
901          * Output a partial stub message for the caller method
902          *
903          * @param       $message        An optional message to display
904          * @return      void
905          */
906         protected function partialStub ($message = "") {
907                 // Get the backtrace
908                 $backtrace = debug_backtrace();
909
910                 // Generate the class::method string
911                 $methodName = "UnknownClass::unknownMethod";
912                 if ((isset($backtrace[1]['class'])) && (isset($backtrace[1]['function']))) {
913                         $methodName = $backtrace[1]['class']."::".$backtrace[1]['function'];
914                 }
915
916                 // Construct the full message
917                 $stubMessage = sprintf("[%s:] Partial stub!",
918                         $methodName
919                 );
920
921                 // Is the extra message given?
922                 if (!empty($message)) {
923                         // Then add it as well
924                         $stubMessage .= sprintf(" Message: <span id=\"stub_message\">%s</span>", $message);
925                 }
926
927                 // Debug instance is there?
928                 if (!is_null($this->getDebugInstance())) {
929                         // Output stub message
930                         $this->getDebugInstance()->output($stubMessage);
931                 } else {
932                         // Trigger an error
933                         trigger_error($stubMessage."<br />\n");
934                 }
935         }
936
937         /**
938          * Converts e.g. a command from URL to a valid class by keeping out bad characters
939          *
940          * @param       $str            The string, what ever it is needs to be converted
941          * @return      $className      Generated class name
942          */
943         public function convertToClassName ($str) {
944                 // Init class name
945                 $className = "";
946
947                 // Convert all dashes in underscores
948                 $str = str_replace("-", "_", $str);
949
950                 // Now use that underscores to get classname parts for hungarian style
951                 foreach (explode("_", $str) as $strPart) {
952                         // Make the class name part lower case and first upper case
953                         $className .= ucfirst(strtolower($strPart));
954                 } // END - foreach
955
956                 // Return class name
957                 return $className;
958         }
959
960         /**
961          * Outputs a debug backtrace and stops further script execution
962          *
963          * @return      void
964          */
965         public function debugBacktrace () {
966                 // Sorry, there is no other way getting this nice backtrace
967                 print "<pre>\n";
968                 debug_print_backtrace();
969                 print "</pre>";
970                 exit;
971         }
972
973         /**
974          * Setter for search instance
975          *
976          * @param       $searchInstance         Searchable criteria instance
977          * @return      void
978          */
979         public final function setSearchInstance (LocalSearchCriteria $searchInstance) {
980                 $this->searchInstance = $searchInstance;
981         }
982
983         /**
984          * Getter for search instance
985          *
986          * @return      $searchInstance         Searchable criteria instance
987          */
988         public final function getSearchInstance () {
989                 return $this->searchInstance;
990         }
991 }
992
993 // [EOF]
994 ?>