<?php
/**
 * YANA library
 *
 * @package yana
 * @licence http://creativecommons.org/licenses/by-nc-sa/2.5/
 */

/**
 * «Singleton» Yana
 *
 * This is a primary controller and application loader for the YANA-Framework.
 *
 * @access      public
 * @package     yana
 * @subpackage  core
 */
class Yana extends Singleton
{
    /**#@+
     * @ignore
     * @access  private
     */

    /** @var array */         var $config   = array();
    /** @var int   */         var $mode     = 0;
    /** @var View  */         var $view     = null;
    /** @var array */         var $log      = array();
    /** @var array */         var $request  = array();

    /**#@-*/
    /**#@+
     * readonly
     * @access  public
     */

    /** @var PluginManager */ var $plugins  = null;
    /** @var Language      */ var $language = null;
    /** @var Skin          */ var $skin     = null;
    /** @var Registry      */ var $registry = null;

    /**#@-*/

    /**
    * «Singleton» Constructor
    *
    * @uses    new yana("config/system.config", $_REQUEST)
    * @param   string  $filename  path to system.config
    * @param   array   $ARGS      associative array of request vars
    * @access  public
    */
    function Yana($filename, $ARGS)
    {
        /**
         * 0. Check
         *
         * before doing anything else, let's check constraints and user-input first
         */

        {
            $this->checkSingletonConstraint();
            assert('is_string($filename) && is_file($filename) && is_readable($filename);');
            assert('is_array($ARGS);');
            /* lower-case all entries */
            $ARGS = changeCaseArray($ARGS,CASE_LOWER);
            assert('is_array($ARGS);');
            foreach ($ARGS as $key => $item)
            {
                if (!is_array($item)) {
                    $ARGS[$key] = untaintInput($item, "string", 50000, YANA_ESCAPE_TOKEN);
                } else {
                    assert('is_array($item);');
                    foreach($item as $key2 => $item2)
                    {
                        $ARGS[$key][$key2] = untaintInput($item2, "string", 50000, YANA_ESCAPE_TOKEN);
                    }
                }
            }
        }/* END 0. */

        /**
         * 1. Startup-Settings
         *
         * system config file contains default- and startup-settings
         */

        /* 1.1 Get System Config file : */
        {
            $this->config = getConfigFile($filename);
        }/* END 1.1 */

        /* 1.2 get action var */
        {
            if (!empty($ARGS['action'])) {
                if (!preg_match('/^[\w][\w\d\_]*$/si', $ARGS['action'])) {
                    $YANA->message('alert','ungueltige_eingabe');
                } else {
                    $ARGS['action'] = strtolower($ARGS['action']);
                }
            } else {
                assert('!empty($this->config["DEFAULT"]["HOMEPAGE"]);');
                $ARGS['action'] = strtolower($this->config['DEFAULT']['HOMEPAGE']);
            }
        }/* END 1.2 */

        /* 1.3 buffer request vars */
        {
            $this->request = $ARGS;
        }/* END 1.3 */

        /**
         * 2. Create Repositories
         *
         * pluginManager holds repositories for interfaces and implementations of plugins
         */

        {
            $this->plugins =& new pluginManager($this->config['PLUGINDIR'],$this->config['PLUGINFILE']);
        } /* END 2. */

        /**
         * 3. Build Registry
         *
         * registry offers coupling of components through common memory
         */

        /* 3.1 get configuration mode */
        {
            $this->mode = $this->plugins->getVar("", "INTERFACE.".$ARGS['action'].".MODE");
            if (is_null($this->mode)) {
                $this->mode = $this->config['DEFAULT']['EVENT']['MODE'];
            }
            settype($this->mode, "integer");
        } /* END 3.1 */

         /* 3.2 build configuration */
        {
            $REF = array();
            $REF = mergeArrays($this->config,$ARGS);
            assert('is_array($REF);');
            if (count($REF) == 0) {
                $REF = array ("__PHP_PWD_DBASE__" => "74e12c1b837c67e7fa4f6a2eacd6076f");
            }
    
            $this->registry =& new registry($this->config['CONFIGDRIVE'], $REF, "", $this->mode);
            $this->registry->read();
        } /* END 3.2 */

        /* 3.3 Save Referer */
        {
            if (!empty($_SERVER['HTTP_REFERER'])) {
                $this->registry->setVar("REFERER", preg_replace("/(.*\/).*(\?.*)?/", "\\1", $_SERVER['HTTP_REFERER']));
            }
        } /* END 3.3 */

        /* 3.4) Save Website Location */
        {
            $this->registry->setVar("SETTINGS.WEBSITE_URL", 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']);
        } /* END 3.4 */

        /**
         * 4. prepare Template
         *
         * view is an auxiliary class that provides access to output-specific functions
         */

        {
            $this->view =& new view();
            $this->setVar("ACTION", $ARGS['action']);
        } /* END 5. */

        /**
         * 5. create Language Library
         *
         * creates the translation-repository
         */

        {
            $this->language =& new language($this->config['LANGUAGEDIR'].$this->getVar("LANGUAGE_INFO.DIRECTORY"), $this->registry->get("LANG"), $this->config['LANGUAGEDIR'] . $this->config['DEFAULT']['LANGUAGE']['DIRECTORY']);
        } /* END 6. */

        /**
         * 6. create Skin Library
         *
         * creates the skin-repository
         */

        {
            if (YANA_CACHE_ACTIVE === true) {
                $cache_file = $this->registry->get('SKINCACHE');
                if ($cache_file->exists()) {
                    $this->skin = unserialize(implode('',file($cache_file->getFilename())));
                } else {
                    $defaultSkinDir =& new dirStream($this->config['SKINDIR'].$this->config['DEFAULT']['SKIN']['DIRECTORY']);
                    $defaultSkinDir->filter = ".config";
                    $defaultSkinDir->read();
                    $this->skin =& new skin($this->config['SKINDIR'].$this->getVar("SKIN_INFO.DIRECTORY"), $this->registry->get("SKIN"), $this->registry->get('SKINDIR'), $defaultSkinDir);
                    $cache_file->create();
                    $cache_file->insert(serialize($this->skin));
                    $cache_file->write();
                }
            } else {
                $defaultSkinDir =& new dirStream($this->config['SKINDIR'].$this->config['DEFAULT']['SKIN']['DIRECTORY']);
                $defaultSkinDir->filter = ".config";
                $defaultSkinDir->read();
                $this->skin =& new skin($this->config['SKINDIR'].$this->getVar("SKIN_INFO.DIRECTORY"), $this->registry->get("SKIN"), $this->registry->get('SKINDIR'), $defaultSkinDir);
            }
        } /* END 6. */

        /**
         * 7. create uper-cased aliases of required request vars
         *
         * these are used in templates
         */

        {
            if (!empty($ARGS['id'])) {
                $this->setVar('ID', $ARGS['id']);
            }
            if (!empty($ARGS['page'])) {
                $this->setVar('PAGE', $ARGS['page']);
            }
            if (!empty($ARGS['target'])) {
                $this->setVar('TARGET', $ARGS['target']);
            }
            $this->setVar('REMOTE_ADDR',$_SERVER['REMOTE_ADDR']);
        } /* END 7. */

        /* Ready to go ... */

    }

    /**
    * resolves event and calls plugin(s), with the given arguments
    *
    * @uses $YANA->handle('test', $_REQUEST)
    * @param string $event (optional) script action parameter
    * @param array $ARGS (optional) array of passed arguments
    * @access public
    * @return boolean
    */
    function handle($event = "", $ARGS = NULL)
    {
        assert('is_string($event);');
        if (empty($event)) {
            $event = $this->request['action'];
        }
        if (is_null($ARGS)) {
            $ARGS  = $this->request;
        }
        assert('is_array($ARGS);');
        if ($event=="test") {
            $this->diagnostics(@$ARGS['target']==='detailed');
            return false;
        } else {
            $test = $this->plugins->handle($event,$ARGS);
            assert('is_bool($test);');
            if ($test === true) {
                /* Create timestamp to provide information for read-stability isolation level */
                $_SESSION['transaction_isolation_created'] = time();
                return true;
            } else {
                return false;
            }
        }
    }

    /**
     * retrieves var from registry (memory shared by all plugins)
     *
     * @uses $YANA->get('CONTAINER1.CONTAINER2.DATA')
     * @param string $key adress of data in memory (case insensitive)
     * @access public
     * @return mixed
     */
    function getVar($key)
    {
        assert('is_scalar($key); /* Wrong type for argument 1. Scalar value expected. */');
        settype($key, 'string');
        return $this->registry->getVar($key);
    }

    /**
     * sets var on registry (memory shared by all plugins)
     *
     * @uses $YANA->setVar('CONTAINER1.CONTAINER2.DATA', $value)
     * @param string $key adress of data in memory (case insensitive)
     * @param mixed $value new value (may be scalar value or array)
     * @access public
     * @return boolean
     */
    function setVar($key, $value)
    {
        assert('is_scalar($key); /* Wrong type for argument 1. Scalar value expected. */');
        settype($key, 'string');
        return $this->registry->setVar($key, $value);
    }

    /**
     * sets the type of a var on registry (memory shared by all plugins)
     *
     * @uses $YANA->setType('CONTAINER1.CONTAINER2.DATA', 'string')
     * @param string $key adress of data in memory (case insensitive)
     * @param string $type new type of variable
     * @access public
     * @return boolean
     */
    function setType($key, $type)
    {
        assert('is_scalar($key); /* Wrong type for argument 1. Scalar value expected. */');
        assert('is_string($type); /* Wrong type for argument 2. String expected. */');
        settype($key, 'string');
        settype($type, 'string');
        return $this->registry->setType($key, $type);
    }

    /**
     * removes var from registry (memory shared by all plugins)
     *
     * @uses $YANA->unsetVar('CONTAINER1.CONTAINER2.DATA')
     * @param string $key adress of data in memory (case insensitive)
     * @access public
     * @return boolean
     */
    function unsetVar($key) 
    {
        assert('is_scalar($key); /* Wrong type for argument 1. Scalar value expected. */');
        settype($key, 'string');
        return $this->registry->unsetVar($key);
    }

    /**
     * merges the value at adresse $key with the provided array data
     *
     * @uses $YANA->merge('CONTAINER1.CONTAINER2.DATA', $array)
     * @param string $key adress of data in memory (case insensitive)
     * @param array $array associative array to merge
     * @access public
     * @return boolean
     */
    function merge($key, $array)
    {
        assert('is_scalar($key); /* Wrong type for argument 1. Scalar value expected. */');
        assert('is_array($array); /* Wrong argument type for argument 2. Array expected */');
        settype($key, 'string');
        return $this->registry->merge($key, $array);
    }

    /**
     * adds an entry to the log-queue (will be printed to screen or written to log-file, depending on base-class)
     *
     * @uses $YANA->report($report)
     * @param yana_log $log object containing the log entry
     * @access public
     * @return void
     */
    function report($log)
    {
        if (is_subclass_of($log, 'yana_log')) {
            array_unshift($this->log, $log);
        } else {
            trigger_error("Wrong argument type for argument 1 in function report(). Instance of 'yana_log' or a derived subclass expected.", E_USER_WARNING);
        }
    }

    /**
     * outputs an text message (while terminating the current script)
     *
     * @uses $YANA->message('ERROR', '404')
     *
     * @access  public
     * @param   string  $level    type of message ('OK'|'ALERT'|'ERROR')
     * @param   string  $errcode  code of corresponding message in message.config
     * @param   string  $event    upcoming event to route to
     */
    function message($level, $errcode, $event = "")
    {
        assert('is_string($level); /* Wrong type for argument 1. String expected. */');
        assert('is_scalar($errcode); /* Wrong type for argument 2. Scalar value expected. */');
        assert('is_string($event); /* Wrong type for argument 3. String expected. */');
        settype($level,   "string");
        settype($errcode, "string");
        settype($event,   "string");
        $errcode = strtoupper($errcode);
        $level   = strtolower($level);
             
        $this->_write_log();
        $this->view->message($level, $errcode, $event);
    }

    /**
     * provides gui from current data
     *
     * @uses $YANA->writeView()
     * @access public
     * @return void
     */
    function writeView()
    {
        /* 0. initialize vars */
        $event        = $this->getVar("ACTION");
        $result       = $this->getVar('SETTINGS.LAST_RESULT');
        $baseDoc      = $this->plugins->getVar("", "INTERFACE.".$event.".TEMPLATE");
        $includeDoc   = $this->plugins->getVar("", "INTERFACE.".$event.".INSERT");

        if (is_null($baseDoc)) {
           $baseDoc = (!empty($this->config['DEFAULT']['EVENT']['TEMPLATE'])) ? $this->config['DEFAULT']['EVENT']['TEMPLATE'] : "";
        }
        if (is_null($includeDoc)) {
           $includeDoc = (!empty($this->config['DEFAULT']['EVENT']['INSERT'])) ? $this->config['DEFAULT']['EVENT']['INSERT'] : "";
        }

        if ($baseDoc == 'NULL') {

            $this->view->unsetView();

        } else if ($baseDoc == 'MESSAGE' || ($result === FALSE && !empty($this->log))) {

            /* get vars */
            $route  = $this->getVar('SETTINGS.EVENT_ROUTING');
            $stdout = array();
            if (!empty($route['TEMPLATE'])) {
                $message_type = $route['TEMPLATE'];
            } else {
                $message_type = '';
            }

            /* b. check vars */
            if (empty($this->log) && empty($route['TEXT'])) {
                if ($result) {
                    $this->report(new message('200'));
                } else {
                    $this->report(new error('500'));
                }
            }
            if (!is_array($route)) {
                $route = array();
            }

            /* need those strings - load 'em */
            $this->language->read('message');

            /* 1. event logging */
            foreach ($this->log as $log) 
            {
                if (is_subclass_of($log, 'yana_log')) {
                    /* checks whether type of report is known and pushes message into output-queue */
                    switch (strtolower(get_class($log))) {
                        case 'message':
                            array_push($stdout, $log->getMessage());
                            if ($result) {
                                $message_type = 'message';
                            }
                        break;
                        case 'warning':
                            array_push($stdout, $log->getMessage());
                            $message_type = 'warning';
                        break;
                        case 'alert':
                            array_push($stdout, $log->getMessage());
                            $message_type = 'alert';
                        break;
                        case 'error':
                            array_push($stdout, $log->getMessage());
                            if (!$result) {
                                $message_type = 'error';
                            }
                        break;
                        default:
                            /* ignore unknown logs */
                        break;
                    }
                }
            }
            if (empty($message_type))  {
                $message_type  = ($result) ? 'ok' : 'error';
            }
            if (empty($route['TEXT'])) {
                $route['TEXT'] = ($result) ? '200' : '500';
            }
            $this->setVar('STDOUT', $stdout);
                          
            if (empty($route['GOTO'])) {
                $this->message($message_type, $route['TEXT']);
            } else {
                $this->message($message_type, $route['TEXT'], $route['GOTO']);
            }

        } else {

            if ($baseDoc) {
                $this->view->selectBaseView($baseDoc);
            }
            if ($includeDoc) {
                $this->view->selectView($includeDoc);
            }
            $this->view->buildPage();
            $this->view->setOptions("*");
            $this->view->show();
            $this->_write_log();

        }

    }

    /**
     * returns current type of session (0=using profile|1=using default data)
     *
     * @uses $YANA->getMode()
     *
     * @access  public
     * @return  integer
     */
    function getMode()
    {
        return $this->mode;
    }

    /**
     * returns the default value for a given var (if any) else returns null (not false!)
     *
     * @uses $YANA->getDefault('CONTAINER1.CONTAINER2.DATA')
     *
     * @access  public
     * @param   string  $key  adress of data in memory (case insensitive)
     * @return  mixed
     */
    function getDefault($key)
    {
        assert('is_string($key) || !empty($key);');
        settype($key, "string");
        $key = strtoupper("DEFAULT.${key}");
        return Hashtable::get($this->config, $key);
    }

    /**
     * diagnostics
     *
     * @access  private
     * @param   bool     $target
     * @ignore
     */
    function diagnostics($target)
    {
        /*
         * IMPORTANT NOTE:
         * DON'T TOUCH IT, since it might be used as input in other apps for aditional error-analysis.
         * This is highly usefull, since not all errors that COULD be extracted from the information
         * provided in this report, currently ARE reported as errors by this function.
         * This comes 'cuz it simply can't "know" everything. ;-)
         *
         * E.g. if there is a known problem with a certain version of a plugin in a wild combination
         * with a number of others, this won't check. But an additional analysis with another app that
         * "knows" this behaviour, might find this error. No matter what version of the framework you
         * are currently running. BUT ONLY IF the output of this function is reliable and remains
         * the same from version to version.
         * If the output is changed in any way, you never know which other apps you might break!
         *
         * TODO:
         * might want to create an alternative xml-output for this function to better assist error analysis
         */

        assert('is_bool($target);');
        
        echo "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n\n<html>\n\n<head>\n\t".'<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">'."\n\t".'<meta name="robots" content="NOINDEX, NOFOLLOW">'."\n\t".'<title>Self-Test Logfile</title>'."\n
        \t".'<style type="text/css">.kommentar { background: #ffffff; color: #808080; } BODY { background: #ffffff; color: #000000; font-family: "Times New Roman", serif; } h1 { font-family: sans-serif; background: #dde5fa; color: #000000; } h2 { font-family: "Arial", sans-serif; background: #eeeeee; color: #000000; }</style>'."\n</head>\n\n
        <body>
    
        <h1>Self-Test Logfile</h1>
    
        <p class=\"kommentar\" align=\"justify\"><b>Anleitung:</b> Dieses Skript führt eine Reihe von Tests zur Selbstdiagnose durch, um festzustellen,
                           ob Ihr Programm korrekt installiert wurde. Sie können diese Log-Datei selbst auf Fehlermeldungen untersuchen - oder aber,
                           falls das Programm dennoch nicht funktioniert, können Sie mir auch eine E-Mail senden, um Hilfe bei der Lösung
                           Ihres Problems zu erhalten. Wenn Sie Fragen via Mail stellen, hängen Sie bitte dieses Diagnoseprotokoll an Ihre Mail.
                           Viele typische Fehler lassen sich bereits aus diesem Protokoll erkennen und Sie erhalten schneller eine Antwort.</p>
        <p class=\"kommentar\">&bull; Falls ein Test fehlschlägt, werden <span style=\"color: #ff0000;\">Fehlermeldungen</span> rot markiert.<br>
                           &bull; Ist ein Test erfolgreich, werden <span style=\"color: #00a000;\">Bestätigungsmeldungen</span> grün markiert.<br>
                           &bull; Alle <span style=\"color: #000000;\">normalen Status-Informationen</span> werden schwarz dargestellt.</p>
        <p class=\"kommentar\">Sollten Sie rote Zeilen finden: prüfen Sie bitte Ihre Konfiguration auf die beschriebenen Fehler.<br>
                           Bitte beachten Sie: dieses Programm erkennt zwar einige der <i>häufigsten Fehler</i>,
                           aber es kann nicht alle möglichen Fehlerquellen entdecken.</p>
        <hr>
        <p class=\"kommentar\" align=\"justify\"><b>Instructions:</b> This self-diagnosis script performs a number of tests to tell, if your program
                           has been installed correctly. You may check this log-file yourself for error-messages - or, if it still does not work,
                           email me to get help fixing your problem. By doing so, please include a copy of this diagnosis protocol with your mail.
                           Many typical problems may be recognized by reviewing this protocol and you will possibly get an answer for your problem a little faster.</p>
        <p class=\"kommentar\">&bull; If a test fails, <span style=\"color: #ff0000;\">failure-messages</span> are marked red.<br>
                           &bull; If a test succeeds, <span style=\"color: #00a000;\">success-messages</span> are marked green.<br>
                           &bull; All <span style=\"color: #000000;\">normal status-information</span> is printed black.</p>
        <p class=\"kommentar\">If you find any red lines: check your configuration for these errors.<br>
                           Please note: this program detects some of the <i>most common errors</i>, but it does not find all possible problems.</p>
        <hr>
        <p><b>Program is performing self-test now...</b><br>
        &nbsp;&nbsp;&nbsp;&nbsp;- current Script-Path is: ".__FILE__."<br>
        &nbsp;&nbsp;&nbsp;&nbsp;- installed version of PHP is: ".PHP_VERSION."</p>
    
        <h1>\tTESTING INSTALLATION:</h1>\n";
    
        @include_once("DB.php");
        if (!class_exists("DB")) {
            echo "<span style=\"color: #ff0000;\"><b>Error:</b> PHP PEAR-DB module not found. Database plugins require PEAR-DB and will not run unless you install it.</span><br>\n";
        } else {
            echo "<span style=\"color: #00a000;\"><b>okay:</b> PHP PEAR-DB found (required to run database plugins)</span><br>\n";
        }
    
        echo "<h2>\tTESTING CONFIGURATION DIRECTORY:</h2>\n";
    
        $drive = $this->registry;
        if (!$drive->exists()) {
            die("<p><span style=\"color: #ff0000;\"><b>Critical error:</b> Configuration file ".$drive->filename." cannot be found.</span></p>\n<hr><p>Test aborted due to a critical error.</p>");
        } else {
            echo "<p><span style=\"color: #00a000;\"><b>No problems found.</b></span></p>\n";
        }
    
        $drive->read();
        $text = str_replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;", nl2br(htmlentities($drive->toString())));
        if ($target) {
            echo "<h2>\tLIST CONFIGURATION FILES:</h2>\n";
            echo $text; }
        $test = $drive->check();
        if (!$test) {
            echo "<p><span style=\"color: #00a000;\"><b>All directories successfully installed.</b></span></p>\n";
        } else {
            echo "<p><span style=\"color: #ff0000;\"><b>Your configuration contains the following errors:</b></span><br>\n";
            echo $test."</p>";
        }
        if ($target) {
            echo "<h2>\tSYSTEM-INTEGRITY CHECK:</h2>\n<pre>";
            $root     = dirlist(".", '.php');
            for ($i=0;$i<count($root);$i++)
            {
                echo "SYSTEM[./".$root[$i]."]";
                for ($j=0;$j< 40 - strlen($root[$i]);$j++)
                {
                    echo " ";
                }
                echo "= ".md5(file_get_contents($root[$i]))."#".crc32(file_get_contents($root[$i]))."\n";
            }
            $root     = dirlist("./includes/", '.php');
            for ($i=0;$i<count($root);$i++)
            {
                echo "SYSTEM[./includes/".$root[$i]."]";
                for ($j=0;$j< 40 - 9 - strlen($root[$i]);$j++)
                {
                    echo " ";
                }
                echo "= ".md5(file_get_contents("includes/".$root[$i]))."#".crc32(file_get_contents("includes/".$root[$i]))."\n";
            }
            echo "</pre>";
        }
    
        if ($target) {
            echo "<h2>\tAUTOMOUNTING ALL FILES:</h2>\n";
    
            foreach ($this->registry->drive as $key => $element)
            {
                if ($element->mount() && $element->mountpoint->exists()) {
                    if (is_readable($element->mountpoint->getFilename())) {
                        echo "<span style=\"color: #00a000;\"><b>okay</b></span> <span class=\"kommentar\">&quot;".$element->mountpoint->getFilename()."&quot; is available</span><br>\n";
                    } else {
                        echo "<span style=\"color: #ff0000;\"><b>Error</b></span> <span class=\"kommentar\">&quot;".$element->mountpoint->getFilename()."&quot; is not readable</span><br>\n";
                    }
                } else {
                    echo "<span style=\"color: #0000a0;\"><b>Notice:</b></span> <span class=\"kommentar\">&quot;".$element->mountpoint->getFilename()."&quot; is not available.</span><br>\n";
                }
            }
        }
    
        echo "<h2>\tTESTING PLUGIN CONFIGURATION:</h2>\n";
        $this->plugins->mountAll();
    
        foreach ($this->plugins->drive as $id=>$drive)
        {
            if (!$drive->exists()) {
                echo "<p><span style=\"color: #ff0000;\"><b>Critical error:</b> Configuration file ".$drive->filename." cannot be found.</span></p>\n<hr><p>Test aborted due to a critical error.</p>";
            } else {
                echo "<div style=\"background-color:#FFFF00\">&bull; Testing Plugin &quot;$id&quot;:</div>\n";
            }
            echo "<blockquote>\n";
    
            $drive->read();
            $text = str_replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;", nl2br(htmlentities($drive->toString())));
            if ($target) {
                echo "<h2>\tLIST CONFIGURATION FILES:</h2>\n";
                echo $text; }
            $test = $drive->check();
            if (!$test) {
                echo "<p><span style=\"color: #00a000;\"><b>All directories successfully installed.</b></span></p>\n";
            } else {
                echo "<p><span style=\"color: #ff0000;\"><b>Your configuration contains the following errors:</b></span><br>\n";
                echo $test."</p>";
            }
    
            echo "</blockquote>\n";
        }
    
        echo "<h1>\tTESTING BACKUP-CONFIGURATION:</h1>\n";
    
        echo "<h2>\tCHECKING PROFILE FOR ERRORS:</h2>\n";
        if (count($this->registry->drive['config']->mountpoint->get("PROFILE"))==0) {
            echo "<p><span style=\"color: #ff0000;\"><b>Error:</b></span> Configuration is not available.</p>\n";
        } else {
            if ($target) {
                echo "<b>Performing deep-scan on file &quot;".$this->registry->files['config']->getFilename()."&quot;:</b><br>\n";
                foreach ($this->registry->drive['config']->mountpoint->get("PROFILE") as $key => $element) 
                {
                    echo "$key = ".gettype($element)."<br>\n";
                    if (is_array($element)) {
                        echo "<BLOCKQUOTE>\n";
                        foreach ($element as $a => $b) 
                        {
                            echo "$a = ".gettype($b)."<br>\n";
                        }
                        echo "</BLOCKQUOTE>\n";
                    }
                }
            }
            echo "<p><span style=\"color: #00a000;\"><b>No problems found.</b></span></p>
                        <div class=\"kommentar\">=&#9658; Profile settings for file &quot;".$this->registry->files['config']->getFilename()."&quot; are available.</div>\n";
        }
        echo "<h2>\tCHECKING SKIN- AND LANGUAGE-SETTINGS:</h2>\n";
        $test = $this->skin->check();
        if (!empty($test)) {
            echo $test;
            echo "<p><span style=\"color: #ff0000;\"><b>Warning: some errors found. This skin might either be corrupt or it was not installed correctly.</span></p>\n";
        } else {
            echo "<p><span style=\"color: #00a000;\"><b>No problems found.</b></span></p>
                        <div class=\"kommentar\">=&#9658; Skin file &quot;".$this->registry->files['skin']->getFilename()."&quot; seems to be installed correctly.</div>\n";
        }
        if (count($this->registry->drive['skin']->mountpoint->get("*"))==0) {
            echo "<p><span style=\"color: #ff0000;\"><b>Error:</b></span> No skin file available.</p>\n";
        }
        if (count($this->registry->drive['language']->mountpoint->get("*"))==0) {
            echo "<p><span style=\"color: #ff0000;\"><b>Error:</b></span> No language file available. Please check if this filename is correct: &quot;".$this->registry->files['language']->getFilename()."&quot;</p>\n";
        }
        if ($target) {
            echo "<b>Performing deep-scan on language-files in package &quot;".$this->registry->files['language']->getFilename()."&quot;:</b><br>\n";
            $test = $this->language->get();
            foreach ($test as $a => $b) 
            {
                echo "$a = ".gettype($b)."<br>\n";
                if (is_array($b)) {
                    echo "<blockquote>\n";
                    foreach ($b as $c => $d) 
                    {
                        echo "$c = ".gettype($d)."<br>\n";
                    }
                    echo "</blockquote>\n";
                }
            }
        }
        echo "<h2>\tCHECKING PLUGIN-TEMPLATES:</h2>\n";
        $test = $this->plugins->check();
        if (!empty($test)) {
            echo $test;
            echo "<p><span style=\"color: #ff0000;\"><b>Warning: some errors found. Some installed plugins might either be corrupt or were not installed correctly.</span></p>\n";
        } else {
            echo "<p><span style=\"color: #00a000;\"><b>No problems found.</b></span></p>
                        <div class=\"kommentar\">=&#9658; All plugin templates seem to be installed correctly.</div>\n";
        }
        echo "<h2>\tLIST ALL SMILIES:</h2>\n";
        DisplayUtility::loadSmilies();
        $smilies = $this->getVar('SMILIES');
        if (count($smilies)==0) {
            echo "<p><span style=\"color: #ff0000;\"><b>Warning:</b></span> No Smilies found. Please check if the given directory is correct: &quot;".$this->registry->files['SMILE']->getFilename()."&quot;</p>\n";
        } else {
            echo "<b>&bull; ".count($smilies)." Smilies found in directory &quot;".$this->registry->files['SMILE']->getFilename()."&quot;:</b><br>\n";
            for ($i=0;$i<count($smilies) && $target;$i++) 
            {
                echo $smilies[$i].", ";
                if (($i+1)%5==0) { 
                    echo "<br>\n";
                }
            }
            echo "<p><span style=\"color: #00a000;\"><b>No problems found.</b></span></p>
                        <div class=\"kommentar\">=&#9658; Directory setting &quot;".$this->registry->files['SMILE']->getFilename()."&quot; seems to be correct.</div>\n";
        }

        die("<hr><p>\tSelf-Test ended at: ".date("d.m.Y H:i:s",time())."</p>\n</body>\n\n</html>");
    }
    
    /**
     * «factory» connect()
     *
     * returns a ready-to-use database connection
     *
     * @access  public
     * @param   string  $source  name of the database schema that describes the names and structure of tables within the database
     * @return  mixed
     */
    function &connect($source)
    {
        assert('is_string($source);');
        settype($source, "string");
        if (YANA_DATABASE_ACTIVE) {
          $connection =& new bufferedDbStream($source);
        } else {
          $connection =& new filedb($source);
        }
        $connection->read();
        return $connection;
    }

    /**
     * flushes events to log
     *
     * @access  private
     * @ignore
     */
    function _write_log()
    {
        /* 0. initialize vars */
        $event_logging= $this->getVar('PROFILE.LOGGING');
        $log_length   = $this->getVar('PROFILE.LOG_LENGTH');
        settype($log_length, "int");
        if ($log_length < 1) {
            $log_length = 50;
        }

        /* 1. event logging */
        if ($event_logging) {  
            $logfile      = $this->registry->get('LOGFILE');
            $log_changed  = false;
            $log_read     = false;
            if (!$logfile->exists()) {
                $logfile->create();
            }           
            foreach ($this->log as $i => $log) 
            {                       
                if (strtolower(get_class($log)) == "log") {
                    if (!$log_read) {
                        $logfile->read();
                        $log_read = true;
                    }
                    if ($logfile->length()>$log_length) {
                        $logfile->remove(0);
                    }
                    if (strpos($logfile->get(0), '"'.$log->getMessage().'"') === false) {
                        /* do no create duplicate entries */
                        $logfile->insert('ACTION="'.$this->getVar("ACTION").'", '.$log->getLog()."\n");
                        $log_changed = true;
                    }
                    array_splice($this->log, $i, 1);
                }
            }
            if ($log_changed) {
                $logfile->write();
            }
        }
    }

}

@session_start();

?>