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