/* Generated by j2s */

#include <Schema/Filter.h>

#include <Memory.h>
#include <Json.h>
#include <Str.h>

int
FilterRoomFromJson(HashMap *json, FilterRoom *out, char **errp)
{
    JsonValue *val;
    int enumParseRes;

    (void) enumParseRes;

    if (!json | !out)
    {
        *errp = "Invalid pointers passed to FilterRoomFromJson()";
        return 0;
    }

    val = HashMapGet(json, "not_rooms");
    if (val)
    {
        if (JsonValueType(val) != JSON_ARRAY)
        {
            *errp = "FilterRoom.not_rooms must be of type [string].";
            return 0;
        }

        out->not_rooms = ArrayCreate();
        if (!out->not_rooms)
        {
            *errp = "Failed to allocate memory for FilterRoom.not_rooms.";
            return 0;
        }
        else
        {
            Array *arr = JsonValueAsArray(val);
            size_t i;

            for (i = 0; i <ArraySize(arr); i++)
            {
                JsonValue *v = ArrayGet(arr, i);
                if (JsonValueType(v) != JSON_STRING)
                {
                    *errp = "FilterRoom.not_rooms[] contains an invalid value.";
                    return 0;
                }
                ArrayAdd(out->not_rooms, StrDuplicate(JsonValueAsString(v)));
            }
        }
    }

    val = HashMapGet(json, "state");
    if (val)
    {
        if (JsonValueType(val) != JSON_OBJECT)
        {
            *errp = "FilterRoom.state must be of type FilterRoomEvent.";
            return 0;
        }

        if (!FilterRoomEventFromJson(JsonValueAsObject(val), &out->state, errp))
        {
            return 0;
        }
    }

    val = HashMapGet(json, "include_leave");
    if (val)
    {
        if (JsonValueType(val) != JSON_BOOLEAN)
        {
            *errp = "FilterRoom.include_leave must be of type boolean.";
            return 0;
        }

        out->include_leave = JsonValueAsBoolean(val);
    }

    val = HashMapGet(json, "timeline");
    if (val)
    {
        if (JsonValueType(val) != JSON_OBJECT)
        {
            *errp = "FilterRoom.timeline must be of type FilterRoomEvent.";
            return 0;
        }

        if (!FilterRoomEventFromJson(JsonValueAsObject(val), &out->timeline, errp))
        {
            return 0;
        }
    }

    val = HashMapGet(json, "account_data");
    if (val)
    {
        if (JsonValueType(val) != JSON_OBJECT)
        {
            *errp = "FilterRoom.account_data must be of type FilterRoomEvent.";
            return 0;
        }

        if (!FilterRoomEventFromJson(JsonValueAsObject(val), &out->account_data, errp))
        {
            return 0;
        }
    }

    val = HashMapGet(json, "rooms");
    if (val)
    {
        if (JsonValueType(val) != JSON_ARRAY)
        {
            *errp = "FilterRoom.rooms must be of type [string].";
            return 0;
        }

        out->rooms = ArrayCreate();
        if (!out->rooms)
        {
            *errp = "Failed to allocate memory for FilterRoom.rooms.";
            return 0;
        }
        else
        {
            Array *arr = JsonValueAsArray(val);
            size_t i;

            for (i = 0; i <ArraySize(arr); i++)
            {
                JsonValue *v = ArrayGet(arr, i);
                if (JsonValueType(v) != JSON_STRING)
                {
                    *errp = "FilterRoom.rooms[] contains an invalid value.";
                    return 0;
                }
                ArrayAdd(out->rooms, StrDuplicate(JsonValueAsString(v)));
            }
        }
    }

    val = HashMapGet(json, "ephemeral");
    if (val)
    {
        if (JsonValueType(val) != JSON_OBJECT)
        {
            *errp = "FilterRoom.ephemeral must be of type FilterRoomEvent.";
            return 0;
        }

        if (!FilterRoomEventFromJson(JsonValueAsObject(val), &out->ephemeral, errp))
        {
            return 0;
        }
    }

    return 1;
}

HashMap *
FilterRoomToJson(FilterRoom *val)
{
    HashMap *json;

    if (!val)
    {
        return NULL;
    }

    json = HashMapCreate();
    if (!json)
    {
        return NULL;
    }

    if (val->not_rooms)
    {
        size_t i;
        Array *jsonArr = ArrayCreate();
        if (!jsonArr)
        {
            JsonFree(json);
            return NULL;
        }
        for (i = 0; i < ArraySize(val->not_rooms); i++)
        {
            ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->not_rooms, i)));
        }
        HashMapSet(json, "not_rooms", JsonValueArray(jsonArr));
    }
    HashMapSet(json, "state", JsonValueObject(FilterRoomEventToJson(&val->state)));
    HashMapSet(json, "include_leave", JsonValueBoolean(val->include_leave));
    HashMapSet(json, "timeline", JsonValueObject(FilterRoomEventToJson(&val->timeline)));
    HashMapSet(json, "account_data", JsonValueObject(FilterRoomEventToJson(&val->account_data)));
    if (val->rooms)
    {
        size_t i;
        Array *jsonArr = ArrayCreate();
        if (!jsonArr)
        {
            JsonFree(json);
            return NULL;
        }
        for (i = 0; i < ArraySize(val->rooms); i++)
        {
            ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->rooms, i)));
        }
        HashMapSet(json, "rooms", JsonValueArray(jsonArr));
    }
    HashMapSet(json, "ephemeral", JsonValueObject(FilterRoomEventToJson(&val->ephemeral)));
    return json;
}

void
FilterRoomFree(FilterRoom *val)
{
    if (!val)
    {
        return;
    }

    if (val->not_rooms)
    {
        size_t i;
        for (i = 0; i < ArraySize(val->not_rooms); i++)
        {
            Free(ArrayGet(val->not_rooms, i));
        }
        ArrayFree(val->not_rooms);
    }
    FilterRoomEventFree(&val->state);
    FilterRoomEventFree(&val->timeline);
    FilterRoomEventFree(&val->account_data);
    if (val->rooms)
    {
        size_t i;
        for (i = 0; i < ArraySize(val->rooms); i++)
        {
            Free(ArrayGet(val->rooms, i));
        }
        ArrayFree(val->rooms);
    }
    FilterRoomEventFree(&val->ephemeral);
}

int
FilterEventFormatFromStr(char *str)
{
    if (StrEquals(str, "federation"))
    {
        return FILTER_FORMAT_FEDERATION;
    }
    else if (StrEquals(str, "client"))
    {
        return FILTER_FORMANT_CLIENT;
    }
    else
    {
        return -1;
    }
}

char *
FilterEventFormatToStr(FilterEventFormat val)
{
    switch (val)
    {
        case FILTER_FORMAT_FEDERATION:
            return "federation";
        case FILTER_FORMANT_CLIENT:
            return "client";
        default:
            return NULL;
    }
}

int
FilterEventFromJson(HashMap *json, FilterEvent *out, char **errp)
{
    JsonValue *val;
    int enumParseRes;

    (void) enumParseRes;

    if (!json | !out)
    {
        *errp = "Invalid pointers passed to FilterEventFromJson()";
        return 0;
    }

    val = HashMapGet(json, "not_senders");
    if (val)
    {
        if (JsonValueType(val) != JSON_ARRAY)
        {
            *errp = "FilterEvent.not_senders must be of type [string].";
            return 0;
        }

        out->not_senders = ArrayCreate();
        if (!out->not_senders)
        {
            *errp = "Failed to allocate memory for FilterEvent.not_senders.";
            return 0;
        }
        else
        {
            Array *arr = JsonValueAsArray(val);
            size_t i;

            for (i = 0; i <ArraySize(arr); i++)
            {
                JsonValue *v = ArrayGet(arr, i);
                if (JsonValueType(v) != JSON_STRING)
                {
                    *errp = "FilterEvent.not_senders[] contains an invalid value.";
                    return 0;
                }
                ArrayAdd(out->not_senders, StrDuplicate(JsonValueAsString(v)));
            }
        }
    }

    val = HashMapGet(json, "limit");
    if (val)
    {
        if (JsonValueType(val) != JSON_INTEGER)
        {
            *errp = "FilterEvent.limit must be of type integer.";
            return 0;
        }

        out->limit = JsonValueAsInteger(val);
    }

    val = HashMapGet(json, "senders");
    if (val)
    {
        if (JsonValueType(val) != JSON_ARRAY)
        {
            *errp = "FilterEvent.senders must be of type [string].";
            return 0;
        }

        out->senders = ArrayCreate();
        if (!out->senders)
        {
            *errp = "Failed to allocate memory for FilterEvent.senders.";
            return 0;
        }
        else
        {
            Array *arr = JsonValueAsArray(val);
            size_t i;

            for (i = 0; i <ArraySize(arr); i++)
            {
                JsonValue *v = ArrayGet(arr, i);
                if (JsonValueType(v) != JSON_STRING)
                {
                    *errp = "FilterEvent.senders[] contains an invalid value.";
                    return 0;
                }
                ArrayAdd(out->senders, StrDuplicate(JsonValueAsString(v)));
            }
        }
    }

    val = HashMapGet(json, "types");
    if (val)
    {
        if (JsonValueType(val) != JSON_ARRAY)
        {
            *errp = "FilterEvent.types must be of type [string].";
            return 0;
        }

        out->types = ArrayCreate();
        if (!out->types)
        {
            *errp = "Failed to allocate memory for FilterEvent.types.";
            return 0;
        }
        else
        {
            Array *arr = JsonValueAsArray(val);
            size_t i;

            for (i = 0; i <ArraySize(arr); i++)
            {
                JsonValue *v = ArrayGet(arr, i);
                if (JsonValueType(v) != JSON_STRING)
                {
                    *errp = "FilterEvent.types[] contains an invalid value.";
                    return 0;
                }
                ArrayAdd(out->types, StrDuplicate(JsonValueAsString(v)));
            }
        }
    }

    val = HashMapGet(json, "not_types");
    if (val)
    {
        if (JsonValueType(val) != JSON_ARRAY)
        {
            *errp = "FilterEvent.not_types must be of type [string].";
            return 0;
        }

        out->not_types = ArrayCreate();
        if (!out->not_types)
        {
            *errp = "Failed to allocate memory for FilterEvent.not_types.";
            return 0;
        }
        else
        {
            Array *arr = JsonValueAsArray(val);
            size_t i;

            for (i = 0; i <ArraySize(arr); i++)
            {
                JsonValue *v = ArrayGet(arr, i);
                if (JsonValueType(v) != JSON_STRING)
                {
                    *errp = "FilterEvent.not_types[] contains an invalid value.";
                    return 0;
                }
                ArrayAdd(out->not_types, StrDuplicate(JsonValueAsString(v)));
            }
        }
    }

    return 1;
}

HashMap *
FilterEventToJson(FilterEvent *val)
{
    HashMap *json;

    if (!val)
    {
        return NULL;
    }

    json = HashMapCreate();
    if (!json)
    {
        return NULL;
    }

    if (val->not_senders)
    {
        size_t i;
        Array *jsonArr = ArrayCreate();
        if (!jsonArr)
        {
            JsonFree(json);
            return NULL;
        }
        for (i = 0; i < ArraySize(val->not_senders); i++)
        {
            ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->not_senders, i)));
        }
        HashMapSet(json, "not_senders", JsonValueArray(jsonArr));
    }
    HashMapSet(json, "limit", JsonValueInteger(val->limit));
    if (val->senders)
    {
        size_t i;
        Array *jsonArr = ArrayCreate();
        if (!jsonArr)
        {
            JsonFree(json);
            return NULL;
        }
        for (i = 0; i < ArraySize(val->senders); i++)
        {
            ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->senders, i)));
        }
        HashMapSet(json, "senders", JsonValueArray(jsonArr));
    }
    if (val->types)
    {
        size_t i;
        Array *jsonArr = ArrayCreate();
        if (!jsonArr)
        {
            JsonFree(json);
            return NULL;
        }
        for (i = 0; i < ArraySize(val->types); i++)
        {
            ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->types, i)));
        }
        HashMapSet(json, "types", JsonValueArray(jsonArr));
    }
    if (val->not_types)
    {
        size_t i;
        Array *jsonArr = ArrayCreate();
        if (!jsonArr)
        {
            JsonFree(json);
            return NULL;
        }
        for (i = 0; i < ArraySize(val->not_types); i++)
        {
            ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->not_types, i)));
        }
        HashMapSet(json, "not_types", JsonValueArray(jsonArr));
    }
    return json;
}

void
FilterEventFree(FilterEvent *val)
{
    if (!val)
    {
        return;
    }

    if (val->not_senders)
    {
        size_t i;
        for (i = 0; i < ArraySize(val->not_senders); i++)
        {
            Free(ArrayGet(val->not_senders, i));
        }
        ArrayFree(val->not_senders);
    }
    if (val->senders)
    {
        size_t i;
        for (i = 0; i < ArraySize(val->senders); i++)
        {
            Free(ArrayGet(val->senders, i));
        }
        ArrayFree(val->senders);
    }
    if (val->types)
    {
        size_t i;
        for (i = 0; i < ArraySize(val->types); i++)
        {
            Free(ArrayGet(val->types, i));
        }
        ArrayFree(val->types);
    }
    if (val->not_types)
    {
        size_t i;
        for (i = 0; i < ArraySize(val->not_types); i++)
        {
            Free(ArrayGet(val->not_types, i));
        }
        ArrayFree(val->not_types);
    }
}

int
FilterFromJson(HashMap *json, Filter *out, char **errp)
{
    JsonValue *val;
    int enumParseRes;

    (void) enumParseRes;

    if (!json | !out)
    {
        *errp = "Invalid pointers passed to FilterFromJson()";
        return 0;
    }

    val = HashMapGet(json, "event_format");
    if (val)
    {
        if (JsonValueType(val) != JSON_STRING)
        {
            *errp = "Filter.event_format must be of type FilterEventFormat.";
            return 0;
        }

        enumParseRes = FilterEventFormatFromStr(JsonValueAsString(val));
        if (enumParseRes == -1)
        {
            *errp = "Invalid value for Filter.event_format.";
            return 0;
        }
        out->event_format = enumParseRes;
    }

    val = HashMapGet(json, "presence");
    if (val)
    {
        if (JsonValueType(val) != JSON_OBJECT)
        {
            *errp = "Filter.presence must be of type FilterEvent.";
            return 0;
        }

        if (!FilterEventFromJson(JsonValueAsObject(val), &out->presence, errp))
        {
            return 0;
        }
    }

    val = HashMapGet(json, "account_data");
    if (val)
    {
        if (JsonValueType(val) != JSON_OBJECT)
        {
            *errp = "Filter.account_data must be of type FilterEvent.";
            return 0;
        }

        if (!FilterEventFromJson(JsonValueAsObject(val), &out->account_data, errp))
        {
            return 0;
        }
    }

    val = HashMapGet(json, "room");
    if (val)
    {
        if (JsonValueType(val) != JSON_OBJECT)
        {
            *errp = "Filter.room must be of type FilterRoom.";
            return 0;
        }

        if (!FilterRoomFromJson(JsonValueAsObject(val), &out->room, errp))
        {
            return 0;
        }
    }

    val = HashMapGet(json, "event_fields");
    if (val)
    {
        if (JsonValueType(val) != JSON_ARRAY)
        {
            *errp = "Filter.event_fields must be of type [string].";
            return 0;
        }

        out->event_fields = ArrayCreate();
        if (!out->event_fields)
        {
            *errp = "Failed to allocate memory for Filter.event_fields.";
            return 0;
        }
        else
        {
            Array *arr = JsonValueAsArray(val);
            size_t i;

            for (i = 0; i <ArraySize(arr); i++)
            {
                JsonValue *v = ArrayGet(arr, i);
                if (JsonValueType(v) != JSON_STRING)
                {
                    *errp = "Filter.event_fields[] contains an invalid value.";
                    return 0;
                }
                ArrayAdd(out->event_fields, StrDuplicate(JsonValueAsString(v)));
            }
        }
    }

    return 1;
}

HashMap *
FilterToJson(Filter *val)
{
    HashMap *json;

    if (!val)
    {
        return NULL;
    }

    json = HashMapCreate();
    if (!json)
    {
        return NULL;
    }

    HashMapSet(json, "event_format", JsonValueString(FilterEventFormatToStr(val->event_format)));
    HashMapSet(json, "presence", JsonValueObject(FilterEventToJson(&val->presence)));
    HashMapSet(json, "account_data", JsonValueObject(FilterEventToJson(&val->account_data)));
    HashMapSet(json, "room", JsonValueObject(FilterRoomToJson(&val->room)));
    if (val->event_fields)
    {
        size_t i;
        Array *jsonArr = ArrayCreate();
        if (!jsonArr)
        {
            JsonFree(json);
            return NULL;
        }
        for (i = 0; i < ArraySize(val->event_fields); i++)
        {
            ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->event_fields, i)));
        }
        HashMapSet(json, "event_fields", JsonValueArray(jsonArr));
    }
    return json;
}

void
FilterFree(Filter *val)
{
    if (!val)
    {
        return;
    }

    FilterEventFree(&val->presence);
    FilterEventFree(&val->account_data);
    FilterRoomFree(&val->room);
    if (val->event_fields)
    {
        size_t i;
        for (i = 0; i < ArraySize(val->event_fields); i++)
        {
            Free(ArrayGet(val->event_fields, i));
        }
        ArrayFree(val->event_fields);
    }
}

int
FilterRoomEventFromJson(HashMap *json, FilterRoomEvent *out, char **errp)
{
    JsonValue *val;
    int enumParseRes;

    (void) enumParseRes;

    if (!json | !out)
    {
        *errp = "Invalid pointers passed to FilterRoomEventFromJson()";
        return 0;
    }

    val = HashMapGet(json, "not_rooms");
    if (val)
    {
        if (JsonValueType(val) != JSON_ARRAY)
        {
            *errp = "FilterRoomEvent.not_rooms must be of type [string].";
            return 0;
        }

        out->not_rooms = ArrayCreate();
        if (!out->not_rooms)
        {
            *errp = "Failed to allocate memory for FilterRoomEvent.not_rooms.";
            return 0;
        }
        else
        {
            Array *arr = JsonValueAsArray(val);
            size_t i;

            for (i = 0; i <ArraySize(arr); i++)
            {
                JsonValue *v = ArrayGet(arr, i);
                if (JsonValueType(v) != JSON_STRING)
                {
                    *errp = "FilterRoomEvent.not_rooms[] contains an invalid value.";
                    return 0;
                }
                ArrayAdd(out->not_rooms, StrDuplicate(JsonValueAsString(v)));
            }
        }
    }

    val = HashMapGet(json, "not_senders");
    if (val)
    {
        if (JsonValueType(val) != JSON_ARRAY)
        {
            *errp = "FilterRoomEvent.not_senders must be of type [string].";
            return 0;
        }

        out->not_senders = ArrayCreate();
        if (!out->not_senders)
        {
            *errp = "Failed to allocate memory for FilterRoomEvent.not_senders.";
            return 0;
        }
        else
        {
            Array *arr = JsonValueAsArray(val);
            size_t i;

            for (i = 0; i <ArraySize(arr); i++)
            {
                JsonValue *v = ArrayGet(arr, i);
                if (JsonValueType(v) != JSON_STRING)
                {
                    *errp = "FilterRoomEvent.not_senders[] contains an invalid value.";
                    return 0;
                }
                ArrayAdd(out->not_senders, StrDuplicate(JsonValueAsString(v)));
            }
        }
    }

    val = HashMapGet(json, "limit");
    if (val)
    {
        if (JsonValueType(val) != JSON_INTEGER)
        {
            *errp = "FilterRoomEvent.limit must be of type integer.";
            return 0;
        }

        out->limit = JsonValueAsInteger(val);
    }

    val = HashMapGet(json, "senders");
    if (val)
    {
        if (JsonValueType(val) != JSON_ARRAY)
        {
            *errp = "FilterRoomEvent.senders must be of type [string].";
            return 0;
        }

        out->senders = ArrayCreate();
        if (!out->senders)
        {
            *errp = "Failed to allocate memory for FilterRoomEvent.senders.";
            return 0;
        }
        else
        {
            Array *arr = JsonValueAsArray(val);
            size_t i;

            for (i = 0; i <ArraySize(arr); i++)
            {
                JsonValue *v = ArrayGet(arr, i);
                if (JsonValueType(v) != JSON_STRING)
                {
                    *errp = "FilterRoomEvent.senders[] contains an invalid value.";
                    return 0;
                }
                ArrayAdd(out->senders, StrDuplicate(JsonValueAsString(v)));
            }
        }
    }

    val = HashMapGet(json, "include_redundant_members");
    if (val)
    {
        if (JsonValueType(val) != JSON_BOOLEAN)
        {
            *errp = "FilterRoomEvent.include_redundant_members must be of type boolean.";
            return 0;
        }

        out->include_redundant_members = JsonValueAsBoolean(val);
    }

    val = HashMapGet(json, "types");
    if (val)
    {
        if (JsonValueType(val) != JSON_ARRAY)
        {
            *errp = "FilterRoomEvent.types must be of type [string].";
            return 0;
        }

        out->types = ArrayCreate();
        if (!out->types)
        {
            *errp = "Failed to allocate memory for FilterRoomEvent.types.";
            return 0;
        }
        else
        {
            Array *arr = JsonValueAsArray(val);
            size_t i;

            for (i = 0; i <ArraySize(arr); i++)
            {
                JsonValue *v = ArrayGet(arr, i);
                if (JsonValueType(v) != JSON_STRING)
                {
                    *errp = "FilterRoomEvent.types[] contains an invalid value.";
                    return 0;
                }
                ArrayAdd(out->types, StrDuplicate(JsonValueAsString(v)));
            }
        }
    }

    val = HashMapGet(json, "rooms");
    if (val)
    {
        if (JsonValueType(val) != JSON_ARRAY)
        {
            *errp = "FilterRoomEvent.rooms must be of type [string].";
            return 0;
        }

        out->rooms = ArrayCreate();
        if (!out->rooms)
        {
            *errp = "Failed to allocate memory for FilterRoomEvent.rooms.";
            return 0;
        }
        else
        {
            Array *arr = JsonValueAsArray(val);
            size_t i;

            for (i = 0; i <ArraySize(arr); i++)
            {
                JsonValue *v = ArrayGet(arr, i);
                if (JsonValueType(v) != JSON_STRING)
                {
                    *errp = "FilterRoomEvent.rooms[] contains an invalid value.";
                    return 0;
                }
                ArrayAdd(out->rooms, StrDuplicate(JsonValueAsString(v)));
            }
        }
    }

    val = HashMapGet(json, "lazy_load_members");
    if (val)
    {
        if (JsonValueType(val) != JSON_BOOLEAN)
        {
            *errp = "FilterRoomEvent.lazy_load_members must be of type boolean.";
            return 0;
        }

        out->lazy_load_members = JsonValueAsBoolean(val);
    }

    val = HashMapGet(json, "not_types");
    if (val)
    {
        if (JsonValueType(val) != JSON_ARRAY)
        {
            *errp = "FilterRoomEvent.not_types must be of type [string].";
            return 0;
        }

        out->not_types = ArrayCreate();
        if (!out->not_types)
        {
            *errp = "Failed to allocate memory for FilterRoomEvent.not_types.";
            return 0;
        }
        else
        {
            Array *arr = JsonValueAsArray(val);
            size_t i;

            for (i = 0; i <ArraySize(arr); i++)
            {
                JsonValue *v = ArrayGet(arr, i);
                if (JsonValueType(v) != JSON_STRING)
                {
                    *errp = "FilterRoomEvent.not_types[] contains an invalid value.";
                    return 0;
                }
                ArrayAdd(out->not_types, StrDuplicate(JsonValueAsString(v)));
            }
        }
    }

    val = HashMapGet(json, "contains_url");
    if (val)
    {
        if (JsonValueType(val) != JSON_BOOLEAN)
        {
            *errp = "FilterRoomEvent.contains_url must be of type boolean.";
            return 0;
        }

        out->contains_url = JsonValueAsBoolean(val);
    }

    val = HashMapGet(json, "unread_thread_notifications");
    if (val)
    {
        if (JsonValueType(val) != JSON_BOOLEAN)
        {
            *errp = "FilterRoomEvent.unread_thread_notifications must be of type boolean.";
            return 0;
        }

        out->unread_thread_notifications = JsonValueAsBoolean(val);
    }

    return 1;
}

HashMap *
FilterRoomEventToJson(FilterRoomEvent *val)
{
    HashMap *json;

    if (!val)
    {
        return NULL;
    }

    json = HashMapCreate();
    if (!json)
    {
        return NULL;
    }

    if (val->not_rooms)
    {
        size_t i;
        Array *jsonArr = ArrayCreate();
        if (!jsonArr)
        {
            JsonFree(json);
            return NULL;
        }
        for (i = 0; i < ArraySize(val->not_rooms); i++)
        {
            ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->not_rooms, i)));
        }
        HashMapSet(json, "not_rooms", JsonValueArray(jsonArr));
    }
    if (val->not_senders)
    {
        size_t i;
        Array *jsonArr = ArrayCreate();
        if (!jsonArr)
        {
            JsonFree(json);
            return NULL;
        }
        for (i = 0; i < ArraySize(val->not_senders); i++)
        {
            ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->not_senders, i)));
        }
        HashMapSet(json, "not_senders", JsonValueArray(jsonArr));
    }
    HashMapSet(json, "limit", JsonValueInteger(val->limit));
    if (val->senders)
    {
        size_t i;
        Array *jsonArr = ArrayCreate();
        if (!jsonArr)
        {
            JsonFree(json);
            return NULL;
        }
        for (i = 0; i < ArraySize(val->senders); i++)
        {
            ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->senders, i)));
        }
        HashMapSet(json, "senders", JsonValueArray(jsonArr));
    }
    HashMapSet(json, "include_redundant_members", JsonValueBoolean(val->include_redundant_members));
    if (val->types)
    {
        size_t i;
        Array *jsonArr = ArrayCreate();
        if (!jsonArr)
        {
            JsonFree(json);
            return NULL;
        }
        for (i = 0; i < ArraySize(val->types); i++)
        {
            ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->types, i)));
        }
        HashMapSet(json, "types", JsonValueArray(jsonArr));
    }
    if (val->rooms)
    {
        size_t i;
        Array *jsonArr = ArrayCreate();
        if (!jsonArr)
        {
            JsonFree(json);
            return NULL;
        }
        for (i = 0; i < ArraySize(val->rooms); i++)
        {
            ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->rooms, i)));
        }
        HashMapSet(json, "rooms", JsonValueArray(jsonArr));
    }
    HashMapSet(json, "lazy_load_members", JsonValueBoolean(val->lazy_load_members));
    if (val->not_types)
    {
        size_t i;
        Array *jsonArr = ArrayCreate();
        if (!jsonArr)
        {
            JsonFree(json);
            return NULL;
        }
        for (i = 0; i < ArraySize(val->not_types); i++)
        {
            ArrayAdd(jsonArr, JsonValueString(ArrayGet(val->not_types, i)));
        }
        HashMapSet(json, "not_types", JsonValueArray(jsonArr));
    }
    HashMapSet(json, "contains_url", JsonValueBoolean(val->contains_url));
    HashMapSet(json, "unread_thread_notifications", JsonValueBoolean(val->unread_thread_notifications));
    return json;
}

void
FilterRoomEventFree(FilterRoomEvent *val)
{
    if (!val)
    {
        return;
    }

    if (val->not_rooms)
    {
        size_t i;
        for (i = 0; i < ArraySize(val->not_rooms); i++)
        {
            Free(ArrayGet(val->not_rooms, i));
        }
        ArrayFree(val->not_rooms);
    }
    if (val->not_senders)
    {
        size_t i;
        for (i = 0; i < ArraySize(val->not_senders); i++)
        {
            Free(ArrayGet(val->not_senders, i));
        }
        ArrayFree(val->not_senders);
    }
    if (val->senders)
    {
        size_t i;
        for (i = 0; i < ArraySize(val->senders); i++)
        {
            Free(ArrayGet(val->senders, i));
        }
        ArrayFree(val->senders);
    }
    if (val->types)
    {
        size_t i;
        for (i = 0; i < ArraySize(val->types); i++)
        {
            Free(ArrayGet(val->types, i));
        }
        ArrayFree(val->types);
    }
    if (val->rooms)
    {
        size_t i;
        for (i = 0; i < ArraySize(val->rooms); i++)
        {
            Free(ArrayGet(val->rooms, i));
        }
        ArrayFree(val->rooms);
    }
    if (val->not_types)
    {
        size_t i;
        for (i = 0; i < ArraySize(val->not_types); i++)
        {
            Free(ArrayGet(val->not_types, i));
        }
        ArrayFree(val->not_types);
    }
}