#include <string.h>
#include <gio/gio.h>

static void
print_schema (GSettings *schema, const gchar *path, const gchar *indent)
{
    gchar *id;
    gchar **keys, **children, **i;

    keys = g_settings_list_keys (schema);
    children = g_settings_list_children (schema);

    g_object_get (schema, "schema-id", &id, NULL);
    g_print ("%s%s %s\n", indent, path, id);
    indent = g_strdup_printf ("%s  ", indent);
    for (i = keys; *i; i++)
    {
        GVariant *range, *value;
        gchar *type;

        range = g_settings_get_range (schema, *i);
        g_variant_get (range, "(&sv)", &type, &value);
        if (strcmp (type, "type") == 0)
        {
            const GVariantType *data_type;
          
            data_type = g_variant_type_element (g_variant_get_type (value));
            g_print ("%s%s (%s)\n", indent, *i, g_variant_type_peek_string (data_type));
        }
        else if (strcmp (type, "enum") == 0)
        {
            GVariantIter *iter;
            const gchar *enum_value;
            gboolean first = TRUE;

            g_print ("%s%s (", indent, *i);
            g_variant_get (value, "as", &iter);
            while (g_variant_iter_loop (iter, "&s", &enum_value))
            {
                if (first)
                    first = FALSE;
                else
                    g_print (", ");
                g_print ("\"%s\"", enum_value);
            }
            g_print (")\n");
        }
        else if (strcmp (type, "range") == 0)
        {
            GVariant *min, *max;

            min = g_variant_get_child_value (value, 0);
            max = g_variant_get_child_value (value, 1);
            g_print ("%s%s (%s, %s-%s)\n", indent, *i, g_variant_get_type_string (min), g_variant_print (min, FALSE), g_variant_print (max, FALSE));
        }
        else if (strcmp (type, "flags") == 0)
        {
            GVariantIter *iter;
            const gchar *flag_value;
            gboolean first = TRUE;

            g_print ("%s%s (", indent, *i);
            g_variant_get (value, "as", &iter);
            while (g_variant_iter_loop (iter, "&s", &flag_value))
            {
                if (first)
                    first = FALSE;
                else
                    g_print (", ");
                g_print ("'%s'", flag_value);
            }
            g_print (")\n");
        }
        // fixme "flags"
        else
            g_print ("%s%s (unknown-type:%s)\n", indent, *i, type);
        g_variant_unref (value);
        g_variant_unref (range);
    }
    for (i = children; *i; i++)
    {
        GSettings *child;
        child = g_settings_get_child (schema, *i);
        print_schema (child, g_strdup_printf ("%s/", *i), indent);
    }

    g_strfreev (keys);
    g_strfreev (children);
}

int
main (int argc, char **argv)
{
    const gchar * const *schemas;
    const gchar * const *i;
  
    g_type_init ();

    schemas = g_settings_list_schemas ();

    for (i = schemas; *i; i++)
    {
        GSettings *schema;
        gchar *path;

        schema = g_settings_new (*i);
        g_object_get (schema, "path", &path, NULL);
        print_schema (schema, path, "");
    }

    return 0;
}
