/**
 * gnome_xkb_info_description_for_option:
 * @self: a #GnomeXkbInfo
 * @group_id: identifier for group containing the option
 * @id: option identifier
 *
 * Return value: the translated description for the option @id.
 *
 * Since: 3.6
 */
const gchar *
gnome_xkb_info_description_for_option (GnomeXkbInfo *self,
                                       const gchar  *group_id,
                                       const gchar  *id)
{
  GnomeXkbInfoPrivate *priv;
  const XkbOptionGroup *group;
  const XkbOption *option;

  g_return_val_if_fail (GNOME_IS_XKB_INFO (self), NULL);

  priv = self->priv;

  if (!ensure_rules_are_parsed (self))
    return NULL;

  group = g_hash_table_lookup (priv->option_groups_table, group_id);
  if (!group)
    return NULL;

  option = g_hash_table_lookup (group->options_table, id);
  if (!option)
    return NULL;

  return XKEYBOARD_CONFIG_(option->description);
}
/**
 * gnome_xkb_info_get_layouts_for_country:
 * @self: a #GnomeXkbInfo
 * @country_code: an ISO 3166 code string
 *
 * Returns a list of all layout identifiers we know about for
 * @country_code.
 *
 * Return value: (transfer container) (element-type utf8): the list
 * of layout ids. The caller takes ownership of the #GList but not of
 * the strings themselves, those are internally allocated and must not
 * be modified.
 *
 * Since: 3.8
 */
GList *
gnome_xkb_info_get_layouts_for_country (GnomeXkbInfo *self,
                                        const gchar  *country_code)
{
  GnomeXkbInfoPrivate *priv;
  GHashTable *layouts_for_country;
  gchar *country;
  GList *list;

  g_return_val_if_fail (GNOME_IS_XKB_INFO (self), NULL);

  priv = self->priv;

  if (!ensure_rules_are_parsed (self))
    return NULL;

  country = gnome_get_country_from_code (country_code, NULL);
  if (!country)
    return NULL;

  layouts_for_country = g_hash_table_lookup (priv->layouts_by_country, country);
  g_free (country);

  if (!layouts_for_country)
    return NULL;

  list = NULL;
  g_hash_table_foreach (layouts_for_country, collect_layout_ids, &list);

  return list;
}
/**
 * gnome_xkb_info_get_layout_info:
 * @self: a #GnomeXkbInfo
 * @id: layout's identifier about which to retrieve the info
 * @display_name: (out) (allow-none) (transfer none): location to store
 * the layout's display name, or %NULL
 * @short_name: (out) (allow-none) (transfer none): location to store
 * the layout's short name, or %NULL
 * @xkb_layout: (out) (allow-none) (transfer none): location to store
 * the layout's XKB name, or %NULL
 * @xkb_variant: (out) (allow-none) (transfer none): location to store
 * the layout's XKB variant, or %NULL
 *
 * Retrieves information about a layout. Both @display_name and
 * @short_name are suitable to show in UIs and might be localized if
 * translations are available.
 *
 * Some layouts don't provide a short name (2 or 3 letters) or don't
 * specify a XKB variant, in those cases @short_name or @xkb_variant
 * are empty strings, i.e. "".
 *
 * If the given layout doesn't exist the return value is %FALSE and
 * all the (out) parameters are set to %NULL.
 *
 * Return value: %TRUE if the layout exists or %FALSE otherwise.
 *
 * Since: 3.6
 */
gboolean
gnome_xkb_info_get_layout_info (GnomeXkbInfo *self,
                                const gchar  *id,
                                const gchar **display_name,
                                const gchar **short_name,
                                const gchar **xkb_layout,
                                const gchar **xkb_variant)
{
  GnomeXkbInfoPrivate *priv;
  const Layout *layout;

  if (display_name)
    *display_name = NULL;
  if (short_name)
    *short_name = NULL;
  if (xkb_layout)
    *xkb_layout = NULL;
  if (xkb_variant)
    *xkb_variant = NULL;

  g_return_val_if_fail (GNOME_IS_XKB_INFO (self), FALSE);

  priv = self->priv;

  if (!ensure_rules_are_parsed (self))
    return FALSE;

  if (!g_hash_table_lookup_extended (priv->layouts_table, id, NULL, (gpointer *)&layout))
    return FALSE;

  if (display_name)
    *display_name = XKEYBOARD_CONFIG_(layout->description);

  if (!layout->is_variant)
    {
      if (short_name)
        *short_name = XKEYBOARD_CONFIG_(layout->short_desc ? layout->short_desc : "");
      if (xkb_layout)
        *xkb_layout = layout->xkb_name;
      if (xkb_variant)
        *xkb_variant = "";
    }
  else
    {
      if (short_name)
        *short_name = XKEYBOARD_CONFIG_(layout->short_desc ? layout->short_desc :
                        layout->main_layout->short_desc ? layout->main_layout->short_desc : "");
      if (xkb_layout)
        *xkb_layout = layout->main_layout->xkb_name;
      if (xkb_variant)
        *xkb_variant = layout->xkb_name;
    }

  return TRUE;
}
/**
 * gnome_xkb_info_get_all_option_groups:
 * @self: a #GnomeXkbInfo
 *
 * Returns a list of all option group identifiers we know about.
 *
 * Return value: (transfer container) (element-type utf8): the list
 * of option group ids. The caller takes ownership of the #GList but
 * not of the strings themselves, those are internally allocated and
 * must not be modified.
 *
 * Since: 3.6
 */
GList *
gnome_xkb_info_get_all_option_groups (GnomeXkbInfo *self)
{
  GnomeXkbInfoPrivate *priv;

  g_return_val_if_fail (GNOME_IS_XKB_INFO (self), NULL);

  priv = self->priv;

  if (!ensure_rules_are_parsed (self))
    return NULL;

  return g_hash_table_get_keys (priv->option_groups_table);
}
/**
 * gnome_xkb_info_get_options_for_group:
 * @self: a #GnomeXkbInfo
 * @group_id: group's identifier about which to retrieve the options
 *
 * Returns a list of all option identifiers we know about for group
 * @group_id.
 *
 * Return value: (transfer container) (element-type utf8): the list
 * of option ids. The caller takes ownership of the #GList but not of
 * the strings themselves, those are internally allocated and must not
 * be modified.
 *
 * Since: 3.6
 */
GList *
gnome_xkb_info_get_options_for_group (GnomeXkbInfo *self,
                                      const gchar  *group_id)
{
  GnomeXkbInfoPrivate *priv;
  const XkbOptionGroup *group;

  g_return_val_if_fail (GNOME_IS_XKB_INFO (self), NULL);

  priv = self->priv;

  if (!ensure_rules_are_parsed (self))
    return NULL;

  group = g_hash_table_lookup (priv->option_groups_table, group_id);
  if (!group)
    return NULL;

  return g_hash_table_get_keys (group->options_table);
}
/**
 * gnome_xkb_info_get_layout_info_for_language:
 * @self: a #GnomeXkbInfo
 * @language: an ISO 639 code
 * @id: (out) (allow-none) (transfer none): location to store the
 * layout's indentifier, or %NULL
 * @display_name: (out) (allow-none) (transfer none): location to store
 * the layout's display name, or %NULL
 * @short_name: (out) (allow-none) (transfer none): location to store
 * the layout's short name, or %NULL
 * @xkb_layout: (out) (allow-none) (transfer none): location to store
 * the layout's XKB name, or %NULL
 * @xkb_variant: (out) (allow-none) (transfer none): location to store
 * the layout's XKB variant, or %NULL
 *
 * Retrieves the layout that better fits @language. It also fetches
 * information about that layout like gnome_xkb_info_get_layout_info().
 *
 * If a layout can't be found the return value is %FALSE and all the
 * (out) parameters are set to %NULL.
 *
 * Return value: %TRUE if a layout exists or %FALSE otherwise.
 *
 * Since: 3.6
 */
gboolean
gnome_xkb_info_get_layout_info_for_language (GnomeXkbInfo *self,
                                             const gchar  *language,
                                             const gchar **id,
                                             const gchar **display_name,
                                             const gchar **short_name,
                                             const gchar **xkb_layout,
                                             const gchar **xkb_variant)
{
  GnomeXkbInfoPrivate *priv;
  const Layout *layout;

  if (id)
    *id = NULL;
  if (display_name)
    *display_name = NULL;
  if (short_name)
    *short_name = NULL;
  if (xkb_layout)
    *xkb_layout = NULL;
  if (xkb_variant)
    *xkb_variant = NULL;

  g_return_val_if_fail (GNOME_IS_XKB_INFO (self), FALSE);

  priv = self->priv;

  if (!ensure_rules_are_parsed (self))
    return FALSE;

  /* First look in the proper language codes index, if we can't find
   * it there try again on the (untranslated) short descriptions since
   * sometimes those will give us a good match. */
  if (!g_hash_table_lookup_extended (priv->layouts_by_iso639, language, NULL, (gpointer *)&layout))
    if (!g_hash_table_lookup_extended (priv->layouts_by_short_desc, language, NULL, (gpointer *)&layout))
      return FALSE;

  if (id)
    *id = layout->id;
  if (display_name)
    *display_name = XKEYBOARD_CONFIG_(layout->description);

  if (!layout->is_variant)
    {
      if (short_name)
        *short_name = XKEYBOARD_CONFIG_(layout->short_desc ? layout->short_desc : "");
      if (xkb_layout)
        *xkb_layout = layout->xkb_name;
      if (xkb_variant)
        *xkb_variant = "";
    }
  else
    {
      if (short_name)
        *short_name = XKEYBOARD_CONFIG_(layout->short_desc ? layout->short_desc :
                        layout->main_layout->short_desc ? layout->main_layout->short_desc : "");
      if (xkb_layout)
        *xkb_layout = layout->main_layout->xkb_name;
      if (xkb_variant)
        *xkb_variant = layout->xkb_name;
    }

  return TRUE;
}