/* Pango2
 *
 * Copyright (C) 2022 Matthias Clasen
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "config.h"

#include <gio/gio.h>

#include "pango-generic-family-private.h"
#include "pango-hbfamily-private.h"
#include "pango-impl-utils.h"
#include "pango-hbface-private.h"
#include "pango-font-private.h"

/**
 * Pango2GenericFamily:
 *
 * An implementation of `Pango2FontFamily`
 * that provides faces from other families.
 *
 * `Pango2GenericFamily can be used to e.g. assemble a
 * generic 'sans-serif' family from a number of other
 * font families.
 */


/* {{{ GListModel implementation */

static GType
pango2_generic_family_get_item_type (GListModel *list)
{
  return PANGO2_TYPE_FONT_FACE;
}

static guint
pango2_generic_family_get_n_items (GListModel *list)
{
  Pango2GenericFamily *self = PANGO2_GENERIC_FAMILY (list);
  guint n;

  n = 0;
  for (int i = 0; i < self->families->len; i++)
    {
      Pango2HbFamily *family = g_ptr_array_index (self->families, i);

      n += g_list_model_get_n_items (G_LIST_MODEL (family));
    }

  return n;
}

static gpointer
pango2_generic_family_get_item (GListModel *list,
                                guint       position)
{
  Pango2GenericFamily *self = PANGO2_GENERIC_FAMILY (list);
  guint pos;

  pos = position;
  for (int i = 0; i < self->families->len; i++)
    {
      Pango2HbFamily *family = g_ptr_array_index (self->families, i);

      if (pos < g_list_model_get_n_items (G_LIST_MODEL (family)))
        return g_list_model_get_item (G_LIST_MODEL (family), pos);

      pos -= g_list_model_get_n_items (G_LIST_MODEL (family));
    }

  return NULL;
}

static void
pango2_generic_family_list_model_init (GListModelInterface *iface)
{
  iface->get_item_type = pango2_generic_family_get_item_type;
  iface->get_n_items = pango2_generic_family_get_n_items;
  iface->get_item = pango2_generic_family_get_item;
}

/* }}} */
/* {{{ Pango2FontFamily implementation */

struct _Pango2GenericFamilyClass
{
  Pango2FontFamilyClass parent_class;
};

G_DEFINE_FINAL_TYPE_WITH_CODE (Pango2GenericFamily, pango2_generic_family, PANGO2_TYPE_FONT_FAMILY,
                               G_IMPLEMENT_INTERFACE (G_TYPE_LIST_MODEL, pango2_generic_family_list_model_init))

static void
pango2_generic_family_init (Pango2GenericFamily *self)
{
  self->families = g_ptr_array_new_with_free_func (g_object_unref);
}

static void
pango2_generic_family_finalize (GObject *object)
{
  Pango2GenericFamily *self = PANGO2_GENERIC_FAMILY (object);

  g_ptr_array_unref (self->families);

  G_OBJECT_CLASS (pango2_generic_family_parent_class)->finalize (object);
}

static void
pango2_generic_family_class_init (Pango2GenericFamilyClass *class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (class);

  object_class->finalize = pango2_generic_family_finalize;
}

/* }}} */
/* {{{ Private API */

/*< private >
 * pango2_generic_family_find_face:
 * @family: a `Pango2GenericFamily`
 * @description: `Pango2FontDescription` to match
 * @language: (nullable): `Pango2Language` to support
 * @wc: a Unicode character, or 0 to ignore
 *
 * Finds the face that best matches the font description while
 * also supporting the given language and character, from the first
 * family in @family that has any matching faces.
 *
 * Returns: (transfer none) (nullable): the face
 */
Pango2FontFace *
pango2_generic_family_find_face (Pango2GenericFamily   *self,
                                 Pango2FontDescription *description,
                                 Pango2Language        *language,
                                 gunichar               wc)
{
  Pango2FontFace *face = NULL;

  for (int i = 0; i < self->families->len; i++)
    {
      Pango2HbFamily *family = g_ptr_array_index (self->families, i);

      face = pango2_hb_family_find_face (family, description, language, wc);
      if (face)
        break;
    }

  /* last resort */
  if (!face && self->families->len > 0)
    {
      Pango2HbFamily *family = g_ptr_array_index (self->families, 0);
      face = g_list_model_get_item (G_LIST_MODEL (family), 0);
      g_object_unref (face);
    }

  return face;
}

/* }}} */
/* {{{ Public API */

/**
 * pango2_generic_family_new:
 * @name: the family name
 *
 * Creates a new `Pango2GenericFamily`.
 *
 * A generic family does not contain faces, but will return
 * faces from other families that match a given query.
 *
 * Returns: a newly created `Pango2GenericFamily`
 */
Pango2GenericFamily *
pango2_generic_family_new (const char *name)
{
  Pango2GenericFamily *self;

  g_return_val_if_fail (name != NULL, NULL);

  self = g_object_new (PANGO2_TYPE_GENERIC_FAMILY, NULL);

  pango2_font_family_set_name (PANGO2_FONT_FAMILY (self), name);

  return self;
}

/**
 * pango2_generic_family_add_family:
 * @self: a `Pango2GenericFamily`
 * @family: (transfer none): a `Pango2FontFamily` to add
 *
 * Adds a `Pango2FontFamily` to a `Pango2GenericFamily`.
 *
 * It is an error to call this function more than
 * once for the same family.
 */
void
pango2_generic_family_add_family (Pango2GenericFamily *self,
                                  Pango2FontFamily    *family)
{
  g_return_if_fail (PANGO2_IS_GENERIC_FAMILY (self));
  g_return_if_fail (PANGO2_IS_FONT_FAMILY (family));

  g_ptr_array_add (self->families, g_object_ref (family));
}

/* }}} */

/* vim:set foldmethod=marker expandtab: */
