/* LIBPIKA - The PIKA Library
 * Copyright (C) 1995-2000 Peter Mattis and Spencer Kimball
 *
 * pikaitem.c
 * Copyright (C) Jehan
 *
 * This library is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library.  If not, see
 * <https://www.gnu.org/licenses/>.
 */

#include "config.h"

#include "pika.h"

#include "libpikabase/pikawire.h" /* FIXME kill this include */

#include "pikaplugin-private.h"
#include "pikaprocedure-private.h"


enum
{
  PROP_0,
  PROP_ID,
  N_PROPS
};


typedef struct _PikaItemPrivate
{
  gint id;
} PikaItemPrivate;


static void   pika_item_set_property  (GObject      *object,
                                       guint         property_id,
                                       const GValue *value,
                                       GParamSpec   *pspec);
static void   pika_item_get_property  (GObject      *object,
                                       guint         property_id,
                                       GValue       *value,
                                       GParamSpec   *pspec);


G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (PikaItem, pika_item, G_TYPE_OBJECT)

#define parent_class pika_item_parent_class

static GParamSpec *props[N_PROPS] = { NULL, };


static void
pika_item_class_init (PikaItemClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);

  object_class->set_property = pika_item_set_property;
  object_class->get_property = pika_item_get_property;

  props[PROP_ID] =
    g_param_spec_int ("id",
                      "The item id",
                      "The item id for internal use",
                      0, G_MAXINT32, 0,
                      PIKA_PARAM_READWRITE |
                      G_PARAM_CONSTRUCT_ONLY);

  g_object_class_install_properties (object_class, N_PROPS, props);
}

static void
pika_item_init (PikaItem *item)
{
}

static void
pika_item_set_property (GObject      *object,
                        guint         property_id,
                        const GValue *value,
                        GParamSpec   *pspec)
{
  PikaItem        *item = PIKA_ITEM (object);
  PikaItemPrivate *priv = pika_item_get_instance_private (item);

  switch (property_id)
    {
    case PROP_ID:
      priv->id = g_value_get_int (value);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}

static void
pika_item_get_property (GObject    *object,
                         guint       property_id,
                         GValue     *value,
                         GParamSpec *pspec)
{
  PikaItem        *item = PIKA_ITEM (object);
  PikaItemPrivate *priv = pika_item_get_instance_private (item);

  switch (property_id)
    {
    case PROP_ID:
      g_value_set_int (value, priv->id);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
      break;
    }
}


/* Public API. */


/**
 * pika_item_get_id:
 * @item: The item.
 *
 * Returns: the item ID.
 *
 * Since: 3.0
 **/
gint32
pika_item_get_id (PikaItem *item)
{
  if (item)
    {
      PikaItemPrivate *priv = pika_item_get_instance_private (item);

      return priv->id;
    }
  else
    {
      return -1;
    }
}

/**
 * pika_item_get_by_id:
 * @item_id: The item id.
 *
 * Returns a #PikaItem representing @item_id. Since #PikaItem is an
 * abstract class, the real object type will actually be the proper
 * subclass.
 *
 * Returns: (nullable) (transfer none): a #PikaItem for @item_id or
 *          %NULL if @item_id does not represent a valid item.
 *          The object belongs to libpika and you must not modify
 *          or unref it.
 *
 * Since: 3.0
 **/
PikaItem *
pika_item_get_by_id (gint32 item_id)
{
  if (item_id > 0)
    {
      PikaPlugIn    *plug_in   = pika_get_plug_in ();
      PikaProcedure *procedure = _pika_plug_in_get_procedure (plug_in);

      return _pika_procedure_get_item (procedure, item_id);
    }

  return NULL;
}

/**
 * pika_item_is_valid:
 * @item: The item to check.
 *
 * Returns TRUE if the item is valid.
 *
 * This procedure checks if the given item is valid and refers to an
 * existing item.
 *
 * Returns: Whether the item is valid.
 *
 * Since: 2.8
 **/
gboolean
pika_item_is_valid (PikaItem *item)
{
  return pika_item_id_is_valid (pika_item_get_id (item));
}

/**
 * pika_item_is_drawable:
 * @item: The item.
 *
 * Returns whether the item is a drawable.
 *
 * This procedure returns TRUE if the specified item is a drawable.
 *
 * Returns: TRUE if the item is a drawable, FALSE otherwise.
 *
 * Since: 2.8
 **/
gboolean
pika_item_is_drawable (PikaItem *item)
{
  return pika_item_id_is_drawable (pika_item_get_id (item));
}

/**
 * pika_item_is_layer:
 * @item: The item.
 *
 * Returns whether the item is a layer.
 *
 * This procedure returns TRUE if the specified item is a layer.
 *
 * Returns: TRUE if the item is a layer, FALSE otherwise.
 *
 * Since: 2.8
 **/
gboolean
pika_item_is_layer (PikaItem *item)
{
  return pika_item_id_is_layer (pika_item_get_id (item));
}

/**
 * pika_item_is_text_layer:
 * @item: The item.
 *
 * Returns whether the item is a text layer.
 *
 * This procedure returns TRUE if the specified item is a text
 * layer.
 *
 * Returns: TRUE if the item is a text layer, FALSE otherwise.
 *
 * Since: 2.8
 **/
gboolean
pika_item_is_text_layer (PikaItem *item)
{
  return pika_item_id_is_text_layer (pika_item_get_id (item));
}

/**
 * pika_item_is_channel:
 * @item: The item.
 *
 * Returns whether the item is a channel.
 *
 * This procedure returns TRUE if the specified item is a channel.
 *
 * Returns: TRUE if the item is a channel, FALSE otherwise.
 *
 * Since: 2.8
 **/
gboolean
pika_item_is_channel (PikaItem *item)
{
  return pika_item_id_is_channel (pika_item_get_id (item));
}

/**
 * pika_item_is_layer_mask:
 * @item: The item.
 *
 * Returns whether the item is a layer mask.
 *
 * This procedure returns TRUE if the specified item is a layer
 * mask.
 *
 * Returns: TRUE if the item is a layer mask, FALSE otherwise.
 *
 * Since: 2.8
 **/
gboolean
pika_item_is_layer_mask (PikaItem *item)
{
  return pika_item_id_is_layer_mask (pika_item_get_id (item));
}

/**
 * pika_item_is_selection:
 * @item: The item.
 *
 * Returns whether the item is a selection.
 *
 * This procedure returns TRUE if the specified item is a selection.
 *
 * Returns: TRUE if the item is a selection, FALSE otherwise.
 *
 * Since: 2.8
 **/
gboolean
pika_item_is_selection (PikaItem *item)
{
  return pika_item_id_is_selection (pika_item_get_id (item));
}

/**
 * pika_item_is_vectors:
 * @item: The item.
 *
 * Returns whether the item is a vectors.
 *
 * This procedure returns TRUE if the specified item is a vectors.
 *
 * Returns: TRUE if the item is a vectors, FALSE otherwise.
 *
 * Since: 2.8
 **/
gboolean
pika_item_is_vectors (PikaItem *item)
{
  return pika_item_id_is_vectors (pika_item_get_id (item));
}

/**
 * pika_item_list_children:
 * @item: The item.
 *
 * Returns the item's list of children.
 *
 * This procedure returns the list of items which are children of the
 * specified item. The order is topmost to bottommost.
 *
 * Returns: (element-type PikaItem) (transfer container):
 *          The item's list of children.
 *          The returned list must be freed with g_list_free(). Item
 *          elements belong to libpika and must not be unrefed.
 *
 * Since: 3.0
 **/
GList *
pika_item_list_children (PikaItem *item)
{
  PikaItem **children;
  gint       num_children;
  GList     *list = NULL;
  gint       i;

  children = pika_item_get_children (item, &num_children);

  for (i = 0; i < num_children; i++)
    list = g_list_prepend (list, children[i]);

  g_free (children);

  return g_list_reverse (list);
}
