Index: code/branches/gui/src/core/Game.cc
===================================================================
--- code/branches/gui/src/orxonox/Game.cc	(revision 2817)
+++ code/branches/gui/src/core/Game.cc	(revision 2844)
@@ -33,5 +33,4 @@
 */
 
-#include "OrxonoxStableHeaders.h"
 #include "Game.h"
 
@@ -41,38 +40,11 @@
 #include "util/Debug.h"
 #include "util/Exception.h"
-#include "core/CommandLine.h"
-#include "core/ConsoleCommand.h"
-#include "core/Core.h"
-#include "core/Identifier.h"
-#include "core/CoreIncludes.h"
-#include "core/ConfigValueIncludes.h"
-
-#include "gamestates/GSRoot.h"
-#include "gamestates/GSGraphics.h"
-#include "gamestates/GSStandalone.h"
-#include "gamestates/GSServer.h"
-#include "gamestates/GSClient.h"
-#include "gamestates/GSDedicated.h"
-#include "gamestates/GSGUI.h"
-#include "gamestates/GSIOConsole.h"
-
-/*
-@brief
-    Main method. Game starts here (except for static initialisations).
-*/
-int main(int argc, char** argv)
-{
-    {
-        orxonox::Game orxonox(argc, argv);
-        orxonox.run();
-        // objects gets destroyed here!
-    }
-
-    // Clean up class hierarchy stuff (identifiers, xmlport, configvalue, consolecommand)
-    // Needs to be done after Game destructor because of ~OrxonoxClass
-    orxonox::Identifier::destroyAllIdentifiers();
-
-    return 0;
-}
+#include "Clock.h"
+#include "CommandLine.h"
+#include "ConsoleCommand.h"
+#include "Core.h"
+#include "CoreIncludes.h"
+#include "ConfigValueIncludes.h"
+#include "GameState.h"
 
 namespace orxonox
@@ -83,7 +55,16 @@
     }
 
+    struct _CoreExport GameStateTreeNode
+    {
+        GameState*                      state_;
+        GameStateTreeNode*              parent_;
+        std::vector<GameStateTreeNode*> children_;
+    };
+
     SetCommandLineArgument(state, "gui").shortcut("s");
+    SetCommandLineSwitch(startWithConsole);
     SetConsoleCommandShortcutExternAlias(stop_game, "exit");
 
+    std::map<std::string, GameState*> Game::allStates_s;
     Game* Game::singletonRef_s = 0;
 
@@ -96,4 +77,7 @@
         assert(singletonRef_s == 0);
         singletonRef_s = this;
+
+        this->rootStateNode_ = 0;
+        this->activeStateNode_ = 0;
 
         this->abort_ = false;
@@ -121,4 +105,8 @@
         // Destroy pretty much everyhting left
         delete this->core_;
+
+        // Delete all GameStates created by the macros
+        for (std::map<std::string, GameState*>::const_iterator it = allStates_s.begin(); it != allStates_s.end(); ++it)
+            delete it->second;
 
         assert(singletonRef_s);
@@ -144,30 +132,43 @@
     void Game::run()
     {
-        // create the gamestates
-        GSRoot root;
-        GSGraphics graphics;
-        GSStandalone standalone;
-        GSServer server;
-        GSClient client;
-        GSDedicated dedicated;
-        GSGUI gui;
-        GSIOConsole ioConsole;
-
-        // make the hierarchy
-        root.addChild(&graphics);
-        graphics.addChild(&standalone);
-        graphics.addChild(&server);
-        graphics.addChild(&client);
-        graphics.addChild(&gui);
-        root.addChild(&ioConsole);
-        root.addChild(&dedicated);
-
-        root.activate();
-
-        // get initial state from command line
-        root.gotoState(CommandLine::getValue("state"));
+        // </EXPORT THIS>
+        this->setStateHierarchy(
+        "root"
+        " graphics"
+        "  gui"
+        "  standalone"
+        "   level"
+        "  server"
+        "   level"
+        "  client"
+        "   level"
+        " dedicated"
+        "  level"
+        " ioConsole"
+        );
+        // </EXPORT THIS>
+
+
+        // Always start with the root state
+        this->requestedStateNodes_.push_back(this->rootStateNode_);
+        this->activeStateNode_ = this->rootStateNode_;
+        this->loadState(this->rootStateNode_->state_);
+
+        // <EXPORT THIS>
+        if (CommandLine::getValue("startWithConsole").getBool())
+        {
+            // Start the game in the console
+            this->requestState("ioConsole");
+        }
+        else
+        {
+            // Start in GUI main menu
+            this->requestState("graphics");
+            this->requestState("gui");
+        }
+        // </EXPORT THIS>
 
         this->gameClock_->capture(); // first delta time should be about 0 seconds
-        while (!this->abort_)
+        while (!this->abort_ && !this->activeStates_.empty())
         {
             this->gameClock_->capture();
@@ -179,6 +180,21 @@
             this->periodTime_ += this->gameClock_->getDeltaTimeMicroseconds();
 
-            // UPDATE
-            root.tick(*this->gameClock_);
+            // UPDATE STATE STACK
+            while (this->requestedStateNodes_.size() > 1)
+            {
+                // Note: this->requestedStateNodes_.front() is the currently active state node
+                std::vector<GameStateTreeNode*>::iterator it = this->requestedStateNodes_.begin() + 1;
+                if (*it == this->activeStateNode_->parent_)
+                    this->unloadState(this->activeStateNode_->state_);
+                else // has to be child
+                    this->loadState((*it)->state_);
+                this->activeStateNode_ = *it;
+                this->requestedStateNodes_.erase(this->requestedStateNodes_.begin());
+            }
+
+            // UPDATE, bottom to top in the stack
+            for (std::vector<GameState*>::const_iterator it = this->activeStates_.begin();
+                it != this->activeStates_.end(); ++it)
+                (*it)->update(*this->gameClock_);
 
             // STATISTICS
@@ -206,11 +222,11 @@
                 this->periodTime_ -= this->statisticsRefreshCycle_;
             }
-
-            if (root.stateRequest_ != "")
-                root.gotoState(root.stateRequest_);
-        }
-
-        root.gotoState("root");
-        root.deactivate();
+        }
+
+        // Unload all remaining states
+        while (!this->activeStates_.empty())
+            this->unloadState(this->activeStates_.back());
+        this->activeStateNode_ = 0;
+        this->requestedStateNodes_.clear();
     }
 
@@ -226,3 +242,167 @@
         this->periodTickTime_+=length;
     }
+
+
+    /***** GameState related *****/
+
+    void Game::requestState(const std::string& name)
+    {
+        GameState* state = this->getState(name);
+        if (state == NULL || this->activeStateNode_ == NULL)
+            return;
+
+        GameStateTreeNode* requestedNode = 0;
+
+        // this->requestedStateNodes_.back() is the currently active state
+        GameStateTreeNode* lastRequestedNode = this->requestedStateNodes_.back();
+
+        // Already the active node?
+        if (state == lastRequestedNode->state_)
+        {
+            COUT(2) << "Warning: Requesting the currently active state! Ignoring." << std::endl;
+            return;
+        }
+
+        // Check children first
+        for (unsigned int i = 0; i < lastRequestedNode->children_.size(); ++i)
+        {
+            if (lastRequestedNode->children_[i]->state_ == state)
+            {
+                requestedNode = lastRequestedNode->children_[i];
+                break;
+            }
+        }
+
+        // Check parent and all its grand parents
+        GameStateTreeNode* currentNode = lastRequestedNode;
+        while (requestedNode == NULL && currentNode->parent_ != NULL)
+        {
+            if (currentNode->state_ == state)
+                requestedNode = currentNode;
+            currentNode = currentNode->parent_;
+        }
+
+        if (requestedNode == NULL)
+            COUT(1) << "Error: Requested GameState transition is not allowed. Ignoring." << std::endl;
+        else
+            this->requestedStateNodes_.push_back(requestedNode);
+    }
+
+    void Game::popState()
+    {
+        if (this->activeStateNode_ != NULL && this->requestedStateNodes_.back()->parent_)
+            this->requestState(this->requestedStateNodes_.back()->parent_->state_->getName());
+        else
+            COUT(2) << "Warning: Could not pop GameState. Ignoring." << std::endl;
+    }
+
+    GameState* Game::getState(const std::string& name)
+    {
+        std::map<std::string, GameState*>::const_iterator it = allStates_s.find(name);
+        if (it != allStates_s.end())
+            return it->second;
+        else
+        {
+            COUT(1) << "Error: Could not find GameState '" << name << "'. Ignoring." << std::endl;
+            return 0;
+        }
+    }
+
+    void Game::setStateHierarchy(const std::string& str)
+    {
+        // Split string into pieces of the form whitespacesText
+        std::vector<std::pair<std::string, unsigned> > stateStrings;
+        size_t pos = 0;
+        size_t startPos = 0;
+        while (pos < str.size())
+        {
+            unsigned indentation = 0;
+            while(pos < str.size() && str[pos] == ' ')
+                ++indentation, ++pos;
+            startPos = pos;
+            while(pos < str.size() && str[pos] != ' ')
+                ++pos;
+            stateStrings.push_back(std::pair<std::string, unsigned>(
+                str.substr(startPos, pos - startPos), indentation));
+        }
+        unsigned int currentLevel = 0;
+        GameStateTreeNode* currentNode = 0;
+        for (std::vector<std::pair<std::string, unsigned> >::const_iterator it = stateStrings.begin(); it != stateStrings.end(); ++it)
+        {
+            std::string newStateName = it->first;
+            unsigned newLevel = it->second;
+            GameState* newState = this->getState(newStateName);
+            if (!newState)
+                ThrowException(GameState, std::string("GameState with name '") + newStateName + "' not found!");
+            if (newLevel == 0)
+            {
+                // root
+                if (this->rootStateNode_ != NULL)
+                    ThrowException(GameState, "No two root GameStates are allowed!");
+                GameStateTreeNode* newNode = new GameStateTreeNode;
+                newNode->state_ = newState;
+                newNode->parent_ = 0;
+                this->rootStateNode_ = newNode;
+                currentNode = this->rootStateNode_;
+            }
+            else if (currentNode)
+            {
+                GameStateTreeNode* newNode = new GameStateTreeNode;
+                newNode->state_ = newState;
+                if (newLevel < currentLevel)
+                {
+                    // Get down the hierarchy
+                    do
+                        currentNode = currentNode->parent_;
+                    while (newLevel < --currentLevel);
+                }
+                if (newLevel == currentLevel)
+                {
+                    // same level
+                    newNode->parent_ = currentNode->parent_;
+                    newNode->parent_->children_.push_back(newNode);
+                }
+                else if (newLevel == currentLevel + 1)
+                {
+                    // child
+                    newNode->parent_ = currentNode;
+                    currentNode->children_.push_back(newNode);
+                }
+                else
+                    ThrowException(GameState, "Indentation error while parsing the hierarchy.");
+                currentNode = newNode;
+                currentLevel = newLevel;
+            }
+            else
+            {
+                ThrowException(GameState, "No root GameState specified!");
+            }
+        }
+    }
+
+    /*** Internal ***/
+
+    void Game::loadState(GameState* state)
+    {
+        state->activate();
+        this->activeStates_.push_back(state);
+    }
+
+    void Game::unloadState(orxonox::GameState* state)
+    {
+        state->deactivate();
+        this->activeStates_.pop_back();
+    }
+
+    /*static*/ bool Game::addGameState(GameState* state)
+    {
+        std::map<std::string, GameState*>::const_iterator it = allStates_s.find(state->getName());
+        if (it == allStates_s.end())
+            allStates_s[state->getName()] = state;
+        else
+            ThrowException(GameState, "Cannot add two GameStates with the same name to 'Game'.");
+
+        // just a required dummy return value
+        return true;
+    }
 }
