/* 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 "pika.h"
#include "pikacontext.h"
#include "pikaguide.h"
#include "pikaimage.h"
#include "pikaimage-crop.h"
#include "pikaimage-guides.h"
#include "pikaimage-sample-points.h"
#include "pikaimage-undo.h"
#include "pikaimage-undo-push.h"
#include "pikalayer.h"
#include "pikasamplepoint.h"

#include "pika-intl.h"


/*  public functions  */

void
pika_image_crop (PikaImage    *image,
                 PikaContext  *context,
                 PikaFillType  fill_type,
                 gint          x,
                 gint          y,
                 gint          width,
                 gint          height,
                 gboolean      crop_layers)
{
  GList *list;
  gint   previous_width;
  gint   previous_height;

  g_return_if_fail (PIKA_IS_IMAGE (image));
  g_return_if_fail (PIKA_IS_CONTEXT (context));

  previous_width  = pika_image_get_width  (image);
  previous_height = pika_image_get_height (image);

  /*  Make sure new width and height are non-zero  */
  if (width < 1 || height < 1)
    return;

  pika_set_busy (image->pika);

  g_object_freeze_notify (G_OBJECT (image));

  if (crop_layers)
    pika_image_undo_group_start (image, PIKA_UNDO_GROUP_IMAGE_CROP,
                                 C_("undo-type", "Crop Image"));
  else
    pika_image_undo_group_start (image, PIKA_UNDO_GROUP_IMAGE_RESIZE,
                                 C_("undo-type", "Resize Image"));

  /*  Push the image size to the stack  */
  pika_image_undo_push_image_size (image, NULL,
                                   x, y, width, height);

  /*  Set the new width and height  */
  g_object_set (image,
                "width",  width,
                "height", height,
                NULL);

  /*  Resize all channels  */
  for (list = pika_image_get_channel_iter (image);
       list;
       list = g_list_next (list))
    {
      PikaItem *item = list->data;

      pika_item_resize (item, context, PIKA_FILL_TRANSPARENT,
                        width, height, -x, -y);
    }

  /*  Resize all vectors  */
  for (list = pika_image_get_vectors_iter (image);
       list;
       list = g_list_next (list))
    {
      PikaItem *item = list->data;

      pika_item_resize (item, context, PIKA_FILL_TRANSPARENT,
                        width, height, -x, -y);
    }

  /*  Don't forget the selection mask!  */
  pika_item_resize (PIKA_ITEM (pika_image_get_mask (image)),
                    context, PIKA_FILL_TRANSPARENT,
                    width, height, -x, -y);

  /*  crop all layers  */
  list = pika_image_get_layer_iter (image);

  while (list)
    {
      PikaItem *item = list->data;

      list = g_list_next (list);

      pika_item_translate (item, -x, -y, TRUE);

      if (crop_layers && ! pika_item_is_content_locked (item, NULL))
        {
          gint off_x, off_y;
          gint lx1, ly1, lx2, ly2;

          pika_item_get_offset (item, &off_x, &off_y);

          lx1 = CLAMP (off_x, 0, pika_image_get_width  (image));
          ly1 = CLAMP (off_y, 0, pika_image_get_height (image));
          lx2 = CLAMP (pika_item_get_width  (item) + off_x,
                       0, pika_image_get_width (image));
          ly2 = CLAMP (pika_item_get_height (item) + off_y,
                       0, pika_image_get_height (image));

          width  = lx2 - lx1;
          height = ly2 - ly1;

          if (width > 0 && height > 0)
            {
              pika_item_resize (item, context, fill_type,
                                width, height,
                                -(lx1 - off_x),
                                -(ly1 - off_y));
            }
          else
            {
              pika_image_remove_layer (image, PIKA_LAYER (item),
                                       TRUE, NULL);
            }
        }
    }

  /*  Reposition or remove guides  */
  list = pika_image_get_guides (image);

  while (list)
    {
      PikaGuide *guide        = list->data;
      gboolean   remove_guide = FALSE;
      gint       position     = pika_guide_get_position (guide);

      list = g_list_next (list);

      switch (pika_guide_get_orientation (guide))
        {
        case PIKA_ORIENTATION_HORIZONTAL:
          position -= y;
          if ((position < 0) || (position > height))
            remove_guide = TRUE;
          break;

        case PIKA_ORIENTATION_VERTICAL:
          position -= x;
          if ((position < 0) || (position > width))
            remove_guide = TRUE;
          break;

        default:
          break;
        }

      if (remove_guide)
        pika_image_remove_guide (image, guide, TRUE);
      else if (position != pika_guide_get_position (guide))
        pika_image_move_guide (image, guide, position, TRUE);
    }

  /*  Reposition or remove sample points  */
  list = pika_image_get_sample_points (image);

  while (list)
    {
      PikaSamplePoint *sample_point        = list->data;
      gboolean         remove_sample_point = FALSE;
      gint             old_x;
      gint             old_y;
      gint             new_x;
      gint             new_y;

      list = g_list_next (list);

      pika_sample_point_get_position (sample_point, &old_x, &old_y);
      new_x = old_x;
      new_y = old_y;

      new_y -= y;
      if ((new_y < 0) || (new_y > height))
       remove_sample_point = TRUE;

      new_x -= x;
      if ((new_x < 0) || (new_x > width))
        remove_sample_point = TRUE;

      if (remove_sample_point)
        pika_image_remove_sample_point (image, sample_point, TRUE);
      else if (new_x != old_x || new_y != old_y)
        pika_image_move_sample_point (image, sample_point,
                                      new_x, new_y, TRUE);
    }

  pika_image_undo_group_end (image);

  pika_image_size_changed_detailed (image,
                                    -x, -y,
                                    previous_width, previous_height);

  g_object_thaw_notify (G_OBJECT (image));

  pika_unset_busy (image->pika);
}
