/* PIKA - Photo and Image Kooker Application
 * a rebranding of The GNU Image Manipulation Program (created with heckimp)
 * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
 *
 * Original copyright, applying to most contents (license remains unchanged): 
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */

#include "config.h"

#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>

#include "core-types.h"

#include "gegl/pika-babl.h"

#include "pikaerror.h"
#include "pikaimage.h"
#include "pikalayer.h"
#include "pikalayermask.h"

#include "pika-intl.h"


static void            pika_layer_mask_preview_freeze       (PikaViewable      *viewable);
static void            pika_layer_mask_preview_thaw         (PikaViewable      *viewable);

static gboolean        pika_layer_mask_is_attached          (PikaItem          *item);
static gboolean        pika_layer_mask_is_content_locked    (PikaItem          *item,
                                                             PikaItem         **locked_item);
static gboolean        pika_layer_mask_is_position_locked   (PikaItem          *item,
                                                             PikaItem         **locked_item,
                                                             gboolean           check_children);
static PikaItemTree  * pika_layer_mask_get_tree             (PikaItem          *item);
static PikaItem      * pika_layer_mask_duplicate            (PikaItem          *item,
                                                             GType              new_type);
static gboolean        pika_layer_mask_rename               (PikaItem          *item,
                                                             const gchar       *new_name,
                                                             const gchar       *undo_desc,
                                                             GError           **error);

static void            pika_layer_mask_bounding_box_changed (PikaDrawable      *drawable);
static void            pika_layer_mask_convert_type         (PikaDrawable      *drawable,
                                                             PikaImage         *dest_image,
                                                             const Babl        *new_format,
                                                             PikaColorProfile  *src_profile,
                                                             PikaColorProfile  *dest_profile,
                                                             GeglDitherMethod   layer_dither_type,
                                                             GeglDitherMethod   mask_dither_type,
                                                             gboolean           push_undo,
                                                             PikaProgress      *progress);


G_DEFINE_TYPE (PikaLayerMask, pika_layer_mask, PIKA_TYPE_CHANNEL)

#define parent_class pika_layer_mask_parent_class


static void
pika_layer_mask_class_init (PikaLayerMaskClass *klass)
{
  PikaViewableClass *viewable_class = PIKA_VIEWABLE_CLASS (klass);
  PikaItemClass     *item_class     = PIKA_ITEM_CLASS (klass);
  PikaDrawableClass *drawable_class = PIKA_DRAWABLE_CLASS (klass);

  viewable_class->default_icon_name = "pika-layer-mask";

  viewable_class->preview_freeze       = pika_layer_mask_preview_freeze;
  viewable_class->preview_thaw         = pika_layer_mask_preview_thaw;

  item_class->is_attached              = pika_layer_mask_is_attached;
  item_class->is_content_locked        = pika_layer_mask_is_content_locked;
  item_class->is_position_locked       = pika_layer_mask_is_position_locked;
  item_class->get_tree                 = pika_layer_mask_get_tree;
  item_class->duplicate                = pika_layer_mask_duplicate;
  item_class->rename                   = pika_layer_mask_rename;
  item_class->translate_desc           = C_("undo-type", "Move Layer Mask");
  item_class->to_selection_desc        = C_("undo-type", "Layer Mask to Selection");

  drawable_class->bounding_box_changed = pika_layer_mask_bounding_box_changed;
  drawable_class->convert_type         = pika_layer_mask_convert_type;
}

static void
pika_layer_mask_init (PikaLayerMask *layer_mask)
{
  layer_mask->layer = NULL;
}

static void
pika_layer_mask_preview_freeze (PikaViewable *viewable)
{
  PikaLayerMask *mask  = PIKA_LAYER_MASK (viewable);
  PikaLayer     *layer = pika_layer_mask_get_layer (mask);

  if (layer)
    {
      PikaViewable *parent = pika_viewable_get_parent (PIKA_VIEWABLE (layer));

      if (! parent && pika_item_is_attached (PIKA_ITEM (layer)))
        parent = PIKA_VIEWABLE (pika_item_get_image (PIKA_ITEM (layer)));

      if (parent)
        pika_viewable_preview_freeze (parent);
    }
}

static void
pika_layer_mask_preview_thaw (PikaViewable *viewable)
{
  PikaLayerMask *mask  = PIKA_LAYER_MASK (viewable);
  PikaLayer     *layer = pika_layer_mask_get_layer (mask);

  if (layer)
    {
      PikaViewable *parent = pika_viewable_get_parent (PIKA_VIEWABLE (layer));

      if (! parent && pika_item_is_attached (PIKA_ITEM (layer)))
        parent = PIKA_VIEWABLE (pika_item_get_image (PIKA_ITEM (layer)));

      if (parent)
        pika_viewable_preview_thaw (parent);
    }
}

static gboolean
pika_layer_mask_is_content_locked (PikaItem  *item,
                                   PikaItem **locked_item)
{
  PikaLayerMask *mask  = PIKA_LAYER_MASK (item);
  PikaLayer     *layer = pika_layer_mask_get_layer (mask);

  if (layer)
    return pika_item_is_content_locked (PIKA_ITEM (layer), locked_item);

  return FALSE;
}

static gboolean
pika_layer_mask_is_position_locked (PikaItem  *item,
                                    PikaItem **locked_item,
                                    gboolean   check_children)
{
  PikaLayerMask *mask  = PIKA_LAYER_MASK (item);
  PikaLayer     *layer = pika_layer_mask_get_layer (mask);

  if (layer)
    return pika_item_is_position_locked (PIKA_ITEM (layer), locked_item);

  return FALSE;
}

static gboolean
pika_layer_mask_is_attached (PikaItem *item)
{
  PikaLayerMask *mask  = PIKA_LAYER_MASK (item);
  PikaLayer     *layer = pika_layer_mask_get_layer (mask);

  return (PIKA_IS_IMAGE (pika_item_get_image (item)) &&
          PIKA_IS_LAYER (layer)                      &&
          pika_layer_get_mask (layer) == mask        &&
          pika_item_is_attached (PIKA_ITEM (layer)));
}

static PikaItemTree *
pika_layer_mask_get_tree (PikaItem *item)
{
  return NULL;
}

static PikaItem *
pika_layer_mask_duplicate (PikaItem *item,
                           GType     new_type)
{
  PikaItem *new_item;

  g_return_val_if_fail (g_type_is_a (new_type, PIKA_TYPE_DRAWABLE), NULL);

  new_item = PIKA_ITEM_CLASS (parent_class)->duplicate (item, new_type);

  return new_item;
}

static gboolean
pika_layer_mask_rename (PikaItem     *item,
                        const gchar  *new_name,
                        const gchar  *undo_desc,
                        GError      **error)
{
  /* reject renaming, layer masks are always named "<layer name> mask"  */

  g_set_error (error, PIKA_ERROR, PIKA_FAILED,
               _("Cannot rename layer masks."));

  return FALSE;
}

static void
pika_layer_mask_bounding_box_changed (PikaDrawable *drawable)
{
  PikaLayerMask *mask  = PIKA_LAYER_MASK (drawable);
  PikaLayer     *layer = pika_layer_mask_get_layer (mask);

  if (PIKA_DRAWABLE_CLASS (parent_class)->bounding_box_changed)
    PIKA_DRAWABLE_CLASS (parent_class)->bounding_box_changed (drawable);

  if (layer)
    pika_drawable_update_bounding_box (PIKA_DRAWABLE (layer));
}

static void
pika_layer_mask_convert_type (PikaDrawable      *drawable,
                              PikaImage         *dest_image,
                              const Babl        *new_format,
                              PikaColorProfile  *src_profile,
                              PikaColorProfile  *dest_profile,
                              GeglDitherMethod   layer_dither_type,
                              GeglDitherMethod   mask_dither_type,
                              gboolean           push_undo,
                              PikaProgress      *progress)
{
  new_format =
    pika_babl_mask_format (pika_babl_format_get_precision (new_format));

  PIKA_DRAWABLE_CLASS (parent_class)->convert_type (drawable, dest_image,
                                                    new_format,
                                                    src_profile,
                                                    dest_profile,
                                                    layer_dither_type,
                                                    mask_dither_type,
                                                    push_undo,
                                                    progress);
}

PikaLayerMask *
pika_layer_mask_new (PikaImage     *image,
                     gint           width,
                     gint           height,
                     const gchar   *name,
                     const PikaRGB *color)
{
  PikaLayerMask *layer_mask;

  g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
  g_return_val_if_fail (width > 0, NULL);
  g_return_val_if_fail (height > 0, NULL);
  g_return_val_if_fail (color != NULL, NULL);

  layer_mask =
    PIKA_LAYER_MASK (pika_drawable_new (PIKA_TYPE_LAYER_MASK,
                                        image, name,
                                        0, 0, width, height,
                                        pika_image_get_mask_format (image)));

  /*  set the layer_mask color and opacity  */
  pika_channel_set_color (PIKA_CHANNEL (layer_mask), color, FALSE);
  pika_channel_set_show_masked (PIKA_CHANNEL (layer_mask), TRUE);

  /*  selection mask variables  */
  PIKA_CHANNEL (layer_mask)->x2 = width;
  PIKA_CHANNEL (layer_mask)->y2 = height;

  return layer_mask;
}

void
pika_layer_mask_set_layer (PikaLayerMask *layer_mask,
                           PikaLayer     *layer)
{
  g_return_if_fail (PIKA_IS_LAYER_MASK (layer_mask));
  g_return_if_fail (layer == NULL || PIKA_IS_LAYER (layer));

  layer_mask->layer = layer;

  if (layer)
    {
      gchar *mask_name;
      gint   offset_x;
      gint   offset_y;

      pika_item_get_offset (PIKA_ITEM (layer), &offset_x, &offset_y);
      pika_item_set_offset (PIKA_ITEM (layer_mask), offset_x, offset_y);

      mask_name = g_strdup_printf (_("%s mask"), pika_object_get_name (layer));

      pika_object_take_name (PIKA_OBJECT (layer_mask), mask_name);
    }
}

PikaLayer *
pika_layer_mask_get_layer (PikaLayerMask *layer_mask)
{
  g_return_val_if_fail (PIKA_IS_LAYER_MASK (layer_mask), NULL);

  return layer_mask->layer;
}
