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