#include <fstream>

#include <sys/time.h>
#include <string.h>

extern "C" {
#include <base/system.h>
#include <engine/e_config.h>
#include <engine/e_if_other.h>
#include <engine/e_if_server.h>
#include <engine/e_network.h>
}
#include <game/server/gamecontext.hpp>

#include "statistics_types.hpp"

extern "C" NETSERVER* net;

using namespace statistics;

static std::fstream file;
enum states {
 off,
 ready,
 on
};

static states state = off;
std::string filename;

template <typename T> std::ostream& operator%(std::ostream& f, T x) {
 return f.write((const char*)&x, sizeof(x));
};

template <> std::ostream& operator%(std::ostream& f, const char* x) {
 return f.write(x, strlen(x)+1);
};

template <> std::ostream& operator%(std::ostream& f, char* x) {
 return f.write(x, strlen(x)+1);
};

void statistics_join(int cid);

void statistics_start_round() {
 if (state != off
     && (!config.sv_statistics 
         || !game.controller->is_instagib()
         || filename != config.sv_statistics_file)) {
  file.close();
  state = off;
 };

 if (state == off && config.sv_statistics && game.controller->is_instagib()) {
  filename = config.sv_statistics_file;
  file.open(
    config.sv_statistics_file, std::ios::out | std::ios::app | std::ios::binary
  );
  file.exceptions();
  state = ready;
 };

 if (state == off) return;

 timeval t;
 gettimeofday(&t, NULL);
 file % 0 % START % game_tick() % t.tv_sec % config.sv_map;

 state = on;

 for (int i = 0; i < MAX_CLIENTS; ++i)
  if (game.players[i]) statistics_join(i);
};

void statistics_end_round() {
 if (state != on) return;
 file % game_tick() % END;
 file.flush();
 state = ready;
};

void statistics_join(int cid) {
 if (state != on) return;
 PLAYER* p = game.players[cid];
 NETADDR addr;
 netserver_client_addr(net, cid, &addr);
 file % game_tick() % JOIN
  % (char)cid
  % (char)p->team
  % server_clientname(cid)
  % p->skin_name
  % (addr.type == NETTYPE_IPV4);
 file.write((const char*)addr.ip, sizeof(addr.ip));
}

void statistics_leave(int cid) {
 if (state != on) return;
 file % game_tick() % LEAVE % (char)cid;
};

void statistics_switch(int cid) {
 if (state != on) return;
 file % game_tick() % SWITCH % (char)cid % (char)game.players[cid]->team;
};

void statistics_shoot(int cid) {
 if (state != on) return;
 file % game_tick() % SHOOT % (char)cid;
};

void statistics_kill(int killer, int victim) {
 if (state != on) return;
 file % game_tick() % KILL % (char)killer % (char)victim;
};

void statistics_change_name(int cid) {
 if (state != on) return;
 file % game_tick() % CHANGE_NAME % (char)cid % server_clientname(cid);
};

void statistics_change_skin(int cid) {
 if (state != on) return;
 file % game_tick() % CHANGE_SKIN 
  % (char)cid % game.players[cid]->skin_name;
};

void statistics_flush() {
 if (state == off) return;
 file.flush();
};

void statistics_fini() {
 if (state == off) return;
 file.close();
};
