/*!
  \file
  \brief Lua スクリプトの実行用 (サーバ)

  \author Satofumi KAMIMURA

  $Id: server.cpp 1140 2009-07-13 21:41:41Z satofumi $

  \todo 接続されたときにスクリプトを起動するように変更する
*/

#include "port.h"
#include "luabindSyncGui_master.h"
#include "MasterLayer.h"
#include "Packet.h"
#include "TcpipSocket.h"
#include "TcpipAccepter.h"
#include "luabindInit.h"
#include "luabindCommon.h"
#include "luabindGeometry.h"
#include "luabindGui.h"
#include "LuaHandler.h"
#include <luabind/luabind.hpp>
#include <iostream>

using namespace qrk;
using namespace luabind;
using namespace std;


namespace
{
  void script_enter(lua_State* L, MasterLayer* master_layer)
  {
    try {
      call_function<void>(L, "script_enter", master_layer);

    } catch (const error &e) {
      static_cast<void>(e);
      cout << "script_enter(): " << lua_tostring(L, -1) << endl;
    }
  }


  void script_execute(lua_State* L, MasterLayer* master_layer)
  {
    try {
      call_function<void>(L, "script_execute", master_layer);

    } catch (const error &e) {
      static_cast<void>(e);
      cout << "script_execute(): " << lua_tostring(L, -1) << endl;
    }
  }


  void script_exit(lua_State* L, MasterLayer* master_layer)
  {
    try {
      call_function<void>(L, "script_exit", master_layer);

    } catch (const error &e) {
      static_cast<void>(e);
      cout << "script_exit(): " << lua_tostring(L, -1) << endl;
    }
  }


  void runServer(TcpipAccepter& server, lua_State* L)
  {
    ClientId client_id = 0;
    Clients clients;
    map<ClientId, MasterLayer*> client_layer;

    bool not_connected = true;
    bool quit = false;
    while (! quit) {
      Connection* client = server.accept();
      if (client) {
        // 接続してきたクライアントを追加
        ++client_id;
        clients[client_id] = client;
        MasterLayer* layer = new MasterLayer();
        script_enter(L, layer);
        client_layer[client_id] = layer;
        not_connected = false;
      }

      for (Clients::iterator it = clients.begin(); it != clients.end();) {
        ClientId client_id = it->first;
        Connection* client = it->second;

        MasterLayer* layer = client_layer[client_id];

        // クライアントの切断確認
        if (! client->isConnected()) {
          script_exit(L, layer);

          delete layer;
          client_layer.erase(client_id);
          delete client;
          clients.erase(it++);
        }

        // スクリプトの実行
        script_execute(L, layer);

        ++it;
      }

      // 全てのクライアントが切断したら終了
      if ((not_connected) && clients.empty()) {
        quit = true;
      }
    }
  }
}


int main(int argc, char *argv[])
{
  if (argc <= 1) {
    cout << "usage: %s <lua script>" << endl;
    exit(1);
  }
  const char* script_file = argv[1];

  lua_State* L = luabindInit();
  luabindCommon(L);
  luabindGeometry(L);
  luabindGui(L);
  luabindSyncGui_master(L);
  LuaHandler::dofile(L, script_file);

  TcpipAccepter server;
  if (! server.activate(Port)) {
    cout << "TcpipServer::activate: " << server.what() << endl;
  }

  runServer(server, L);

  return 0;
}
