#include <gom/gom.h>


#define ITEM_TYPE_RESOURCE (item_resource_get_type ())
G_DECLARE_FINAL_TYPE (ItemResource, item_resource, ITEM, RESOURCE, GomResource)

struct _ItemResourceClass
{
    GomResourceClass parent;
};

struct _ItemResource
{
    GomResource  parent;

    guint64      id;
    gchar       *name;
};

G_DEFINE_TYPE (ItemResource, item_resource, GOM_TYPE_RESOURCE)

enum {
    PROP_0,
    PROP_ID,
    PROP_NAME,
    LAST_PROP
};

static GParamSpec *specs[LAST_PROP];

static void
item_resource_finalize (GObject *object)
{
    ItemResource *self = ITEM_RESOURCE (object);
    g_free (self->name);
    G_OBJECT_CLASS (item_resource_parent_class)->finalize (object);
}

static void
item_resource_get_property (GObject    *object,
                            guint       prop_id,
                            GValue     *value,
                            GParamSpec *pspec)
{
    ItemResource *self = ITEM_RESOURCE (object);

    switch (prop_id) {
        case PROP_ID:
            g_value_set_uint64 (value, self->id);
            break;
        case PROP_NAME:
            g_value_set_string (value, self->name);
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}

static void
item_resource_set_property (GObject      *object,
                            guint         prop_id,
                            const GValue *value,
                            GParamSpec   *pspec)
{
    ItemResource *self = ITEM_RESOURCE (object);

    switch (prop_id) {
        case PROP_ID:
            self->id = g_value_get_uint64 (value);
            break;
        case PROP_NAME:
            g_clear_pointer (&self->name, g_free);
            self->name = g_value_dup_string (value);
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    }
}

static void
item_resource_class_init (ItemResourceClass *klass)
{
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
    GomResourceClass *resource_class = GOM_RESOURCE_CLASS (klass);

    object_class->finalize = item_resource_finalize;
    object_class->get_property = item_resource_get_property;
    object_class->set_property = item_resource_set_property;

    gom_resource_class_set_table (resource_class, "items");

    specs[PROP_ID] = g_param_spec_uint64 ("id", NULL, NULL, 0, G_MAXINT64, 0, G_PARAM_READWRITE);
    g_object_class_install_property (object_class, PROP_ID, specs[PROP_ID]);
    gom_resource_class_set_primary_key (resource_class, "id");

    specs[PROP_NAME] = g_param_spec_string ("name", NULL, NULL, NULL, G_PARAM_READWRITE);
    g_object_class_install_property (object_class, PROP_NAME, specs[PROP_NAME]);
    gom_resource_class_set_notnull (resource_class, "name");
}

static void
item_resource_init (ItemResource *self)
{
}

void main () {
    GomAdapter *adapter;
    GomRepository *repository;
    ItemResource *item;
    GList *object_types;
    GError *error = NULL;
    gboolean ret;
    guint64 id;
    gchar *name;

    /* Connect to the database */
    adapter = gom_adapter_new ();
    ret = gom_adapter_open_sync (adapter, ":memory:", &error);
    g_assert_no_error (error);
    g_assert_true (ret);

    /* Create the table */
    repository = gom_repository_new (adapter);
    object_types = g_list_prepend (NULL, GINT_TO_POINTER (ITEM_TYPE_RESOURCE));
    ret = gom_repository_automatic_migrate_sync (repository, 1, object_types, &error);
    g_assert_no_error (error);
    g_assert_true (ret);

    /* Insert an item */
    item = g_object_new (ITEM_TYPE_RESOURCE, "repository", repository, "name", "item1", NULL);
    ret = gom_resource_save_sync (GOM_RESOURCE (item), &error);
    g_assert_no_error (error);
    g_assert (ret);
    g_object_unref (item);

    /* Fetch the item back */
    item = ITEM_RESOURCE (gom_repository_find_one_sync (repository, ITEM_TYPE_RESOURCE, NULL, &error));
    g_assert_no_error (error);
    g_object_get (item, "id", &id, "name", &name, NULL);
    g_print ("Item: id=%d, name='%s'\n", id, name);
    g_object_unref(item);
    g_free(name);

    /* Close the database */
    ret = gom_adapter_close_sync (adapter, &error);
    g_assert_no_error (error);
    g_assert (ret);
    g_object_unref (repository);
    g_object_unref (adapter);
}
