bygfoot/src/json_interface.c

672 lines
25 KiB
C

#include <json-c/json.h>
#include <json-c/json_tokener.h>
#include <json-c/json_object.h>
#include "json_interface.h"
#include "json_serialize.h"
#include "user.h"
#include "league_struct.h"
#include "load_save.h"
#include "misc.h"
#include "team.h"
#include "option.h"
#include "start_end.h"
static int bygfoot_json_do_commands(Bygfoot *bygfoot, const json_object *commands);
static int bygfoot_json_do_add_user(Bygfoot *bygfoot, const json_object *args);
static struct json_object *bygfoot_json_call_load_bygfoot(Bygfoot *bygfoot, const json_object *args);
static struct json_object *bygfoot_json_call_save_bygfoot(Bygfoot *bygfoot, const json_object *args);
static struct json_object *bygfoot_json_call_dump_bygfoot(Bygfoot *bygfoot, const json_object *args);
static struct json_object *bygfoot_json_call_add_country(Bygfoot *bygfoot, const json_object *args);
static struct json_object *bygfoot_json_call_add_user(Bygfoot *bygfoot, const json_object *args);
static struct json_object *bygfoot_json_call_start_bygfoot(Bygfoot *bygfoot, const json_object *args);
static struct json_object *bygfoot_json_call_simulate_games(Bygfoot *bygfoot,
const json_object *args);
static struct json_object *bygfoot_json_call_get_tables(Bygfoot *bygfoot,
const json_object *args);
static struct json_object *bygfoot_json_call_get_players(Bygfoot *bygfoot,
const json_object *args);
static struct json_object *bygfoot_json_call_get_fixtures(Bygfoot *bygfoot,
const json_object *args);
static struct json_object *bygfoot_json_call_get_cups(Bygfoot *bygfoot,
const json_object *args);
static struct json_object *bygfoot_json_response_error(const char *command,
const char *error);
static json_object *
bygfoot_json_fixture_to_json(const Fixture *fixture);
static json_object * bygfoot_json_player_to_json(const Player *player);
static json_object *bygfoot_json_user_to_json(const User *user);
static json_object *bygfoot_json_table_to_json(const Table *table);
struct json_field {
const gchar *name;
enum json_type type;
};
static gboolean
bygfoot_json_validate_arg_types(const struct json_object *args,
const struct json_field *fields)
{
const struct json_field *field;
for (field = fields; field->name; field++ ) {
struct json_object *value;
if (!json_object_object_get_ex(args, field->name, &value))
continue;
if (!json_object_is_type(value, field->type))
return FALSE;
}
return TRUE;
}
int bygfoot_json_main(Bygfoot *bygfoot, const CommandLineArgs *cl_args)
{
gchar *contents;
GError *error;
struct json_object *json;
enum json_tokener_error json_error;
/* Disable option to skip rounds without user games, so the simulate_games
* command works correctly. */
opt_set_int("int_opt_skip", 0);
if (!g_file_get_contents(cl_args->json_filename, &contents, NULL, &error)) {
misc_print_error(&error, FALSE);
return 1;
}
json = json_tokener_parse_verbose(contents, &json_error);
if (!json) {
fprintf(stderr, "Failed to parse json %s:\n", cl_args->json_filename);
fprintf(stderr, "%s\n",
json_tokener_error_desc(json_error));
return 1;
}
/* Handle configuration options */
/* TODO: Get option from json */
//bygfoot_set_save_dir(bygfoot, NULL);
json_object_object_foreach(json, key, val) {
if (!strcmp("commands", key))
return bygfoot_json_do_commands(bygfoot, val);
}
fprintf(stderr, "commands key is not present");
return 1;
}
static int bygfoot_json_do_commands(Bygfoot *bygfoot, const json_object *commands)
{
size_t i, num_commands;
static const struct json_func {
const gchar *command;
json_object* (*func)(Bygfoot *, const json_object *);
} json_funcs[] = {
{ "load_bygfoot", bygfoot_json_call_load_bygfoot },
{ "save_bygfoot", bygfoot_json_call_save_bygfoot },
{ "dump_bygfoot", bygfoot_json_call_dump_bygfoot },
{ "add_country", bygfoot_json_call_add_country },
{ "add_user", bygfoot_json_call_add_user },
{ "start_bygfoot", bygfoot_json_call_start_bygfoot },
{ "simulate_games", bygfoot_json_call_simulate_games },
{ "get_tables", bygfoot_json_call_get_tables },
{ "get_players", bygfoot_json_call_get_players },
{ "get_fixtures", bygfoot_json_call_get_fixtures },
{ "cups", bygfoot_json_call_get_cups },
{ NULL, NULL}
};
if (!json_object_is_type(commands, json_type_array)) {
fprintf(stderr, "json commands should be in an array\n");
return 1;
}
num_commands = json_object_array_length(commands);
for (i = 0; i < num_commands; i++) {
const json_object *command = json_object_array_get_idx(commands, i);
struct json_object *response = NULL;
// TODO: CHECK COMMAND SIZE
json_object_object_foreach(command, key, val) {
const struct json_func *json_func;
for (json_func = json_funcs; json_func->command; json_func++) {
if (!strcmp(json_func->command, key)) {
response = json_func->func(bygfoot, val);
break;
}
}
if (!response) {
response = bygfoot_json_response_error("commands", "command not recognized");
}
fprintf(stderr, "%s\n", json_object_to_json_string_ext(response, JSON_C_TO_STRING_PRETTY));
json_object_put(response);
}
}
return 0;
}
static const gchar *
bygfoot_json_validate_bygfoot_id(const json_object *args, json_object **error)
{
const gchar *id;
/* Get the id field */
json_object *id_obj = json_object_object_get(args, "id");
if (id_obj) {
if(!json_object_is_type(id_obj, json_type_string)) {
*error = bygfoot_json_response_error("",
"field 'id' must be a string");
return NULL;
}
return json_object_get_string(id_obj);
}
*error = bygfoot_json_response_error("", "field 'id' is missing or NULL");
return NULL;
}
static struct json_object *
bygfoot_json_call_load_bygfoot(Bygfoot *bygfoot, const json_object *args)
{
const gchar *id = NULL;
struct json_object *filename_obj;
const gchar *filename;
static const struct json_field fields [] = {
{ "filename", json_type_string }
};
if (!bygfoot_json_validate_arg_types(args, fields))
return bygfoot_json_response_error("load_bygfoot",
"wrong type for argument");
if (!json_object_object_get_ex(args, "filename", &filename_obj))
return bygfoot_json_response_error("load_bygfoot",
"filename argument is required");
filename = json_object_get_string(filename_obj);
if (!g_file_test(filename, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR))
return bygfoot_json_response_error("load_bygfoot", "file not found");
load_save_load_game(bygfoot, filename, FALSE);
return json_object_new_object();
}
static struct json_object *
bygfoot_json_call_save_bygfoot(Bygfoot *bygfoot, const json_object *args)
{
const gchar *id = NULL;
struct json_object *filename_obj;
const gchar *filename;
static const struct json_field fields [] = {
{ "filename", json_type_string }
};
if (!bygfoot_json_validate_arg_types(args, fields))
return bygfoot_json_response_error("save_bygfoot",
"wrong type for argument");
if (!json_object_object_get_ex(args, "filename", &filename_obj))
return bygfoot_json_response_error("save_bygfoot",
"filename argument is required");
filename = json_object_get_string(filename_obj);
load_save_save_game(bygfoot, filename);
return json_object_new_object();
}
static json_object *
bygfoot_json_call_dump_bygfoot(Bygfoot *bygfoot, const json_object *args)
{
return bygfoot_json_serialize_bygfoot(bygfoot);
}
static json_object *
bygfoot_json_call_add_country(Bygfoot *bygfoot, const json_object *args)
{
gchar const *country_name = NULL;
static const struct json_field fields [] = {
{ "name", json_type_string },
{ NULL, json_type_null }
};
const struct json_field *field;
for (field = fields; field->name; field++ ) {
struct json_object *value = json_object_object_get(args, field->name);
if (!value)
continue;
if (!json_object_is_type(value, field->type))
continue;
if (!strcmp(field->name, "name"))
country_name = json_object_get_string(value);
}
if (!country_name)
return bygfoot_json_response_error("add_country", "field 'country' is required");
bygfoot_load_country(bygfoot, country_name);
return json_object_new_string("success");
}
static json_object *bygfoot_json_call_add_user(Bygfoot *bygfoot, const json_object *args)
{
const char *command = "add_user";
const char *username = NULL;
const char *country_name = NULL;
const char *team_name = NULL;
struct json_object *response;
Country *country;
Team *tm;
User *user;
json_object_object_foreach(args, key, val) {
if (!strcmp("username", key)) {
if (!json_object_is_type(val, json_type_string)) {
return bygfoot_json_response_error(command, "username must be of type string");
}
username = json_object_get_string(val);
}
if (!strcmp("country", key)) {
if (!json_object_is_type(val, json_type_string)) {
return bygfoot_json_response_error(command, "country must be of type string");
}
country_name = json_object_get_string(val);
}
if (!strcmp("team", key)) {
if (!json_object_is_type(val, json_type_string)) {
return bygfoot_json_response_error(command, "team must be of type string");
}
team_name = json_object_get_string(val);
}
}
if (!username) {
return bygfoot_json_response_error(command, "field 'username' is required");
}
if (!country_name) {
return bygfoot_json_response_error(command, "field 'country' is required");
}
if (!team_name) {
return bygfoot_json_response_error(command, "field 'team' is required");
}
country = bygfoot_load_country(bygfoot, country_name);
tm = team_of_sid(team_name, country);
user = bygfoot_add_user(bygfoot, username, tm);
response = json_object_new_object();
json_object_object_add(response, "success", bygfoot_json_user_to_json(user));
return response;
}
static json_object *bygfoot_json_call_start_bygfoot(Bygfoot *bygfoot,
const json_object *args)
{
unsigned i;
bygfoot_start_game(bygfoot);
/* FIXME: We should really be doing this when the user is added, but
* the user options get loaded during the bygfoot_start_bygfoot() call and w
* can't add options before that.
*/
for (i = 0; i < users->len; i++) {
/* We need to set this option to avoid activating the GUI.
* FIXME: More work is needed to separate the logic from the GUI */
option_set_int("int_opt_user_show_live_game", &usr(i).options, 0);
}
return json_object_new_string("success");
}
static void simulate_weeks(Bygfoot *bygfoot, gint weeks)
{
gint num_weeks = 0;
gint current_week = week;
while (num_weeks < weeks) {
do {
end_week_round(bygfoot);
} while (current_week == week);
current_week = week;
num_weeks++;
}
}
static struct json_object *bygfoot_json_call_simulate_games(Bygfoot *bygfoot,
const json_object *args)
{
int32_t rounds = 0;
int32_t weeks = 0;
int32_t seasons = 0;
unsigned i;
json_object_object_foreach(args, key, val) {
if (!strcmp("rounds", key)) {
rounds = json_object_get_int(val);
for (i = 0; i < rounds; i++) {
end_week_round(bygfoot);
}
} else if (!strcmp("weeks", key)) {
weeks = json_object_get_int(val);
simulate_weeks(bygfoot, weeks);
} else if (!strcmp("seasons", key)) {
gint num_seasons = 0;
gint start_week = week;
gint current_season = season;
seasons = json_object_get_int(val);
while (num_seasons < seasons) {
do {
end_week_round(bygfoot);
} while (current_season == season);
current_season = season;
num_seasons++;
}
simulate_weeks(bygfoot, start_week);
}
}
return json_object_new_string("success");
}
static json_object *
bygfoot_json_call_get_fixtures(Bygfoot *bygfoot, const json_object *args)
{
struct json_object *fixtures_obj = json_object_new_array();
struct json_object *response, *data;
int i;
for (i = 0; i < country.leagues->len; i++) {
const League *league = &g_array_index(country.leagues, League, i);
int j;
for (j = 0; j < league->fixtures->len; j++) {
const Fixture *fixture = &g_array_index(league->fixtures, Fixture, j);
json_object_array_add(fixtures_obj, bygfoot_json_fixture_to_json(fixture));
}
}
for (i = 0; i < country.cups->len; i++) {
const Cup *cup = &g_array_index(country.cups, Cup, i);
int j;
for (j = 0; j < cup->fixtures->len; j++) {
const Fixture *fixture = &g_array_index(cup->fixtures, Fixture, j);
json_object_array_add(fixtures_obj, bygfoot_json_fixture_to_json(fixture));
}
}
data = json_object_new_object();
response = json_object_new_object();
json_object_object_add(data, "fixtures", fixtures_obj);
json_object_object_add(response, "success", data);
return response;
}
static json_object *
bygfoot_json_call_get_tables(Bygfoot *bygfoot, const json_object *args)
{
gchar const *country_name = NULL;
static const struct json_field fields [] = {
{ NULL, json_type_null }
};
const struct json_field *field;
int i;
struct json_object *response, *data, *tables;
for (field = fields; field->name; field++ ) {
struct json_object *value = json_object_object_get(args, field->name);
if (!value)
continue;
if (!json_object_is_type(value, field->type))
continue;
}
tables = json_object_new_array();
//GArray *leagues, *cups;
for (i = 0; i < country.leagues->len; i++) {
const League *league = &g_array_index(country.leagues, League, i);
int j;
for (j = 0; j < league->tables->len; j++) {
const Table *table = &g_array_index(league->tables, Table, j);
json_object_array_add(tables, bygfoot_json_table_to_json(table));
}
}
response = json_object_new_object();
data = json_object_new_object();
json_object_object_add(data, "tables", tables);
json_object_object_add(response, "success", data);
return response;
}
static json_object *
bygfoot_json_call_get_players(Bygfoot *bygfoot, const json_object *args)
{
struct json_object *players_obj = json_object_new_array();
struct json_object *response, *data;
int i;
for (i = 0; i < country.leagues->len; i++) {
const League *league = &g_array_index(country.leagues, League, i);
int j;
for (j = 0; j < league->teams->len; j++) {
const Team *team = &g_array_index(league->teams, Team, j);
int k;
for (k = 0; k < team->players->len; k++) {
const Player *player = &g_array_index(team->players, Player, k);
json_object_array_add(players_obj, bygfoot_json_player_to_json(player));
}
}
}
response = json_object_new_object();
data = json_object_new_object();
json_object_object_add(data, "players", players_obj);
json_object_object_add(response, "success", data);
return response;
}
static json_object *
bygfoot_json_call_get_cups(Bygfoot *bygfoot, const json_object *args)
{
struct json_object *cups_obj = json_object_new_array_ext(country.cups->len);
int i;
for (i = 0; i < country.cups->len; i++) {
const Cup *cup = &g_array_index(country.cups, Cup, i);
json_object_array_add(cups_obj, bygfoot_json_serialize_cup(cup));
}
return cups_obj;
}
static json_object *
bygfoot_json_live_game_stats_to_json(const LiveGameStats *stats, gint team_index)
{
}
static json_object *
bygfoot_json_fixture_stats_to_json(const Fixture *fixture, gint team_index)
{
struct json_object *team_obj = json_object_new_object();
struct json_object *stats_obj = json_object_new_object();
static const struct key_index {
const gchar *key;
gint index;
} result_fields[] = {
{ "goals_regulation", 0 },
{ "goals_extra_time", 1 },
{ "goals_penalty_shootout", 2 },
{ NULL, 0 }
};
static const struct key_index live_stats_fields[] = {
{ "goals_regular", LIVE_GAME_STAT_VALUE_GOALS_REGULAR },
{ "shots", LIVE_GAME_STAT_VALUE_SHOTS },
{ "shot_percentage", LIVE_GAME_STAT_VALUE_SHOT_PERCENTAGE },
{ "possession", LIVE_GAME_STAT_VALUE_POSSESSION },
{ "penalties", LIVE_GAME_STAT_VALUE_PENALTIES },
{ "fouls", LIVE_GAME_STAT_VALUE_FOULS },
{ "cards", LIVE_GAME_STAT_VALUE_CARDS },
{ "reds", LIVE_GAME_STAT_VALUE_REDS } ,
{ "injuries", LIVE_GAME_STAT_VALUE_INJURIES },
{ NULL, LIVE_GAME_STAT_VALUE_END }
};
const struct key_index *iter;
if (!fixture->live_game)
return stats_obj;
for (iter = result_fields; iter->key; iter++) {
gint value = fixture->result[team_index][iter->index];
json_object_object_add(stats_obj, iter->key, json_object_new_int64(value));
}
/* Note it seems like fixture->live_game does not persist when the game is
* over, so that is why we are not including it in the json. */
return stats_obj;
}
static json_object *
bygfoot_json_fixture_to_json(const Fixture *fixture)
{
struct json_object *fixture_obj = json_object_new_object();
struct json_object *home_team_obj = json_object_new_object();
struct json_object *away_team_obj = json_object_new_object();
json_object_object_add(fixture_obj, "id", json_object_new_int64(fixture->id));
json_object_object_add(fixture_obj, "league_id", json_object_new_int64(fixture->clid));
json_object_object_add(fixture_obj, "round", json_object_new_int64(fixture->round));
json_object_object_add(fixture_obj, "replay_number", json_object_new_int64(fixture->replay_number));
json_object_object_add(fixture_obj, "week", json_object_new_int64(fixture->week_number));
json_object_object_add(fixture_obj, "round", json_object_new_int64(fixture->week_round_number));
json_object_object_add(home_team_obj, "id", json_object_new_int64(fixture->team_ids[0]));
json_object_object_add(home_team_obj, "stats",
bygfoot_json_fixture_stats_to_json(fixture, 0));
json_object_object_add(fixture_obj, "home_team", home_team_obj);
json_object_object_add(away_team_obj, "id", json_object_new_int64(fixture->team_ids[1]));
json_object_object_add(away_team_obj, "stats",
bygfoot_json_fixture_stats_to_json(fixture, 1));
json_object_object_add(fixture_obj, "away_team", away_team_obj);
return fixture_obj;
}
static json_object *
bygfoot_json_player_games_goals_to_json(const GArray *stats)
{
int i;
struct json_object *stats_obj = json_object_new_array_ext(stats->len);
for (i = 0; i < stats->len; i++) {
const PlayerGamesGoals *league_stats = &g_array_index(stats,
PlayerGamesGoals, i);
struct json_object *league_stats_obj = json_object_new_object();
json_object_object_add(league_stats_obj, "league_id",
json_object_new_int64(league_stats->clid));
json_object_object_add(league_stats_obj, "games",
json_object_new_int64(league_stats->games));
json_object_object_add(league_stats_obj, "goals",
json_object_new_int64(league_stats->goals));
json_object_object_add(league_stats_obj, "shots",
json_object_new_int64(league_stats->shots));
json_object_array_add(stats_obj, league_stats_obj);
}
return stats_obj;
}
static json_object *
bygfoot_json_player_to_json(const Player *player)
{
struct json_object *player_obj = json_object_new_object();
json_object_object_add(player_obj, "name", json_object_new_string(player->name));
json_object_object_add(player_obj, "season_stats",
bygfoot_json_player_games_goals_to_json(player->games_goals));
return player_obj;
}
static json_object *
bygfoot_json_team_to_json(const Team *team)
{
struct json_object *team_obj = json_object_new_object();
json_object_object_add(team_obj, "name",
json_object_new_string(team->name));
return team_obj;
}
static json_object *
bygfoot_json_table_element_to_json(const TableElement *element)
{
struct json_object *element_obj = json_object_new_object();
json_object_object_add(element_obj, "team",
bygfoot_json_team_to_json(element->team));
json_object_object_add(element_obj, "old_rank",
json_object_new_int64(element->old_rank));
json_object_object_add(element_obj, "played",
json_object_new_int64(element->values[TABLE_PLAYED]));
json_object_object_add(element_obj, "won",
json_object_new_int64(element->values[TABLE_WON]));
json_object_object_add(element_obj, "draw",
json_object_new_int64(element->values[TABLE_DRAW]));
json_object_object_add(element_obj, "lost",
json_object_new_int64(element->values[TABLE_LOST]));
json_object_object_add(element_obj, "gf",
json_object_new_int64(element->values[TABLE_GF]));
json_object_object_add(element_obj, "ga",
json_object_new_int64(element->values[TABLE_GA]));
json_object_object_add(element_obj, "gd",
json_object_new_int64(element->values[TABLE_GD]));
json_object_object_add(element_obj, "pts",
json_object_new_int64(element->values[TABLE_PTS]));
return element_obj;
}
static json_object *
bygfoot_json_table_to_json(const Table *table)
{
struct json_object *table_obj = json_object_new_object();
struct json_object *elements_obj = json_object_new_array_ext(table->elements->len);
int i;
json_object_object_add(table_obj, "name", json_object_new_string(table->name));
json_object_object_add(table_obj, "id", json_object_new_int64(table->clid));
json_object_object_add(table_obj, "round", json_object_new_int64(table->round));
for (i = 0; i < table->elements->len; i++) {
const TableElement *element = &g_array_index(table->elements,
TableElement, i);
json_object_array_add(elements_obj,
bygfoot_json_table_element_to_json(element));
}
json_object_object_add(table_obj, "elements", elements_obj);
return table_obj;
}
static json_object *bygfoot_json_user_to_json(const User *user)
{
struct json_object *json = json_object_new_object();
struct json_object *user_obj = json_object_new_object();
json_object_object_add(user_obj, "name", json_object_new_string(user->name));
json_object_object_add(json, "user", user_obj);
return json;
}
static struct json_object *bygfoot_json_response_error(const char *command,
const char *error)
{
struct json_object *json = json_object_new_object();
json_object_object_add(json, "message", json_object_new_string(error));
return json;
}
static void bygfoot_json_error_to_console(const char *command, const char *error)
{
struct json_object *json = bygfoot_json_response_error(command, error);
fprintf(stderr, "%s\n", json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
json_object_put(json);
}