Index: code/trunk/src/orxonox/gamestates/GSDedicated.cc
===================================================================
--- code/trunk/src/orxonox/gamestates/GSDedicated.cc	(revision 3196)
+++ code/trunk/src/orxonox/gamestates/GSDedicated.cc	(revision 3198)
@@ -33,11 +33,25 @@
 #include "core/Clock.h"
 #include "core/CommandLine.h"
+#include "core/CommandExecutor.h"
 #include "core/Game.h"
 #include "core/GameMode.h"
 #include "network/Server.h"
 
+#include <iostream>
+#include <iomanip>
+#include <boost/bind.hpp>
+
+#ifndef ORXONOX_PLATFORM_WINDOWS
+#include <termios.h>
+#endif
+
+
 namespace orxonox
 {
+    const unsigned int MAX_COMMAND_LENGTH = 255;
+    
     AddGameState(GSDedicated, "dedicated");
+    
+    termios* GSDedicated::originalTerminalSettings_;
 
     GSDedicated::GSDedicated(const std::string& name)
@@ -45,5 +59,12 @@
         , server_(0)
         , timeSinceLastUpdate_(0)
-    {
+        , closeThread_(false)
+        , inputIterator_(0)
+        , cleanLine_(true)
+        , cursorX_(0)
+        , cursorY_(0)
+    {
+        this->commandLine_ = new unsigned char[MAX_COMMAND_LENGTH];
+//         memset( this->commandLine_, 0, MAX_COMMAND_LENGTH );
     }
 
@@ -55,4 +76,11 @@
     {
         GameMode::setHasServer(true);
+        
+        this->inputThread_ = new boost::thread(boost::bind(&GSDedicated::inputThread, this));
+        
+#ifndef ORXONOX_PLATFORM_WINDOWS
+        this->originalTerminalSettings_ = new termios;
+        this->setTerminalMode();
+#endif
 
         this->server_ = new Server(CommandLine::getValue("port"));
@@ -66,4 +94,13 @@
         this->server_->close();
         delete this->server_;
+        
+        closeThread_ = true;
+#ifndef ORXONOX_PLATFORM_WINDOWS
+        std::cout << "\033[0G\033[K";
+        std::cout.flush();
+        resetTerminalMode();
+        delete this->originalTerminalSettings_;
+#endif
+        //inputThread_->join();
 
         GameMode::setHasServer(false);
@@ -72,11 +109,7 @@
     void GSDedicated::update(const Clock& time)
     {
-//        static float startTime = time.getSecondsPrecise();
-//        static int nrOfTicks = 0;
         timeSinceLastUpdate_ += time.getDeltaTime();
         if (timeSinceLastUpdate_ >= NETWORK_PERIOD)
         {
-//            ++nrOfTicks;
-//            COUT(0) << "estimated ticks/sec: " << nrOfTicks/(time.getSecondsPrecise()-startTime) << endl;
             timeSinceLastUpdate_ -= static_cast<unsigned int>(timeSinceLastUpdate_ / NETWORK_PERIOD) * NETWORK_PERIOD;
             server_->update(time);
@@ -84,7 +117,186 @@
         else
         {
-            usleep((int)((NETWORK_PERIOD - timeSinceLastUpdate_) * 1000 * 1000));
+            usleep((unsigned int)((NETWORK_PERIOD - timeSinceLastUpdate_)*1000*1000 ));
+            usleep(NETWORK_PERIOD*1000*1000); // NOTE: this is to throttle the non-network framerate
 //            COUT(0) << "sleeping for " << (int)((NETWORK_PERIOD - timeSinceLastUpdate_) * 1000 * 1000) << " usec" << endl;
         }
-    }
+        processQueue();
+        printLine();
+    }
+    
+    void GSDedicated::inputThread()
+    {
+        unsigned char c;
+        unsigned int  escapeChar=0;
+        while(!closeThread_)
+        {
+            c = getchar();
+            {
+//                 boost::recursive_mutex::scoped_lock(this->inputLineMutex_);
+                if ( inputIterator_>=MAX_COMMAND_LENGTH-1 && c!='\n' )
+                    continue;
+                if( escapeChar > 0 )
+                {
+                    if( c == '[' )
+                    {
+                        escapeChar = 2;
+                        continue;
+                    }
+                    else if ( escapeChar == 2 )
+                    {
+                        switch (c)
+                        {
+                            case 'A': //keyup
+                                
+                                break;
+                            case 'B': //keydown
+                                
+                                break;
+                            case 'C': //keyright
+                                if(cursorX_<inputIterator_)
+                                    ++cursorX_;
+                                break;
+                            case 'D': //keyleft
+                                if(cursorX_>0)
+                                    --cursorX_;
+                                break;
+                            default: //not supported...
+//                                 std::cout << endl << c << endl;
+                                break;
+                        }
+                        escapeChar = 0;
+                    }
+                }
+                else // not in escape sequence mode
+                {
+                    switch (c)
+                    {
+                        case '\n':
+                            this->cleanLine_ = true;
+                            {
+                                boost::recursive_mutex::scoped_lock(this->inputQueueMutex_);
+                                boost::recursive_mutex::scoped_lock(this->inputLineMutex_);
+                                this->commandQueue_.push( std::string((const char*)this->commandLine_,inputIterator_) );
+                            }
+                            memset( this->commandLine_, 0, inputIterator_ );
+                            inputIterator_ = 0;
+                            this->cursorX_ = 0;
+                            this->cursorY_ = 0;
+                            std::cout << endl;
+                            break;
+                        case 127: // backspace
+                        case '\b':
+                            deleteCharacter( this->cursorX_ );
+                            break;
+                        case '\t':
+                        {
+//                             boost::recursive_mutex::scoped_lock(this->inputLineMutex_);
+                            std::cout << endl << CommandExecutor::hint( std::string((const char*)this->commandLine_,inputIterator_) ) << endl;
+                            strncpy((char*)this->commandLine_, CommandExecutor::complete( std::string((const char*)this->commandLine_,inputIterator_) ).c_str(), MAX_COMMAND_LENGTH);
+                            inputIterator_ = strlen((const char*)this->commandLine_);
+                            break;
+                        }
+                        case '\033': // 1. escape character
+                            escapeChar = 1;
+                            break;
+                        default:
+                            insertCharacter( this->cursorX_, c );
+                            break;
+                    }
+                }
+            }
+        }
+    }
+    
+    void GSDedicated::printLine()
+    {
+#ifndef ORXONOX_PLATFORM_WINDOWS
+        // set cursor to the begining of the line and erase the line
+        std::cout << "\033[0G\033[K";
+//         boost::recursive_mutex::scoped_lock(this->inputLineMutex_);
+        // print status line
+        std::cout << std::fixed << std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgFPS() << " fps, " << std::setprecision(2) << std::setw(5) << Game::getInstance().getAvgTickTime() << " ms avg ticktime # ";
+        //save cursor position
+        std::cout << "\033[s";
+        //print commandLine buffer
+        std::cout << std::string((const char*)this->commandLine_, inputIterator_);
+        //restore cursor position and move it cursorX_ to the right
+        std::cout << "\033[u";
+        if( this->cursorX_ > 0 )
+            std::cout << "\033[" << this->cursorX_ << "C";
+        std::cout.flush();
+#endif
+    }
+    
+    void GSDedicated::processQueue()
+    {
+        std::string tempstr;
+        {
+            boost::recursive_mutex::scoped_lock lock1(this->inputQueueMutex_);
+            while(true)
+            {
+                if ( !this->commandQueue_.empty() )
+                {
+                    tempstr = this->commandQueue_.front();
+                    this->commandQueue_.pop();
+                    lock1.unlock();
+                }
+                else
+                    break;
+                CommandExecutor::execute(tempstr, true);
+            }
+        }
+    }
+    
+    void GSDedicated::setTerminalMode()
+    {
+#ifndef ORXONOX_PLATFORM_WINDOWS
+        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] = 1;
+        tcsetattr(0,TCSANOW,&new_settings);
+        COUT(0) << endl;
+//       atexit(&GSDedicated::resetTerminalMode);
+#endif
+    }
+    
+    void GSDedicated::resetTerminalMode()
+    {
+#ifndef ORXONOX_PLATFORM_WINDOWS
+        tcsetattr(0, TCSANOW, GSDedicated::originalTerminalSettings_);
+#endif
+    }
+    
+    void GSDedicated::insertCharacter( unsigned int position, char c )
+    {
+//         std::cout << endl << (unsigned int)c << endl;
+        // check that we do not exceed MAX_COMMAND_LENGTH
+        if( inputIterator_+1 < MAX_COMMAND_LENGTH )
+        {
+            // if cursor not at end of line then move the rest of the line
+            if( position != this->inputIterator_ )
+                    memmove( this->commandLine_+position+1, this->commandLine_+position, this->inputIterator_-position);
+//             boost::recursive_mutex::scoped_lock(this->inputLineMutex_);
+            this->commandLine_[position] = c;
+            ++this->cursorX_;
+            ++this->inputIterator_;
+        }
+    }
+    void GSDedicated::deleteCharacter( unsigned int position )
+    {
+//         boost::recursive_mutex::scoped_lock(this->inputLineMutex_);
+        if ( this->inputIterator_>0 && position>0 )
+        {
+            if ( position != this->inputIterator_ )
+                memmove( this->commandLine_+position-1, this->commandLine_+position, this->inputIterator_-position);
+            --this->cursorX_;
+            --this->inputIterator_;
+        }
+    }
+    
 }
