Index: code/trunk/src/libraries/core/CMakeLists.txt
===================================================================
--- code/trunk/src/libraries/core/CMakeLists.txt	(revision 6084)
+++ code/trunk/src/libraries/core/CMakeLists.txt	(revision 6105)
@@ -29,4 +29,5 @@
   GraphicsManager.cc
   GUIManager.cc
+  IOConsole.cc
   Language.cc
   LuaState.cc
Index: code/trunk/src/libraries/core/ConfigFileManager.h
===================================================================
--- code/trunk/src/libraries/core/ConfigFileManager.h	(revision 6084)
+++ code/trunk/src/libraries/core/ConfigFileManager.h	(revision 6105)
@@ -54,10 +54,10 @@
     };
 
-    bool config(const std::string& classname, const std::string& varname, const std::string& value);
-    bool tconfig(const std::string& classname, const std::string& varname, const std::string& value);
-    void reloadConfig();
-    void saveConfig();
-    void cleanConfig();
-    void loadSettings(const std::string& filename);
+    _CoreExport bool config(const std::string& classname, const std::string& varname, const std::string& value);
+    _CoreExport bool tconfig(const std::string& classname, const std::string& varname, const std::string& value);
+    _CoreExport void reloadConfig();
+    _CoreExport void saveConfig();
+    _CoreExport void cleanConfig();
+    _CoreExport void loadSettings(const std::string& filename);
 
 
Index: code/trunk/src/libraries/core/ConfigValueIncludes.h
===================================================================
--- code/trunk/src/libraries/core/ConfigValueIncludes.h	(revision 6084)
+++ code/trunk/src/libraries/core/ConfigValueIncludes.h	(revision 6105)
@@ -47,15 +47,15 @@
     @param defvalue The default-value of the variable
 */
-#define SetConfigValueGeneric(type, varname, defvalue) \
+#define SetConfigValueGeneric(type, varname, entryname, sectionname, defvalue) \
     static orxonox::Identifier* identifier##varname = this->getIdentifier(); \
-    orxonox::ConfigValueContainer* container##varname = identifier##varname->getConfigValueContainer(#varname); \
+    orxonox::ConfigValueContainer* container##varname = identifier##varname->getConfigValueContainer(entryname); \
     if (!container##varname) \
     { \
-        container##varname = new orxonox::ConfigValueContainer(type, identifier##varname, identifier##varname->getName(), #varname, defvalue, varname); \
-        identifier##varname->addConfigValueContainer(#varname, container##varname); \
+        container##varname = new orxonox::ConfigValueContainer(type, identifier##varname, sectionname, entryname, defvalue, varname); \
+        identifier##varname->addConfigValueContainer(entryname, container##varname); \
     } \
     container##varname->getValue(&varname, this)
 
-#define SetConfigValue(varname, defvalue) SetConfigValueGeneric(ConfigFileType::Settings, varname, defvalue)
+#define SetConfigValue(varname, defvalue) SetConfigValueGeneric(ConfigFileType::Settings, varname, #varname, identifier##varname->getName(), defvalue)
 
 
Index: code/trunk/src/libraries/core/ConsoleCommandCompilation.cc
===================================================================
--- code/trunk/src/libraries/core/ConsoleCommandCompilation.cc	(revision 6084)
+++ code/trunk/src/libraries/core/ConsoleCommandCompilation.cc	(revision 6105)
@@ -86,5 +86,4 @@
     std::string echo(const std::string& text)
     {
-        std::cout << text << std::endl;
         return text;
     }
Index: code/trunk/src/libraries/core/Core.cc
===================================================================
--- code/trunk/src/libraries/core/Core.cc	(revision 6084)
+++ code/trunk/src/libraries/core/Core.cc	(revision 6105)
@@ -64,7 +64,7 @@
 #include "Identifier.h"
 #include "Language.h"
+#include "IOConsole.h"
 #include "LuaState.h"
 #include "ScopedSingletonManager.h"
-#include "Shell.h"
 #include "TclBind.h"
 #include "TclThreadManager.h"
@@ -105,47 +105,19 @@
         void setConfigValues()
         {
-#ifdef NDEBUG
-            const unsigned int defaultLevelConsole = 1;
-            const unsigned int defaultLevelLogfile = 3;
-            const unsigned int defaultLevelShell   = 1;
+#ifdef ORXONOX_RELEASE
+            const unsigned int defaultLevelLogFile = 3;
 #else
-            const unsigned int defaultLevelConsole = 3;
-            const unsigned int defaultLevelLogfile = 4;
-            const unsigned int defaultLevelShell   = 3;
-#endif
-            SetConfigValue(softDebugLevelConsole_, defaultLevelConsole)
-                .description("The maximal level of debug output shown in the console")
-                .callback(this, &CoreConfiguration::debugLevelChanged);
-            SetConfigValue(softDebugLevelLogfile_, defaultLevelLogfile)
-                .description("The maximal level of debug output shown in the logfile")
-                .callback(this, &CoreConfiguration::debugLevelChanged);
-            SetConfigValue(softDebugLevelShell_, defaultLevelShell)
-                .description("The maximal level of debug output shown in the ingame shell")
-                .callback(this, &CoreConfiguration::debugLevelChanged);
+            const unsigned int defaultLevelLogFile = 4;
+#endif
+            SetConfigValueGeneric(ConfigFileType::Settings, softDebugLevelLogFile_, "softDebugLevelLogFile", "OutputHandler", defaultLevelLogFile)
+                .description("The maximum level of debug output shown in the log file");
+            OutputHandler::getInstance().setSoftDebugLevel(OutputHandler::logFileOutputListenerName_s, this->softDebugLevelLogFile_);
 
             SetConfigValue(language_, Language::getInstance().defaultLanguage_)
-                .description("The language of the ingame text")
+                .description("The language of the in game text")
                 .callback(this, &CoreConfiguration::languageChanged);
             SetConfigValue(bInitializeRandomNumberGenerator_, true)
                 .description("If true, all random actions are different each time you start the game")
                 .callback(this, &CoreConfiguration::initializeRandomNumberGenerator);
-        }
-
-        /**
-            @brief Callback function if the debug level has changed.
-        */
-        void debugLevelChanged()
-        {
-            // softDebugLevel_ is the maximum of the 3 variables
-            this->softDebugLevel_ = this->softDebugLevelConsole_;
-            if (this->softDebugLevelLogfile_ > this->softDebugLevel_)
-                this->softDebugLevel_ = this->softDebugLevelLogfile_;
-            if (this->softDebugLevelShell_ > this->softDebugLevel_)
-                this->softDebugLevel_ = this->softDebugLevelShell_;
-
-            OutputHandler::setSoftDebugLevel(OutputHandler::LD_All,     this->softDebugLevel_);
-            OutputHandler::setSoftDebugLevel(OutputHandler::LD_Console, this->softDebugLevelConsole_);
-            OutputHandler::setSoftDebugLevel(OutputHandler::LD_Logfile, this->softDebugLevelLogfile_);
-            OutputHandler::setSoftDebugLevel(OutputHandler::LD_Shell,   this->softDebugLevelShell_);
         }
 
@@ -178,8 +150,5 @@
         }
 
-        int softDebugLevel_;                            //!< The debug level
-        int softDebugLevelConsole_;                     //!< The debug level for the console
-        int softDebugLevelLogfile_;                     //!< The debug level for the logfile
-        int softDebugLevelShell_;                       //!< The debug level for the ingame shell
+        int softDebugLevelLogFile_;                     //!< The debug level for the log file (belongs to OutputHandler)
         std::string language_;                          //!< The language
         bool bInitializeRandomNumberGenerator_;         //!< If true, srand(time(0)) is called
@@ -221,11 +190,11 @@
         this->pathConfig_->setConfigurablePaths();
 
-        // create a signal handler (only active for linux)
+        // create a signal handler (only active for Linux)
         // This call is placed as soon as possible, but after the directories are set
         this->signalHandler_.reset(new SignalHandler());
         this->signalHandler_->doCatch(PathConfig::getExecutablePathString(), PathConfig::getLogPathString() + "orxonox_crash.log");
 
-        // Set the correct log path. Before this call, /tmp (Unix) or %TEMP% was used
-        OutputHandler::getOutStream().setLogPath(PathConfig::getLogPathString());
+        // Set the correct log path. Before this call, /tmp (Unix) or %TEMP% (Windows) was used
+        OutputHandler::getInstance().setLogPath(PathConfig::getLogPathString());
 
         // Parse additional options file now that we know its path
@@ -249,4 +218,7 @@
         this->languageInstance_.reset(new Language());
 
+        // create persistent io console
+        this->ioConsole_.reset(new IOConsole());
+
         // creates the class hierarchy for all classes with factories
         Identifier::createClassHierarchy();
@@ -262,7 +234,4 @@
         this->tclBind_.reset(new TclBind(PathConfig::getDataPathString()));
         this->tclThreadManager_.reset(new TclThreadManager(tclBind_->getTclInterpreter()));
-
-        // create a shell
-        this->shell_.reset(new Shell());
 
         // Create singletons that always exist (in other libraries)
@@ -325,46 +294,4 @@
         bGraphicsLoaded_ = false;
         GameMode::bShowsGraphics_s = false;
-    }
-
-    /**
-        @brief Returns the softDebugLevel for the given device (returns a default-value if the class is right about to be created).
-        @param device The device
-        @return The softDebugLevel
-    */
-    /*static*/ int Core::getSoftDebugLevel(OutputHandler::OutputDevice device)
-    {
-        switch (device)
-        {
-        case OutputHandler::LD_All:
-            return Core::getInstance().configuration_->softDebugLevel_;
-        case OutputHandler::LD_Console:
-            return Core::getInstance().configuration_->softDebugLevelConsole_;
-        case OutputHandler::LD_Logfile:
-            return Core::getInstance().configuration_->softDebugLevelLogfile_;
-        case OutputHandler::LD_Shell:
-            return Core::getInstance().configuration_->softDebugLevelShell_;
-        default:
-            assert(0);
-            return 2;
-        }
-    }
-
-     /**
-        @brief Sets the softDebugLevel for the given device. Please use this only temporary and restore the value afterwards, as it overrides the configured value.
-        @param device The device
-        @param level The level
-    */
-    /*static*/ void Core::setSoftDebugLevel(OutputHandler::OutputDevice device, int level)
-    {
-        if (device == OutputHandler::LD_All)
-            Core::getInstance().configuration_->softDebugLevel_ = level;
-        else if (device == OutputHandler::LD_Console)
-            Core::getInstance().configuration_->softDebugLevelConsole_ = level;
-        else if (device == OutputHandler::LD_Logfile)
-            Core::getInstance().configuration_->softDebugLevelLogfile_ = level;
-        else if (device == OutputHandler::LD_Shell)
-            Core::getInstance().configuration_->softDebugLevelShell_ = level;
-
-        OutputHandler::setSoftDebugLevel(device, level);
     }
 
@@ -444,4 +371,6 @@
             ScopedSingletonManager::update<ScopeID::Graphics>(time);
         }
+        // process console text
+        this->ioConsole_->update(time);
         // process thread commands
         this->tclThreadManager_->update(time);
Index: code/trunk/src/libraries/core/Core.h
===================================================================
--- code/trunk/src/libraries/core/Core.h	(revision 6084)
+++ code/trunk/src/libraries/core/Core.h	(revision 6105)
@@ -69,6 +69,4 @@
             void setConfigValues();
 
-            static int   getSoftDebugLevel(OutputHandler::OutputDevice device = OutputHandler::LD_All);
-            static void  setSoftDebugLevel(OutputHandler::OutputDevice device, int level);
             static const std::string& getLanguage();
             static void  resetLanguage();
@@ -93,8 +91,8 @@
             scoped_ptr<ConfigFileManager> configFileManager_;
             scoped_ptr<Language>          languageInstance_;
+            scoped_ptr<IOConsole>         ioConsole_;
             scoped_ptr<CoreConfiguration> configuration_;
             scoped_ptr<TclBind>           tclBind_;
             scoped_ptr<TclThreadManager>  tclThreadManager_;
-            scoped_ptr<Shell>             shell_;
             // graphical
             scoped_ptr<GraphicsManager>   graphicsManager_;     //!< Interface to OGRE
Index: code/trunk/src/libraries/core/CorePrereqs.h
===================================================================
--- code/trunk/src/libraries/core/CorePrereqs.h	(revision 6084)
+++ code/trunk/src/libraries/core/CorePrereqs.h	(revision 6105)
@@ -148,4 +148,5 @@
     class GUIManager;
     class Identifier;
+    class IOConsole;
     class IRC;
     template <class T>
Index: code/trunk/src/libraries/core/GUIManager.cc
===================================================================
--- code/trunk/src/libraries/core/GUIManager.cc	(revision 6084)
+++ code/trunk/src/libraries/core/GUIManager.cc	(revision 6105)
@@ -53,5 +53,4 @@
 #include "util/Exception.h"
 #include "util/OrxAssert.h"
-#include "Core.h"
 #include "LuaState.h"
 #include "PathConfig.h"
@@ -75,5 +74,5 @@
                 default: OrxAssert(false, "CEGUI log level out of range, inpect immediately!");
             }
-            OutputHandler::getOutStream().setOutputLevel(orxonoxLevel)
+            OutputHandler::getOutStream(orxonoxLevel)
                 << "CEGUI: " << message << std::endl;
 
@@ -121,5 +120,5 @@
         // set the log level according to ours (translate by subtracting 1)
         ceguiLogger->setLoggingLevel(
-            static_cast<LoggingLevel>(Core::getSoftDebugLevel(OutputHandler::LD_Logfile) - 1));
+            static_cast<LoggingLevel>(OutputHandler::getInstance().getSoftDebugLevel("logFile") - 1));
         this->ceguiLogger_ = ceguiLogger.release();
 
@@ -127,5 +126,5 @@
         guiSystem_.reset(new System(guiRenderer_.get(), resourceProvider_, 0, scriptModule_.get()));
 
-        // Initialise the basic lua code
+        // Initialise the basic Lua code
         rootFileInfo_ = Resource::getInfo("InitialiseGUI.lua", "GUI");
         this->luaState_->doFile("InitialiseGUI.lua", "GUI", false);
@@ -134,5 +133,5 @@
         guiSystem_->injectMousePosition(mousePosition.first, mousePosition.second);
 
-        // Hide the mouse cursor unless playing in fullscreen mode
+        // Hide the mouse cursor unless playing in full screen mode
         if (!bFullScreen)
             CEGUI::MouseCursor::getSingleton().hide();
@@ -280,5 +279,5 @@
         code of the mouse button as it is used by CEGUI
 
-        Simple convertion from mouse event code in Orxonox to the one used in CEGUI.
+        Simple conversion from mouse event code in Orxonox to the one used in CEGUI.
      */
     static inline CEGUI::MouseButton convertButton(MouseButtonCode::ByEnum button)
Index: code/trunk/src/libraries/core/GraphicsManager.cc
===================================================================
--- code/trunk/src/libraries/core/GraphicsManager.cc	(revision 6084)
+++ code/trunk/src/libraries/core/GraphicsManager.cc	(revision 6105)
@@ -409,5 +409,5 @@
             orxonoxLevel = 0;
         }
-        OutputHandler::getOutStream().setOutputLevel(orxonoxLevel)
+        OutputHandler::getOutStream(orxonoxLevel)
             << "Ogre: " << message << std::endl;
     }
Index: code/trunk/src/libraries/core/GraphicsManager.h
===================================================================
--- code/trunk/src/libraries/core/GraphicsManager.h	(revision 6084)
+++ code/trunk/src/libraries/core/GraphicsManager.h	(revision 6105)
@@ -106,11 +106,11 @@
 
         // config values
-        std::string         ogreConfigFile_;           //!< ogre config file name
+        std::string         ogreConfigFile_;           //!< ogre config filename
         std::string         ogrePluginsDirectory_;     //!< Directory where the Ogre plugins are located
         std::string         ogrePlugins_;              //!< Comma separated list of all plugins to load
-        std::string         ogreLogFile_;              //!< log file name for Ogre log messages
-        int                 ogreLogLevelTrivial_;      //!< Corresponding Orxonx debug level for LL_TRIVIAL
-        int                 ogreLogLevelNormal_;       //!< Corresponding Orxonx debug level for LL_NORMAL
-        int                 ogreLogLevelCritical_;     //!< Corresponding Orxonx debug level for LL_CRITICAL
+        std::string         ogreLogFile_;              //!< log filename for Ogre log messages
+        int                 ogreLogLevelTrivial_;      //!< Corresponding Orxonox debug level for LL_TRIVIAL
+        int                 ogreLogLevelNormal_;       //!< Corresponding Orxonox debug level for LL_NORMAL
+        int                 ogreLogLevelCritical_;     //!< Corresponding Orxonox debug level for LL_CRITICAL
 
         // console commands
Index: code/trunk/src/libraries/core/IOConsole.cc
===================================================================
--- code/trunk/src/libraries/core/IOConsole.cc	(revision 6105)
+++ code/trunk/src/libraries/core/IOConsole.cc	(revision 6105)
@@ -0,0 +1,562 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Oliver Scheuss
+ *      Reto Grieder
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#include "IOConsole.h"
+
+#include <iomanip>
+#include <iostream>
+#include "core/Game.h"
+#include "core/input/InputBuffer.h"
+
+// ##########################
+// ###   Mutual methods   ###
+// ##########################
+namespace orxonox
+{
+    IOConsole* IOConsole::singletonPtr_s = NULL;
+
+    int IOConsole::extractLogLevel(std::string* text)
+    {
+        // Handle line colouring by inspecting the first letter
+        char level = 0;
+        if (!text->empty())
+        {
+            level = (*text)[0];
+            if (level == -1 || level >= 1 && level <= 6)
+            {
+                *text = text->substr(1);
+                if (level != -1)
+                    return level;
+            }
+        }
+        return 0;
+    }
+
+    inline bool IOConsole::willPrintStatusLines()
+    {
+        return !this->statusLineWidths_.empty()
+             && this->terminalWidth_  >= this->statusLineMaxWidth_
+             && this->terminalHeight_ >= (this->minOutputLines_ + this->statusLineWidths_.size());
+    }
+
+    // ###############################
+    // ###  ShellListener methods  ###
+    // ###############################
+
+    //! Called if all output-lines have to be reprinted
+    void IOConsole::linesChanged()
+    {
+        // Method only gets called upon start to draw all the lines
+        // or when scrolling. But scrolling is disabled and the output
+        // is already in std::cout when we start the IOConsole
+    }
+
+    //! Called if the text in the input-line has changed
+    void IOConsole::inputChanged()
+    {
+        this->printInputLine();
+        this->cout_.flush();
+    }
+
+    //! Called if the position of the cursor in the input-line has changed
+    void IOConsole::cursorChanged()
+    {
+        this->printInputLine();
+        this->cout_.flush();
+    }
+
+    //! Called if a command is about to be executed
+    void IOConsole::executed()
+    {
+        this->shell_->addOutputLine(this->promptString_ + this->shell_->getInput());
+    }
+
+    //! Called if the console gets closed
+    void IOConsole::exit()
+    {
+        // Exit is not an option, just do nothing (Shell doesn't really exit too)
+    }
+}
+
+#ifdef ORXONOX_PLATFORM_UNIX
+// ###############################
+// ###   Unix Implementation   ###
+// ###############################
+
+#include <termios.h>
+#include <sys/ioctl.h>
+
+namespace orxonox
+{
+    namespace EscapeMode
+    {
+        enum Value
+        {
+            None,
+            First,
+            Second
+        };
+    }
+
+    IOConsole::IOConsole()
+        : shell_(new Shell("IOConsole", false, true))
+        , buffer_(shell_->getInputBuffer())
+        , cout_(std::cout.rdbuf())
+        , bStatusPrinted_(false)
+        , promptString_("orxonox # ")
+        , originalTerminalSettings_(new termios())
+    {
+        this->setTerminalMode();
+        this->shell_->registerListener(this);
+
+        // Manually set the widths of the individual status lines
+        this->statusLineWidths_.push_back(29);
+        this->statusLineMaxWidth_ = 29;
+
+        this->getTerminalSize();
+        this->lastTerminalWidth_ = this->terminalWidth_;
+        this->lastTerminalHeight_ = this->terminalHeight_;
+
+        // Disable standard std::cout logging
+        OutputHandler::getInstance().disableCout();
+        // Redirect std::cout to an ostringstream
+        // (Other part is in the initialiser list)
+        std::cout.rdbuf(this->origCout_.rdbuf());
+
+        // Make sure we make way for the status lines
+        this->update(Game::getInstance().getGameClock());
+    }
+
+    IOConsole::~IOConsole()
+    {
+        // Empty all buffers
+        this->update(Game::getInstance().getGameClock());
+        // Erase input and status lines
+        this->cout_ << "\033[1G\033[J";
+        // Move cursor to the bottom
+        this->cout_ << "\033[" << this->statusLineWidths_.size() << 'B';
+        // Scroll terminal to compensate for erased lines
+        this->cout_ << "\033[" << this->statusLineWidths_.size() << 'T';
+
+        resetTerminalMode();
+        delete this->originalTerminalSettings_;
+        this->shell_->destroy();
+
+        // Restore this->cout_ redirection
+        std::cout.rdbuf(this->cout_.rdbuf());
+        // Enable standard std::cout logging again
+        OutputHandler::getInstance().enableCout();
+    }
+
+    void IOConsole::update(const Clock& time)
+    {
+        unsigned char c;
+        std::string escapeSequence;
+        EscapeMode::Value escapeMode = EscapeMode::None;
+        while (std::cin.good())
+        {
+            c = std::cin.get();
+            if (!std::cin.good())
+                break;
+
+            if (escapeMode == EscapeMode::First && (c == '[' || c=='O') )
+                escapeMode = EscapeMode::Second;
+            // Get Alt+Tab combination when switching applications
+            else if (escapeMode == EscapeMode::First && c == '\t')
+            {
+                this->buffer_->buttonPressed(KeyEvent(KeyCode::Tab, '\t', KeyboardModifier::Alt));
+                escapeMode = EscapeMode::None;
+            }
+            else if (escapeMode == EscapeMode::Second)
+            {
+                escapeSequence += c;
+                escapeMode = EscapeMode::None;
+                if      (escapeSequence == "A")
+                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Up,       0, 0));
+                else if (escapeSequence == "B")
+                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Down,     0, 0));
+                else if (escapeSequence == "C")
+                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Right,    0, 0));
+                else if (escapeSequence == "D")
+                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Left,     0, 0));
+                else if (escapeSequence == "1~" || escapeSequence == "H")
+                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Home,     0, 0));
+                else if (escapeSequence == "2~")
+                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Insert,   0, 0));
+                else if (escapeSequence == "3~")
+                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Delete,   0, 0));
+                else if (escapeSequence == "4~" || escapeSequence == "F")
+                    this->buffer_->buttonPressed(KeyEvent(KeyCode::End,      0, 0));
+                else if (escapeSequence == "5~")
+                    this->buffer_->buttonPressed(KeyEvent(KeyCode::PageUp,   0, 0));
+                else if (escapeSequence == "6~")
+                    this->buffer_->buttonPressed(KeyEvent(KeyCode::PageDown, 0, 0));
+                else
+                    // Waiting for sequence to complete
+                    // If the user presses ESC and then '[' or 'O' while the loop is not
+                    // running (for instance while loading), the whole sequence gets dropped
+                    escapeMode = EscapeMode::Second;
+            }
+            else // not in an escape sequence OR user might have pressed just ESC
+            {
+                if (escapeMode == EscapeMode::First)
+                {
+                    this->buffer_->buttonPressed(KeyEvent(KeyCode::Escape, c, 0));
+                    escapeMode = EscapeMode::None;
+                }
+                if (c == '\033')
+                {
+                    escapeMode = EscapeMode::First;
+                    escapeSequence.clear();
+                }
+                else
+                {
+                    KeyCode::ByEnum code;
+                    switch (c)
+                    {
+                    case '\n'  : case '\r': code = KeyCode::Return; break;
+                    case '\177': case '\b': code = KeyCode::Back;   break;
+                    case '\t'             : code = KeyCode::Tab;    break;
+                    default:
+                        // We don't encode the key code (would be a very large switch)
+                        // because the InputBuffer will only insert the text anyway
+                        // Replacement character is simply KeyCode::A
+                        code = KeyCode::A;
+                    }
+                    this->buffer_->buttonPressed(KeyEvent(code, c, 0));
+                }
+            }
+        }
+        // Reset error flags in std::cin
+        std::cin.clear();
+
+        // If there is still an escape key pending (escape key ONLY), then
+        // it sure isn't an escape sequence anymore
+        if (escapeMode == EscapeMode::First)
+            this->buffer_->buttonPressed(KeyEvent(KeyCode::Escape, '\033', 0));
+
+        // Determine terminal width and height
+        this->lastTerminalWidth_ = this->terminalWidth_;
+        this->lastTerminalHeight_ = this->terminalHeight_;
+        this->getTerminalSize();
+
+        int heightDiff = this->terminalHeight_ - this->lastTerminalHeight_;
+        if (this->bStatusPrinted_ && heightDiff < 0)
+        {
+            // Terminal width has shrunk. The cursor will still be on the input line,
+            // but that line might very well be the last
+            int newLines = std::min((int)this->statusLineWidths_.size(), -heightDiff);
+            // Scroll terminal to create new lines
+            this->cout_ << "\033[" << newLines << 'S';
+        }
+
+        if (!this->bStatusPrinted_ && this->willPrintStatusLines())
+        {
+            // Scroll console to make way for status lines
+            this->cout_ << "\033[" << this->statusLineWidths_.size() << 'S';
+            this->bStatusPrinted_ = true;
+        }
+
+        // We always assume that the cursor is on the inputline.
+        // But we cannot always be sure about that, esp. if we scroll the console
+        this->cout_ << "\033[" << this->statusLineWidths_.size() << 'B';
+        this->cout_ << "\033[" << this->statusLineWidths_.size() << 'A';
+
+        // Erase status and input lines
+        this->cout_ << "\033[1G\033[J";
+        this->printInputLine();
+        this->printStatusLines();
+        this->cout_.flush();
+
+        // Process output written to std::cout
+        if (!this->origCout_.str().empty())
+        {
+            this->shell_->addOutputLine(this->origCout_.str());
+            this->origCout_.str("");
+        }
+    }
+
+    void IOConsole::printLogText(const std::string& text)
+    {
+        std::string output = text;
+        /*int level =*/ this->extractLogLevel(&output);
+
+/*
+        // Colour line
+        switch (level)
+        {
+        case -1: this->cout_ << "\033[37m"; break;
+        case  1: this->cout_ << "\033[91m"; break;
+        case  2: this->cout_ << "\033[31m"; break;
+        case  3: this->cout_ << "\033[34m"; break;
+        case  4: this->cout_ << "\033[36m"; break;
+        case  5: this->cout_ << "\033[35m"; break;
+        case  6: this->cout_ << "\033[37m"; break;
+        default: break;
+        }
+*/
+
+        // Print output line
+        this->cout_ << output;
+
+        // Reset colour to white
+//        this->cout_ << "\033[37m";
+    }
+
+    void IOConsole::printInputLine()
+    {
+        // Set cursor to the beginning of the line and erase the line
+        this->cout_ << "\033[1G\033[K";
+        // Indicate a command prompt
+        this->cout_ << this->promptString_;
+        // Save cursor position
+        this->cout_ << "\033[s";
+        // Print command line buffer
+        this->cout_ << this->shell_->getInput();
+        // Restore cursor position and move it to the right
+        this->cout_ << "\033[u";
+        if (this->buffer_->getCursorPosition() > 0)
+            this->cout_ << "\033[" << this->buffer_->getCursorPosition() << "C";
+    }
+
+    void IOConsole::printStatusLines()
+    {
+        if (this->willPrintStatusLines())
+        {
+            // Save cursor position
+            this->cout_ << "\033[s";
+            // Move cursor down (don't create a new line here because the buffer might flush then!)
+            this->cout_ << "\033[1B\033[1G";
+            this->cout_ << std::fixed << std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgFPS() << " fps, ";
+            this->cout_ <<               std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgTickTime() << " ms tick time";
+            // Restore cursor position
+            this->cout_ << "\033[u";
+            this->bStatusPrinted_ = true;
+        }
+        else
+            this->bStatusPrinted_ = false;
+    }
+
+    void IOConsole::setTerminalMode()
+    {
+        termios new_settings;
+
+        tcgetattr(0, this->originalTerminalSettings_);
+        new_settings = *this->originalTerminalSettings_;
+        new_settings.c_lflag &= ~(ICANON | ECHO);
+        //new_settings.c_lflag |= (ISIG | IEXTEN);
+        new_settings.c_cc[VTIME] = 0;
+        new_settings.c_cc[VMIN]  = 0;
+        tcsetattr(0, TCSANOW, &new_settings);
+    }
+
+    void IOConsole::resetTerminalMode()
+    {
+        tcsetattr(0, TCSANOW, IOConsole::originalTerminalSettings_);
+    }
+
+    void IOConsole::getTerminalSize()
+    {
+#ifdef TIOCGSIZE
+        struct ttysize win;
+        if (!ioctl(STDIN_FILENO, TIOCGSIZE, &win))
+        {
+            this->terminalWidth_  = win.ts_cols;
+            this->terminalHeight_ = win.ts_lines;
+            return;
+        }
+#elif defined TIOCGWINSZ
+        struct winsize win;
+        if (!ioctl(STDIN_FILENO, TIOCGWINSZ, &win))
+        {
+            this->terminalWidth_  = win.ws_col;
+            this->terminalHeight_ = win.ws_row;
+            return;
+        }
+#else
+        const char* s = getenv("COLUMNS");
+        this->terminalWidth_  = s ? strtol(s, NULL, 10) : 80;
+        s = getenv("LINES");
+        this->terminalHeight_ = s ? strtol(s, NULL, 10) : 24;
+        return;
+#endif
+        this->terminalWidth_  = 80;
+        this->terminalHeight_ = 24;
+    }
+
+    // ###############################
+    // ###  ShellListener methods  ###
+    // ###############################
+
+    //! Called if only the last output-line has changed
+    void IOConsole::onlyLastLineChanged()
+    {
+        // Save cursor position and move it to the beginning of the first output line
+        this->cout_ << "\033[s\033[1A\033[1G";
+        // Erase the line
+        this->cout_ << "\033[K";
+        // Reprint the last output line
+        this->printLogText(*(this->shell_->getNewestLineIterator()));
+        // Restore cursor
+        this->cout_ << "\033[u";
+        this->cout_.flush();
+    }
+
+    //! Called if a new output-line was added
+    void IOConsole::lineAdded()
+    {
+        int newLines = this->shell_->getNewestLineIterator()->size() / this->terminalWidth_ + 1;
+        // Create new lines by scrolling the screen
+        this->cout_ << "\033[" << newLines << 'S';
+        // Move cursor to the beginning of the new (last) output line
+        this->cout_ << "\033[" << newLines << "A\033[1G";
+        // Erase screen from here
+        this->cout_ << "\033[J";
+        // Print the new output lines
+        for (int i = 0; i < newLines; ++i)
+            this->printLogText(this->shell_->getNewestLineIterator()->substr(i*this->terminalWidth_, this->terminalWidth_));
+        // Move cursor down
+        this->cout_ << "\033[1B\033[1G";
+        // Print status and input lines
+        this->printInputLine();
+        this->printStatusLines();
+        this->cout_.flush();
+    }
+}
+
+#elif defined(ORXONOX_PLATFORM_WINDOWS)
+// ##################################
+// ###   Windows Implementation   ###
+// ##################################
+
+namespace orxonox
+{
+    IOConsole::IOConsole()
+        : shell_(new Shell("IOConsole", false, true))
+        , buffer_(shell_->getInputBuffer())
+        , cout_(std::cout.rdbuf())
+        , bStatusPrinted_(false)
+        , promptString_("orxonox # ")
+    {
+/*
+        this->setTerminalMode();
+        this->shell_->registerListener(this);
+
+        // Manually set the widths of the individual status lines
+        this->statusLineWidths_.push_back(29);
+        this->statusLineMaxWidth_ = 29;
+
+        this->getTerminalSize();
+        this->lastTerminalWidth_ = this->terminalWidth_;
+        this->lastTerminalHeight_ = this->terminalHeight_;
+
+        // Disable standard this->cout_ logging
+        OutputHandler::getInstance().disableCout();
+*/
+    }
+
+    IOConsole::~IOConsole()
+    {
+/*
+        resetTerminalMode();
+        this->shell_->destroy();
+
+        // Enable standard this->cout_ logging again
+        OutputHandler::getInstance().enableCout();
+*/
+    }
+
+    void IOConsole::update(const Clock& time)
+    {
+/*
+        unsigned char c = 0;
+        while (std::cin.good())
+        {
+            c = std::cin.get();
+            if (std::cin.bad())
+                break;
+        }
+        // Reset error flags in std::cin
+        std::cin.clear();
+
+        // Determine terminal width and height
+        this->lastTerminalWidth_ = this->terminalWidth_;
+        this->lastTerminalHeight_ = this->terminalHeight_;
+        this->getTerminalSize();
+*/
+    }
+
+    void IOConsole::printLogText(const std::string& text)
+    {
+    }
+
+    void IOConsole::printInputLine()
+    {
+    }
+
+    void IOConsole::printStatusLines()
+    {
+/*
+        if (this->willPrintStatusLines())
+        {
+            this->bStatusPrinted_ = true;
+        }
+        else
+            this->bStatusPrinted_ = false;
+*/
+    }
+
+    void IOConsole::setTerminalMode()
+    {
+    }
+
+    void IOConsole::resetTerminalMode()
+    {
+    }
+
+    void IOConsole::getTerminalSize()
+    {
+    }
+
+    // ###############################
+    // ###  ShellListener methods  ###
+    // ###############################
+
+    //! Called if only the last output-line has changed
+    void IOConsole::onlyLastLineChanged()
+    {
+    }
+
+    //! Called if a new output-line was added
+    void IOConsole::lineAdded()
+    {
+    }
+}
+
+#endif /* ORXONOX_PLATFORM_UNIX */
Index: code/trunk/src/libraries/core/IOConsole.h
===================================================================
--- code/trunk/src/libraries/core/IOConsole.h	(revision 6105)
+++ code/trunk/src/libraries/core/IOConsole.h	(revision 6105)
@@ -0,0 +1,99 @@
+/*
+ *   ORXONOX - the hottest 3D action shooter ever to exist
+ *                    > www.orxonox.net <
+ *
+ *
+ *   License notice:
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation; either version 2
+ *   of the License, or (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ *   Author:
+ *      Oliver Scheuss
+ *      Reto Grieder
+ *   Co-authors:
+ *      ...
+ *
+ */
+
+#ifndef _IOConsole_H__
+#define _IOConsole_H__
+
+#include "CorePrereqs.h"
+
+#include <sstream>
+#include <string>
+#include <vector>
+#include "util/Singleton.h"
+#include "core/Shell.h"
+
+#ifdef ORXONOX_PLATFORM_UNIX
+struct termios;
+#endif
+
+namespace orxonox
+{
+    class _CoreExport IOConsole : public Singleton<IOConsole>, public ShellListener
+    {
+        friend class Singleton<IOConsole>;
+
+    public:
+        IOConsole();
+        ~IOConsole();
+
+        void update(const Clock& time);
+
+    private:
+        void setTerminalMode();
+        void resetTerminalMode();
+        void getTerminalSize();
+        bool willPrintStatusLines();
+        int extractLogLevel(std::string* text);
+
+        void printLogText(const std::string& line);
+        void printInputLine();
+        void printStatusLines();
+
+        // Methods from ShellListener
+        void linesChanged();
+        void onlyLastLineChanged();
+        void lineAdded();
+        void inputChanged();
+        void cursorChanged();
+        void executed();
+        void exit();
+        Shell*                  shell_;
+        InputBuffer*            buffer_;
+        std::ostream            cout_;
+        std::ostringstream      origCout_;
+        unsigned int            terminalWidth_;
+        unsigned int            terminalHeight_;
+        unsigned int            lastTerminalWidth_;
+        unsigned int            lastTerminalHeight_;
+        bool                    bPrintStatusLine_;
+        bool                    bStatusPrinted_;
+        std::vector<unsigned>   statusLineWidths_;
+        unsigned int            statusLineMaxWidth_;
+        const std::string       promptString_;
+        static const unsigned   minOutputLines_ = 3;
+
+#ifdef ORXONOX_PLATFORM_UNIX
+        termios*                originalTerminalSettings_;
+#endif
+
+        static IOConsole* singletonPtr_s;
+    };
+}
+
+#endif /* _IOConsole_H__ */
Index: code/trunk/src/libraries/core/LuaState.cc
===================================================================
--- code/trunk/src/libraries/core/LuaState.cc	(revision 6084)
+++ code/trunk/src/libraries/core/LuaState.cc	(revision 6105)
@@ -182,5 +182,5 @@
     void LuaState::luaLog(unsigned int level, const std::string& message)
     {
-        OutputHandler::getOutStream().setOutputLevel(level) << message << std::endl;
+        OutputHandler::getOutStream(level) << message << std::endl;
     }
 
Index: code/trunk/src/libraries/core/OrxonoxClass.cc
===================================================================
--- code/trunk/src/libraries/core/OrxonoxClass.cc	(revision 6084)
+++ code/trunk/src/libraries/core/OrxonoxClass.cc	(revision 6105)
@@ -34,4 +34,5 @@
 #include "OrxonoxClass.h"
 
+#include <cassert>
 #include "MetaObjectList.h"
 #include "Identifier.h"
@@ -72,4 +73,5 @@
     void OrxonoxClass::destroy()
     {
+        assert(this); // Just in case someone tries to delete a NULL pointer
         this->requestedDestruction_ = true;
         if (this->referenceCount_ == 0)
Index: code/trunk/src/libraries/core/OrxonoxClass.h
===================================================================
--- code/trunk/src/libraries/core/OrxonoxClass.h	(revision 6084)
+++ code/trunk/src/libraries/core/OrxonoxClass.h	(revision 6105)
@@ -42,4 +42,11 @@
 #include <set>
 #include <vector>
+
+/**
+@def CCOUT
+    Acts almost exactly like COUT(x), but prepends "ClassName: "
+*/
+#define CCOUT(level) \
+    COUT(level) << this->getIdentifier()->getName() << ": "
 
 namespace orxonox
Index: code/trunk/src/libraries/core/PathConfig.cc
===================================================================
--- code/trunk/src/libraries/core/PathConfig.cc	(revision 6084)
+++ code/trunk/src/libraries/core/PathConfig.cc	(revision 6105)
@@ -263,4 +263,8 @@
         putenv(const_cast<char*>(("PATH=" + pathVariable + ";" + modulePath_.string()).c_str()));
 
+        // Make sure the path exists, otherwise don't load modules
+        if (!boost::filesystem::exists(modulePath_))
+            return modulePaths;
+
         boost::filesystem::directory_iterator file(modulePath_);
         boost::filesystem::directory_iterator end;
Index: code/trunk/src/libraries/core/Shell.cc
===================================================================
--- code/trunk/src/libraries/core/Shell.cc	(revision 6084)
+++ code/trunk/src/libraries/core/Shell.cc	(revision 6105)
@@ -23,5 +23,5 @@
  *      Fabian 'x3n' Landau
  *   Co-authors:
- *      ...
+ *      Reto Grieder
  *
  */
@@ -30,19 +30,13 @@
 
 #include "util/OutputHandler.h"
+#include "util/StringUtils.h"
+#include "util/SubString.h"
 #include "CommandExecutor.h"
 #include "CoreIncludes.h"
 #include "ConfigValueIncludes.h"
-#include "Core.h"
 #include "ConsoleCommand.h"
-
-#define SHELL_UPDATE_LISTENERS(function) \
-    for (std::list<ShellListener*>::iterator it = this->listeners_.begin(); it != this->listeners_.end(); ) \
-        (*(it++))->function()
 
 namespace orxonox
 {
-    SetConsoleCommand(Shell, clearShell, true);
-    SetConsoleCommand(Shell, history, true);
-
     SetConsoleCommandShortcut(OutputHandler, log);
     SetConsoleCommandShortcut(OutputHandler, error);
@@ -51,11 +45,11 @@
     SetConsoleCommandShortcut(OutputHandler, debug);
 
-    Shell* Shell::singletonPtr_s = 0;
-
-    Shell::Shell()
-    {
-        int level = Core::getSoftDebugLevel(OutputHandler::LD_Shell);
-        Core::setSoftDebugLevel(OutputHandler::LD_Shell, -1);
-
+    Shell::Shell(const std::string& consoleName, bool bScrollable, bool bPrependOutputLevel)
+        : OutputListener(consoleName)
+        , inputBuffer_(new InputBuffer())
+        , consoleName_(consoleName)
+        , bPrependOutputLevel_(bPrependOutputLevel)
+        , bScrollable_(bScrollable)
+    {
         RegisterRootObject(Shell);
 
@@ -64,14 +58,8 @@
         this->historyPosition_ = 0;
         this->historyOffset_ = 0;
-        this->finishedLastLine_ = true;
-        this->bAddOutputLevel_ = false;
-
-        this->clearLines();
-
-        this->inputBuffer_ = new InputBuffer();
+        this->bFinishedLastLine_ = true;
+
+        this->clearOutput();
         this->configureInputBuffer();
-
-        this->outputBuffer_.registerListener(this);
-        OutputHandler::getOutStream().setOutputBuffer(&this->outputBuffer_);
 
         // Get a config file for the command history
@@ -79,23 +67,46 @@
         ConfigFileManager::getInstance().setFilename(this->commandHistoryConfigFileType_, "commandHistory.ini");
 
+        // Use a stringstream object to buffer the output and get it line by line in update()
+        this->outputStream_ = &this->outputBuffer_;
+
         this->setConfigValues();
 
-        Core::setSoftDebugLevel(OutputHandler::LD_Shell, level);
+        // Get the previous output and add it to the Shell
+        for (OutputHandler::OutputVectorIterator it = OutputHandler::getInstance().getOutputVectorBegin();
+            it != OutputHandler::getInstance().getOutputVectorEnd(); ++it)
+        {
+            if (it->first <= this->getSoftDebugLevel())
+            {
+                this->outputBuffer_ << it->second;
+                this->outputChanged(it->first);
+            }
+        }
+
+        // Register the shell as output listener
+        OutputHandler::getInstance().registerOutputListener(this);
     }
 
     Shell::~Shell()
     {
-        OutputHandler::getOutStream().setOutputBuffer(0);
-        if (this->inputBuffer_)
-            this->inputBuffer_->destroy();
+        OutputHandler::getInstance().unregisterOutputListener(this);
+        this->inputBuffer_->destroy();
     }
 
     void Shell::setConfigValues()
     {
-        SetConfigValueGeneric(commandHistoryConfigFileType_, maxHistoryLength_, 100)
+        SetConfigValue(maxHistoryLength_, 100)
             .callback(this, &Shell::commandHistoryLengthChanged);
-        SetConfigValueGeneric(commandHistoryConfigFileType_, historyOffset_, 0)
+        SetConfigValue(historyOffset_, 0)
             .callback(this, &Shell::commandHistoryOffsetChanged);
         SetConfigValueVectorGeneric(commandHistoryConfigFileType_, commandHistory_, std::vector<std::string>());
+
+#ifdef ORXONOX_RELEASE
+        const unsigned int defaultLevel = 1;
+#else
+        const unsigned int defaultLevel = 3;
+#endif
+        SetConfigValueGeneric(ConfigFileType::Settings, softDebugLevel_, "softDebugLevel" + this->consoleName_, "OutputHandler", defaultLevel)
+            .description("The maximal level of debug output shown in the Shell");
+        this->setSoftDebugLevel(this->softDebugLevel_);
     }
 
@@ -121,24 +132,30 @@
     {
         this->inputBuffer_->registerListener(this, &Shell::inputChanged, true);
-        this->inputBuffer_->registerListener(this, &Shell::execute, '\r', false);
-        this->inputBuffer_->registerListener(this, &Shell::hintandcomplete, '\t', true);
-        this->inputBuffer_->registerListener(this, &Shell::backspace, '\b', true);
-        this->inputBuffer_->registerListener(this, &Shell::deletechar, KeyCode::Delete);
-        this->inputBuffer_->registerListener(this, &Shell::exit, static_cast<char>(27), true);
-        this->inputBuffer_->registerListener(this, &Shell::cursor_right, KeyCode::Right);
-        this->inputBuffer_->registerListener(this, &Shell::cursor_left, KeyCode::Left);
-        this->inputBuffer_->registerListener(this, &Shell::cursor_end, KeyCode::End);
-        this->inputBuffer_->registerListener(this, &Shell::cursor_home, KeyCode::Home);
-        this->inputBuffer_->registerListener(this, &Shell::history_up, KeyCode::Up);
-        this->inputBuffer_->registerListener(this, &Shell::history_down, KeyCode::Down);
-        this->inputBuffer_->registerListener(this, &Shell::scroll_up, KeyCode::PageUp);
-        this->inputBuffer_->registerListener(this, &Shell::scroll_down, KeyCode::PageDown);
-    }
-
-    void Shell::clearShell()
-    {
-        Shell::getInstance().clearLines();
-    }
-
+        this->inputBuffer_->registerListener(this, &Shell::execute,         '\r',   false);
+        this->inputBuffer_->registerListener(this, &Shell::execute,         '\n',   false);
+        this->inputBuffer_->registerListener(this, &Shell::hintAndComplete, '\t',   true);
+        this->inputBuffer_->registerListener(this, &Shell::backspace,       '\b',   true);
+        this->inputBuffer_->registerListener(this, &Shell::backspace,       '\177', true);
+        this->inputBuffer_->registerListener(this, &Shell::exit,            '\033', true); // escape
+        this->inputBuffer_->registerListener(this, &Shell::deleteChar,      KeyCode::Delete);
+        this->inputBuffer_->registerListener(this, &Shell::cursorRight,     KeyCode::Right);
+        this->inputBuffer_->registerListener(this, &Shell::cursorLeft,      KeyCode::Left);
+        this->inputBuffer_->registerListener(this, &Shell::cursorEnd,       KeyCode::End);
+        this->inputBuffer_->registerListener(this, &Shell::cursorHome,      KeyCode::Home);
+        this->inputBuffer_->registerListener(this, &Shell::historyUp,       KeyCode::Up);
+        this->inputBuffer_->registerListener(this, &Shell::historyDown,     KeyCode::Down);
+        if (this->bScrollable_)
+        {
+            this->inputBuffer_->registerListener(this, &Shell::scrollUp,    KeyCode::PageUp);
+            this->inputBuffer_->registerListener(this, &Shell::scrollDown,  KeyCode::PageDown);
+        }
+        else
+        {
+            this->inputBuffer_->registerListener(this, &Shell::historySearchUp,   KeyCode::PageUp);
+            this->inputBuffer_->registerListener(this, &Shell::historySearchDown, KeyCode::PageDown);
+        }
+    }
+
+    /*
     void Shell::history()
     {
@@ -146,12 +163,13 @@
 
         for (unsigned int i = instance.historyOffset_; i < instance.commandHistory_.size(); ++i)
-            instance.addLine(instance.commandHistory_[i], -1);
+            instance.addOutputLine(instance.commandHistory_[i], -1);
         for (unsigned int i =  0; i < instance.historyOffset_; ++i)
-            instance.addLine(instance.commandHistory_[i], -1);
-    }
+            instance.addOutputLine(instance.commandHistory_[i], -1);
+    }
+    */
 
     void Shell::registerListener(ShellListener* listener)
     {
-        this->listeners_.insert(this->listeners_.end(), listener);
+        this->listeners_.push_back(listener);
     }
 
@@ -161,5 +179,5 @@
         {
             if ((*it) == listener)
-                this->listeners_.erase(it++);
+                it = this->listeners_.erase(it);
             else
                 ++it;
@@ -170,34 +188,28 @@
     {
         this->inputBuffer_->setCursorPosition(cursor);
-        SHELL_UPDATE_LISTENERS(cursorChanged);
-    }
-
-    void Shell::setInput(const std::string& input)
-    {
-        this->inputBuffer_->set(input);
-        this->inputChanged();
-    }
-
-    void Shell::addLine(const std::string& line, int level)
-    {
-        int original_level = OutputHandler::getOutStream().getOutputLevel();
-        OutputHandler::getOutStream().setOutputLevel(level);
-
-        if (!this->finishedLastLine_)
-            this->outputBuffer_ << std::endl;
-
-        this->outputBuffer_ << line << std::endl;
-        OutputHandler::getOutStream().setOutputLevel(original_level);
-    }
-
-    void Shell::clearLines()
-    {
-        this->lines_.clear();
-        this->scrollIterator_ = this->lines_.begin();
+        this->updateListeners<&ShellListener::cursorChanged>();
+    }
+
+    void Shell::addOutputLine(const std::string& line, int level)
+    {
+        // Make sure we really only have one line per line (no new lines!)
+        SubString lines(line, '\n');
+        for (unsigned i = 0; i < lines.size(); ++i)
+        {
+            if (level <= this->softDebugLevel_)
+                this->outputLines_.push_front(lines[i]);
+            this->updateListeners<&ShellListener::lineAdded>();
+        }
+    }
+
+    void Shell::clearOutput()
+    {
+        this->outputLines_.clear();
+        this->scrollIterator_ = this->outputLines_.begin();
 
         this->scrollPosition_ = 0;
-        this->finishedLastLine_ = true;
-
-        SHELL_UPDATE_LISTENERS(linesChanged);
+        this->bFinishedLastLine_ = true;
+
+        this->updateListeners<&ShellListener::linesChanged>();
     }
 
@@ -207,10 +219,10 @@
             return this->scrollIterator_;
         else
-            return this->lines_.begin();
+            return this->outputLines_.begin();
     }
 
     std::list<std::string>::const_iterator Shell::getEndIterator() const
     {
-        return this->lines_.end();
+        return this->outputLines_.end();
     }
 
@@ -231,39 +243,47 @@
     }
 
-    void Shell::outputChanged()
-    {
-        std::string output;
-        bool newline;
+    void Shell::outputChanged(int level)
+    {
+        bool newline = false;
         do
         {
-            newline = this->outputBuffer_.getLine(&output);
+            std::string output;
+            std::getline(this->outputBuffer_, output);
+
+            bool eof = this->outputBuffer_.eof();
+            bool fail = this->outputBuffer_.fail();
+            if (eof)
+                this->outputBuffer_.flush();
+            if (eof || fail)
+                this->outputBuffer_.clear();
+            newline = (!eof && !fail);
 
             if (!newline && output == "")
                 break;
 
-            if (this->finishedLastLine_)
+            if (this->bFinishedLastLine_)
             {
-                if (this->bAddOutputLevel_)
-                    output.insert(0, 1, static_cast<char>(OutputHandler::getOutStream().getOutputLevel()));
-
-                this->lines_.insert(this->lines_.begin(), output);
+                if (this->bPrependOutputLevel_)
+                    output.insert(0, 1, static_cast<char>(level));
+
+                this->outputLines_.push_front(output);
 
                 if (this->scrollPosition_)
                     this->scrollPosition_++;
                 else
-                    this->scrollIterator_ = this->lines_.begin();
-
-                this->finishedLastLine_ = newline;
+                    this->scrollIterator_ = this->outputLines_.begin();
+
+                this->bFinishedLastLine_ = newline;
 
                 if (!this->scrollPosition_)
                 {
-                    SHELL_UPDATE_LISTENERS(lineAdded);
+                    this->updateListeners<&ShellListener::lineAdded>();
                 }
             }
             else
             {
-                (*this->lines_.begin()) += output;
-                this->finishedLastLine_ = newline;
-                SHELL_UPDATE_LISTENERS(onlyLastLineChanged);
+                (*this->outputLines_.begin()) += output;
+                this->bFinishedLastLine_ = newline;
+                this->updateListeners<&ShellListener::onlyLastLineChanged>();
             }
 
@@ -271,75 +291,99 @@
     }
 
-    void Shell::inputChanged()
-    {
-        SHELL_UPDATE_LISTENERS(inputChanged);
-        SHELL_UPDATE_LISTENERS(cursorChanged);
-    }
-
-    void Shell::execute()
-    {
-        this->addToHistory(this->inputBuffer_->get());
-        this->addLine(this->inputBuffer_->get(), 0);
-
-        if (!CommandExecutor::execute(this->inputBuffer_->get()))
-            this->addLine("Error: Can't execute \"" + this->inputBuffer_->get() + "\".", 1);
-
-        this->clear();
-    }
-
-    void Shell::hintandcomplete()
-    {
-        this->inputBuffer_->set(CommandExecutor::complete(this->inputBuffer_->get()));
-        this->addLine(CommandExecutor::hint(this->inputBuffer_->get()), -1);
-
-        this->inputChanged();
-    }
-
-    void Shell::backspace()
-    {
-        this->inputBuffer_->removeBehindCursor();
-        SHELL_UPDATE_LISTENERS(inputChanged);
-        SHELL_UPDATE_LISTENERS(cursorChanged);
-    }
-
-    void Shell::deletechar()
-    {
-        this->inputBuffer_->removeAtCursor();
-        SHELL_UPDATE_LISTENERS(inputChanged);
-    }
-
-    void Shell::clear()
+    void Shell::clearInput()
     {
         this->inputBuffer_->clear();
         this->historyPosition_ = 0;
-        SHELL_UPDATE_LISTENERS(inputChanged);
-        SHELL_UPDATE_LISTENERS(cursorChanged);
-    }
-
-    void Shell::cursor_right()
+        this->updateListeners<&ShellListener::inputChanged>();
+        this->updateListeners<&ShellListener::cursorChanged>();
+    }
+
+    void Shell::setPromptPrefix(const std::string& str)
+    {
+    }
+
+
+    // ##########################################
+    // ###   InputBuffer callback functions   ###
+    // ##########################################
+
+    void Shell::inputChanged()
+    {
+        this->updateListeners<&ShellListener::inputChanged>();
+        this->updateListeners<&ShellListener::cursorChanged>();
+    }
+
+    void Shell::execute()
+    {
+        this->addToHistory(this->inputBuffer_->get());
+        this->updateListeners<&ShellListener::executed>();
+
+        if (!CommandExecutor::execute(this->inputBuffer_->get()))
+            this->addOutputLine("Error: Can't execute \"" + this->inputBuffer_->get() + "\".", 1);
+
+        this->clearInput();
+    }
+
+    void Shell::hintAndComplete()
+    {
+        this->inputBuffer_->set(CommandExecutor::complete(this->inputBuffer_->get()));
+        this->addOutputLine(CommandExecutor::hint(this->inputBuffer_->get()), -1);
+
+        this->inputChanged();
+    }
+
+    void Shell::backspace()
+    {
+        this->inputBuffer_->removeBehindCursor();
+        this->updateListeners<&ShellListener::inputChanged>();
+        this->updateListeners<&ShellListener::cursorChanged>();
+    }
+
+    void Shell::exit()
+    {
+        if (this->inputBuffer_->getSize() > 0)
+        {
+            this->clearInput();
+            return;
+        }
+
+        this->clearInput();
+        this->scrollPosition_ = 0;
+        this->scrollIterator_ = this->outputLines_.begin();
+
+        this->updateListeners<&ShellListener::exit>();
+    }
+
+    void Shell::deleteChar()
+    {
+        this->inputBuffer_->removeAtCursor();
+        this->updateListeners<&ShellListener::inputChanged>();
+    }
+
+    void Shell::cursorRight()
     {
         this->inputBuffer_->increaseCursor();
-        SHELL_UPDATE_LISTENERS(cursorChanged);
-    }
-
-    void Shell::cursor_left()
+        this->updateListeners<&ShellListener::cursorChanged>();
+    }
+
+    void Shell::cursorLeft()
     {
         this->inputBuffer_->decreaseCursor();
-        SHELL_UPDATE_LISTENERS(cursorChanged);
-    }
-
-    void Shell::cursor_end()
+        this->updateListeners<&ShellListener::cursorChanged>();
+    }
+
+    void Shell::cursorEnd()
     {
         this->inputBuffer_->setCursorToEnd();
-        SHELL_UPDATE_LISTENERS(cursorChanged);
-    }
-
-    void Shell::cursor_home()
+        this->updateListeners<&ShellListener::cursorChanged>();
+    }
+
+    void Shell::cursorHome()
     {
         this->inputBuffer_->setCursorToBegin();
-        SHELL_UPDATE_LISTENERS(cursorChanged);
-    }
-
-    void Shell::history_up()
+        this->updateListeners<&ShellListener::cursorChanged>();
+    }
+
+    void Shell::historyUp()
     {
         if (this->historyPosition_ < this->commandHistory_.size())
@@ -350,5 +394,5 @@
     }
 
-    void Shell::history_down()
+    void Shell::historyDown()
     {
         if (this->historyPosition_ > 0)
@@ -359,39 +403,60 @@
     }
 
-    void Shell::scroll_up()
-    {
-        if (this->scrollIterator_ != this->lines_.end())
+    void Shell::historySearchUp()
+    {
+        if (this->historyPosition_ == this->historyOffset_)
+            return;
+        unsigned int cursorPosition = this->getCursorPosition();
+        std::string input_str(this->getInput().substr(0, cursorPosition)); // only search for the expression from the beginning of the inputline until the cursor position
+        for (unsigned int newPos = this->historyPosition_ + 1; newPos <= this->historyOffset_; newPos++)
+        {
+            if (getLowercase(this->commandHistory_[this->historyOffset_ - newPos]).find(getLowercase(input_str)) == 0) // search case insensitive
+            {
+                this->historyPosition_ = newPos;
+                this->inputBuffer_->set(this->getFromHistory());
+                this->setCursorPosition(cursorPosition);
+                return;
+            }
+        }
+    }
+
+    void Shell::historySearchDown()
+    {
+        if (this->historyPosition_ == 0)
+            return;
+        unsigned int cursorPosition = this->getCursorPosition();
+        std::string input_str(this->getInput().substr(0, cursorPosition)); // only search for the expression from the beginning
+        for (unsigned int newPos = this->historyPosition_ - 1; newPos > 0; newPos--)
+        {
+            if (getLowercase(this->commandHistory_[this->historyOffset_ - newPos]).find(getLowercase(input_str)) == 0) // sear$
+            {
+                this->historyPosition_ = newPos;
+                this->inputBuffer_->set(this->getFromHistory());
+                this->setCursorPosition(cursorPosition);
+                return;
+            }
+        }
+    }
+
+    void Shell::scrollUp()
+    {
+        if (this->scrollIterator_ != this->outputLines_.end())
         {
             ++this->scrollIterator_;
             ++this->scrollPosition_;
 
-            SHELL_UPDATE_LISTENERS(linesChanged);
-        }
-    }
-
-    void Shell::scroll_down()
-    {
-        if (this->scrollIterator_ != this->lines_.begin())
+            this->updateListeners<&ShellListener::linesChanged>();
+        }
+    }
+
+    void Shell::scrollDown()
+    {
+        if (this->scrollIterator_ != this->outputLines_.begin())
         {
             --this->scrollIterator_;
             --this->scrollPosition_;
 
-            SHELL_UPDATE_LISTENERS(linesChanged);
-        }
-    }
-
-    void Shell::exit()
-    {
-        if (this->inputBuffer_->getSize() > 0)
-        {
-            this->clear();
-            return;
-        }
-
-        this->clear();
-        this->scrollPosition_ = 0;
-        this->scrollIterator_ = this->lines_.begin();
-
-        SHELL_UPDATE_LISTENERS(exit);
+            this->updateListeners<&ShellListener::linesChanged>();
+        }
     }
 }
Index: code/trunk/src/libraries/core/Shell.h
===================================================================
--- code/trunk/src/libraries/core/Shell.h	(revision 6084)
+++ code/trunk/src/libraries/core/Shell.h	(revision 6105)
@@ -23,5 +23,5 @@
  *      Fabian 'x3n' Landau
  *   Co-authors:
- *      ...
+ *      Reto Grieder
  *
  */
@@ -32,13 +32,13 @@
 #include "CorePrereqs.h"
 
-#include <cassert>
 #include <list>
+#include <sstream>
 #include <string>
 #include <vector>
 
-#include "util/OutputBuffer.h"
-#include "input/InputBuffer.h"
+#include "util/OutputHandler.h"
 #include "OrxonoxClass.h"
 #include "ConfigFileManager.h"
+#include "input/InputBuffer.h"
 
 namespace orxonox
@@ -57,18 +57,16 @@
             virtual void inputChanged() {}
             virtual void cursorChanged() {}
+            virtual void executed() {}
             virtual void exit() {}
     };
 
-    class _CoreExport Shell : public Singleton<Shell>, virtual public OrxonoxClass, public OutputBufferListener
+
+    class _CoreExport Shell : virtual public OrxonoxClass, public OutputListener
     {
-        friend class Singleton<Shell>;
         public:
-            Shell();
-            virtual ~Shell();
+            Shell(const std::string& consoleName, bool bScrollable, bool bPrependOutputLevel = false);
+            ~Shell();
 
-            static void clearShell();
-            static void history();
-
-            virtual void setConfigValues();
+            void setConfigValues();
             void commandHistoryOffsetChanged();
             void commandHistoryLengthChanged();
@@ -79,6 +77,4 @@
             inline InputBuffer* getInputBuffer()
                 { return this->inputBuffer_; }
-            inline OutputBuffer& getOutputBuffer()
-                { return this->outputBuffer_; }
 
             void setCursorPosition(unsigned int cursor);
@@ -86,8 +82,4 @@
                 { return this->inputBuffer_->getCursorPosition(); }
 
-            void setInput(const std::string& input);
-
-            inline void clearInput()
-                { this->setInput(""); }
             inline std::string getInput() const
                 { return this->inputBuffer_->get(); }
@@ -96,56 +88,71 @@
             std::list<std::string>::const_iterator getEndIterator() const;
 
-            void addLine(const std::string& line, int level = 0);
-            void clearLines();
+            void addOutputLine(const std::string& line, int level = 0);
+            void clearOutput();
 
             inline unsigned int getNumLines() const
-                { return this->lines_.size(); }
+                { return this->outputLines_.size(); }
             inline unsigned int getScrollPosition() const
                 { return this->scrollPosition_; }
 
-            inline void addOutputLevel(bool bAddOutputLevel)
-                { this->bAddOutputLevel_ = bAddOutputLevel; }
+            inline const std::string& getPromptPrefix() const { return this->promptPrefix_; }
+            void setPromptPrefix(const std::string& str);
 
         private:
             Shell(const Shell& other);
 
+            void addToHistory(const std::string& command);
+            std::string getFromHistory() const;
+            void clearInput();
+            // OutputListener
+            void outputChanged(int level);
+
             void configureInputBuffer();
 
-            void addToHistory(const std::string& command);
-            std::string getFromHistory() const;
-
-            virtual void outputChanged();
+            // InputBuffer callbacks
             void inputChanged();
             void execute();
-            void hintandcomplete();
+            void hintAndComplete();
             void backspace();
-            void deletechar();
-            void clear();
-            void cursor_right();
-            void cursor_left();
-            void cursor_end();
-            void cursor_home();
-            void history_up();
-            void history_down();
-            void scroll_up();
-            void scroll_down();
+            void deleteChar();
+            void cursorRight();
+            void cursorLeft();
+            void cursorEnd();
+            void cursorHome();
+            void historyUp();
+            void historyDown();
+            void historySearchUp();
+            void historySearchDown();
+            void scrollUp();
+            void scrollDown();
             void exit();
 
+            template <void (ShellListener::*F)()>
+            void updateListeners()
+            {
+                for (std::list<ShellListener*>::const_iterator it = this->listeners_.begin(); it != this->listeners_.end(); )
+                    ((*(it++))->*F)();
+            }
+
             std::list<ShellListener*> listeners_;
-            InputBuffer* inputBuffer_;
-            OutputBuffer outputBuffer_;
-            bool finishedLastLine_;
-            std::list<std::string> lines_;
+            InputBuffer*              inputBuffer_;
+            std::stringstream         outputBuffer_;
+            bool                      bFinishedLastLine_;
+            std::list<std::string>    outputLines_;
             std::list<std::string>::const_iterator scrollIterator_;
-            unsigned int scrollPosition_;
-            std::vector<std::string> commandHistory_;
-            unsigned int maxHistoryLength_;
-            unsigned int historyPosition_;
-            unsigned int historyOffset_;
-            bool bAddOutputLevel_;
+            unsigned int              scrollPosition_;
+            unsigned int              historyPosition_;
+            ConfigFileType            commandHistoryConfigFileType_;
 
-            ConfigFileType commandHistoryConfigFileType_;
+            std::string               promptPrefix_;
+            const std::string         consoleName_;
+            const bool                bPrependOutputLevel_;
+            const bool                bScrollable_;
 
-            static Shell* singletonPtr_s;
+            // Config values
+            unsigned int              maxHistoryLength_;
+            unsigned int              historyOffset_;
+            std::vector<std::string>  commandHistory_;
+            int                       softDebugLevel_;
     };
 }
Index: code/trunk/src/libraries/core/input/InputBuffer.cc
===================================================================
--- code/trunk/src/libraries/core/input/InputBuffer.cc	(revision 6084)
+++ code/trunk/src/libraries/core/input/InputBuffer.cc	(revision 6105)
@@ -80,5 +80,5 @@
     void InputBuffer::setConfigValues()
     {
-        SetConfigValue(keyRepeatDeleay_, 0.4).description("Key repeat deleay of the input buffer");
+        SetConfigValue(keyRepeatDeleay_, 0.4).description("Key repeat delay of the input buffer");
         SetConfigValue(keyRepeatTime_, 0.022).description("Key repeat time of the input buffer");
 
@@ -186,4 +186,5 @@
     void InputBuffer::processKey(const KeyEvent& evt)
     {
+        // Prevent disaster when switching applications
         if (evt.isModifierDown(KeyboardModifier::Alt) && evt.getKeyCode() == KeyCode::Tab)
             return;
@@ -222,5 +223,5 @@
 
     /**
-        @brief This update() function is called by the InputManager if the InputBuffer is active.
+        @brief This update() function is called by the InputState if the InputBuffer is active.
         @param dt Delta time
     */
Index: code/trunk/src/libraries/core/input/InputBuffer.h
===================================================================
--- code/trunk/src/libraries/core/input/InputBuffer.h	(revision 6084)
+++ code/trunk/src/libraries/core/input/InputBuffer.h	(revision 6105)
@@ -162,8 +162,9 @@
                 { if (this->cursor_ > 0) { --this->cursor_; } }
 
+            void buttonPressed(const KeyEvent& evt);
+
         private:
             bool charIsAllowed(const char& input);
 
-            void buttonPressed(const KeyEvent& evt);
             void buttonHeld   (const KeyEvent& evt);
             void processKey   (const KeyEvent& evt);
Index: code/trunk/src/libraries/core/input/InputHandler.h
===================================================================
--- code/trunk/src/libraries/core/input/InputHandler.h	(revision 6084)
+++ code/trunk/src/libraries/core/input/InputHandler.h	(revision 6105)
@@ -73,4 +73,9 @@
             , modifiers_(0)
         { }
+        KeyEvent(KeyCode::ByEnum key, unsigned int text, int modifiers)
+            : key_(key)
+            , text_(text)
+            , modifiers_(modifiers)
+        { }
         bool operator==(const KeyEvent& rhs) const
             { return rhs.key_ == key_; }
@@ -97,8 +102,8 @@
 
         Derive from this class if you wish to receive input events.
-        But keep in mind that this is pointless wihtout first having an InputState.
+        But keep in mind that this is pointless without first having an InputState.
     @note
         The definitions for the button events with the weird arguments are simply
-        to avoid redunant code in the input devices.
+        to avoid redundant code in the input devices.
     */
     class _CoreExport InputHandler
Index: code/trunk/src/libraries/core/input/InputManager.cc
===================================================================
--- code/trunk/src/libraries/core/input/InputManager.cc	(revision 6084)
+++ code/trunk/src/libraries/core/input/InputManager.cc	(revision 6105)
@@ -190,5 +190,5 @@
             // Exception-safety
             Loki::ScopeGuard guard = Loki::MakeGuard(OIS::InputManager::destroyInputSystem, oisInputManager_);
-            CCOUT(ORX_DEBUG) << "Created OIS input manager." << std::endl;
+            CCOUT(4) << "Created OIS input manager." << std::endl;
 
             if (oisInputManager_->getNumberOfDevices(OIS::OISKeyboard) > 0)
@@ -232,5 +232,5 @@
         }
         else
-            CCOUT(ORX_WARNING) << "Warning: No mouse found! Proceeding without mouse support." << std::endl;
+            CCOUT(2) << "Warning: No mouse found! Proceeding without mouse support." << std::endl;
     }
 
