/*!
  \example chat_server.cpp
  \brief チャットサンプル (サーバ)

  \author Satofumi KAMIMURA

  $Id: chat_server.cpp 1474 2009-11-01 05:33:08Z satofumi $
*/

#include "TcpipAccepter.h"
#include "TcpipSocket.h"
#include "PacketBuffer.h"
#include "PacketUtils.h"
#include "port.h"
#include "delay.h"
#include <iostream>
#include <cstdlib>

using namespace qrk;
using namespace std;


namespace
{
  ClientId client_id_ = 0;


  bool addClient(Clients& clients, ClientGroup& all_clients,
                 TcpipAccepter& server)
  {
    TcpipSocket* client = server.accept(0);
    if (! client) {
      return false;
    }

    // 新規追加
    ++client_id_;
    clients[client_id_] = client;
    all_clients.insert(client_id_);
    cout << "new client [id " << client_id_ << "]" << endl;

    return true;
  }


  void recvPackets(PacketBuffer& buffer, Clients& clients)
  {
    PacketControl::receive(buffer, clients);
  }


  void packetHandler(PacketBuffer& send_buffer, PacketBuffer& recv_buffer,
                     ClientGroup& all_clients)
  {
    // 各クライアントから受信したパケットを、全てのクライアントに送信する
    for (ClientGroup::iterator it = all_clients.begin();
         it != all_clients.end(); ++it) {
      const ClientId& client_id = *it;
      while (! recv_buffer.empty(client_id)) {
        Packet packet = recv_buffer.pop(client_id);
        if (! packetType(packet).compare("CH")) {

          // !!! 送信先の情報を利用すべき

          send_buffer.push(packet, all_clients);
        }
      }
    }
  }


  void sendPackets(Clients& clients, PacketBuffer& buffer)
  {
    PacketControl::send(buffer, clients);
  }


  void eraseDisconnected(Clients& clients, ClientGroup& all_clients)
  {
    for (Clients::iterator it = clients.begin(); it != clients.end();) {
      Connection* client = it->second;

      if (! client->isConnected()) {
        // 接続されていない場合、グループから ID を削除
        const ClientId& client_id = it->first;
        all_clients.erase(client_id);
        cout << "disconnected [id " << client_id << "]" << endl;

        delete client;
        clients.erase(it++);

      } else {
        ++it;
      }
    }
  }
}


int main(int argc, char *argv[])
{
  TcpipAccepter server;
  if (! server.activate(Port)) {
    cout << "TcpipAccepter::activate(): " << server.what() << endl;
    exit(1);
  }
  cout << "server activated [port " << Port << "]" << endl;

  Clients clients;
  PacketBuffer recv_buffer;
  PacketBuffer send_buffer;
  ClientGroup all_clients;

  bool not_connected = true;
  while (not_connected || (! clients.empty())) {
    // 接続してきたクライアントを登録
    if (addClient(clients, all_clients, server)) {
      not_connected = false;
    }

    // パケットの受信
    recvPackets(recv_buffer, clients);

    // 受信したチャット用パケットを全てのクライアントに送信
    packetHandler(send_buffer, recv_buffer, all_clients);
    sendPackets(clients, send_buffer);

    // 切断したクライアントを削除
    eraseDisconnected(clients, all_clients);

    delay(10);
  }

  return 0;
}
