/*
 * matrix-statetable.c
 *
 *
 * Copyright (c) Openmarket UK Ltd 2015
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
 */


#include "matrix-statetable.h"

#include "debug.h"

#include "matrix-event.h"
#include "matrix-json.h"


/**
 * create a new, empty, state table
 */
MatrixRoomStateEventTable *matrix_statetable_new()
{
    return g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
            (GDestroyNotify) g_hash_table_destroy);
}


void matrix_statetable_destroy(MatrixRoomStateEventTable *table)
{
    g_hash_table_destroy(table);
}


/**
 * look up a particular bit of state
 *
 * @returns null if this key ies not known
 */
MatrixRoomEvent *matrix_statetable_get_event(
        MatrixRoomStateEventTable *state_table, const gchar *event_type,
        const gchar *state_key)
{
    GHashTable *tmp;

    tmp = (GHashTable *) g_hash_table_lookup(state_table, event_type);
    if(tmp == NULL)
        return NULL;

    return (MatrixRoomEvent *)g_hash_table_lookup(tmp, state_key);
}


/**
 * Update the state table on a room
 */
void matrix_statetable_update(MatrixRoomStateEventTable *state_table,
        JsonObject *json_event_obj,
        MatrixStateUpdateCallback callback, gpointer user_data)
{
    const gchar *event_type, *state_key, *sender;
    JsonObject *json_content_obj;
    MatrixRoomEvent *event, *old_event;
    GHashTable *state_table_entry;

    event_type = matrix_json_object_get_string_member(
            json_event_obj, "type");
    state_key = matrix_json_object_get_string_member(
            json_event_obj, "state_key");
    sender = matrix_json_object_get_string_member(
            json_event_obj, "sender");
    json_content_obj = matrix_json_object_get_object_member(
            json_event_obj, "content");
    
    if (g_strcmp0(event_type, "m.typing") == 0) {
        // Create a fake key so we can keep track of typing state
        state_key = "typing";
        sender = "";
    }

    if(event_type == NULL || state_key == NULL || sender == NULL ||
            json_content_obj == NULL) {
        purple_debug_warning("matrixprpl", "event missing fields\n");
        return;
    }

    event = matrix_event_new(event_type, json_content_obj);
    event -> sender = g_strdup(sender);

    state_table_entry = g_hash_table_lookup(state_table, event_type);
    if(state_table_entry == NULL) {
        state_table_entry = g_hash_table_new_full(g_str_hash, g_str_equal,
                g_free, (GDestroyNotify)matrix_event_free);
        g_hash_table_insert(state_table, g_strdup(event_type),
                state_table_entry);
        old_event = NULL;
    } else {
        old_event = g_hash_table_lookup(state_table_entry,
                state_key);
    }

    if(callback) {
        callback(event_type, state_key, old_event, event, user_data);
    }

    g_hash_table_insert(state_table_entry, g_strdup(state_key), event);
}


/**
 * If the room has an official name, or an alias, return it
 *
 * @returns a string which should be freed
 */
gchar *matrix_statetable_get_room_alias(MatrixRoomStateEventTable *state_table)
{
    GHashTable *tmp;
    MatrixRoomEvent *event;
    const gchar *tmpname = NULL;

    /* start by looking for the official room name */
    event = matrix_statetable_get_event(state_table, "m.room.name", "");
    if(event != NULL) {
        tmpname = matrix_json_object_get_string_member(
                event->content, "name");
        if(tmpname != NULL && tmpname[0] != '\0') {
            return g_strdup(tmpname);
        }
    }

    /* look for a canonical alias */
    event = matrix_statetable_get_event(state_table, "m.room.canonical_alias",
            "");
    if(event != NULL) {
        tmpname = matrix_json_object_get_string_member(
                event->content, "alias");
        if(tmpname != NULL) {
            return g_strdup(tmpname);
        }
    }

    /* look for an alias */
    tmp = (GHashTable *) g_hash_table_lookup(state_table, "m.room.aliases");
    if(tmp != NULL) {
        GHashTableIter iter;
        gpointer key, value;

        g_hash_table_iter_init(&iter, tmp);
        while(g_hash_table_iter_next(&iter, &key, &value)) {
            MatrixRoomEvent *event = value;
            JsonArray *array = matrix_json_object_get_array_member(
                    event->content, "aliases");
            if(array != NULL && json_array_get_length(array) > 0) {
                tmpname = matrix_json_array_get_string_element(array, 0);
                if(tmpname != NULL) {
                    return g_strdup(tmpname);
                }
            }
        }
    }

    return NULL;
}
