/* 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) 2009 Martin Nordholts <martinn@src.gnome.org>
 *
 * 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 <stdlib.h>
#include <string.h>

#include <gegl.h>
#include <glib/gstdio.h>
#include <gtk/gtk.h>

#include "libpikabase/pikabase.h"
#include "libpikamath/pikamath.h"
#include "libpikawidgets/pikawidgets.h"

#include "dialogs/dialogs-types.h"

#include "core/pika.h"
#include "core/pikachannel.h"
#include "core/pikacontext.h"
#include "core/pikaimage.h"
#include "core/pikalayer.h"
#include "core/pikatoolinfo.h"
#include "core/pikatooloptions.h"

#include "plug-in/pikapluginmanager-file.h"

#include "file/file-open.h"
#include "file/file-save.h"

#include "widgets/pikadialogfactory.h"
#include "widgets/pikadock.h"
#include "widgets/pikadockable.h"
#include "widgets/pikadockbook.h"
#include "widgets/pikadocked.h"
#include "widgets/pikadockwindow.h"
#include "widgets/pikahelp-ids.h"
#include "widgets/pikasessioninfo.h"
#include "widgets/pikatoolbox.h"
#include "widgets/pikatooloptionseditor.h"
#include "widgets/pikauimanager.h"
#include "widgets/pikawidgets-utils.h"

#include "display/pikadisplay.h"
#include "display/pikadisplayshell.h"
#include "display/pikadisplayshell-scale.h"
#include "display/pikadisplayshell-transform.h"
#include "display/pikaimagewindow.h"

#include "pikacoreapp.h"

#include "pika-app-test-utils.h"
#include "tests.h"


#define ADD_TEST(function) \
  g_test_add_data_func ("/pika-save-and-export/" #function, pika, function);


typedef gboolean (*PikaUiTestFunc) (GObject *object);


/**
 * new_file_has_no_files:
 * @data:
 *
 * Tests that the URIs are correct for a newly created image.
 **/
static void
new_file_has_no_files (gconstpointer    data)
{
  Pika      *pika  = PIKA (data);
  PikaImage *image = pika_test_utils_create_image_from_dialog (pika);

  g_assert (pika_image_get_file (image) == NULL);
  g_assert (pika_image_get_imported_file (image) == NULL);
  g_assert (pika_image_get_exported_file (image) == NULL);
}

/**
 * opened_xcf_file_files:
 * @data:
 *
 * Tests that PikaImage URIs are correct for an XCF file that has just
 * been opened.
 **/
static void
opened_xcf_file_files (gconstpointer data)
{
  Pika              *pika = PIKA (data);
  PikaImage         *image;
  GFile             *file;
  gchar             *filename;
  PikaPDBStatusType  status;

  filename = g_build_filename (g_getenv ("PIKA_TESTING_ABS_TOP_SRCDIR"),
                               "app/tests/files/pika-2-6-file.xcf",
                               NULL);
  file = g_file_new_for_path (filename);
  g_free (filename);

  image = file_open_image (pika,
                           pika_get_user_context (pika),
                           NULL /*progress*/,
                           file,
                           FALSE /*as_new*/,
                           NULL /*file_proc*/,
                           PIKA_RUN_NONINTERACTIVE,
                           &status,
                           NULL /*mime_type*/,
                           NULL /*error*/);

  g_assert (g_file_equal (pika_image_get_file (image), file));
  g_assert (pika_image_get_imported_file (image) == NULL);
  g_assert (pika_image_get_exported_file (image) == NULL);

  g_object_unref (file);
}

/**
 * imported_file_files:
 * @data:
 *
 * Tests that URIs are correct for an imported image.
 **/
static void
imported_file_files (gconstpointer data)
{
  Pika              *pika = PIKA (data);
  PikaImage         *image;
  GFile             *file;
  gchar             *filename;
  PikaPDBStatusType  status;

  filename = g_build_filename (g_getenv ("PIKA_TESTING_ABS_TOP_SRCDIR"),
                               "desktop/64x64/pika.png",
                               NULL);
  g_assert (g_file_test (filename, G_FILE_TEST_EXISTS));
  file = g_file_new_for_path (filename);
  g_free (filename);

  image = file_open_image (pika,
                           pika_get_user_context (pika),
                           NULL /*progress*/,
                           file,
                           FALSE /*as_new*/,
                           NULL /*file_proc*/,
                           PIKA_RUN_NONINTERACTIVE,
                           &status,
                           NULL /*mime_type*/,
                           NULL /*error*/);

  g_assert (pika_image_get_file (image) == NULL);
  g_assert (g_file_equal (pika_image_get_imported_file (image), file));
  g_assert (pika_image_get_exported_file (image) == NULL);

  g_object_unref (file);
}

/**
 * saved_imported_file_files:
 * @data:
 *
 * Tests that the URIs are correct for an image that has been imported
 * and then saved.
 **/
static void
saved_imported_file_files (gconstpointer data)
{
  Pika                *pika = PIKA (data);
  PikaImage           *image;
  GFile               *import_file;
  gchar               *import_filename;
  GFile               *save_file;
  gchar               *save_filename;
  PikaPDBStatusType    status;
  PikaPlugInProcedure *proc;

  import_filename = g_build_filename (g_getenv ("PIKA_TESTING_ABS_TOP_SRCDIR"),
                                      "desktop/64x64/pika.png",
                                      NULL);
  import_file = g_file_new_for_path (import_filename);
  g_free (import_filename);

  save_filename = g_build_filename (g_get_tmp_dir (), "pika-test.xcf", NULL);
  save_file = g_file_new_for_path (save_filename);
  g_free (save_filename);

  /* Import */
  image = file_open_image (pika,
                           pika_get_user_context (pika),
                           NULL /*progress*/,
                           import_file,
                           FALSE /*as_new*/,
                           NULL /*file_proc*/,
                           PIKA_RUN_NONINTERACTIVE,
                           &status,
                           NULL /*mime_type*/,
                           NULL /*error*/);

  g_object_unref (import_file);

  /* Save */
  proc = pika_plug_in_manager_file_procedure_find (image->pika->plug_in_manager,
                                                   PIKA_FILE_PROCEDURE_GROUP_SAVE,
                                                   save_file,
                                                   NULL /*error*/);
  file_save (pika,
             image,
             NULL /*progress*/,
             save_file,
             proc,
             PIKA_RUN_NONINTERACTIVE,
             TRUE /*change_saved_state*/,
             FALSE /*export_backward*/,
             FALSE /*export_forward*/,
             NULL /*error*/);

  /* Assert */
  g_assert (g_file_equal (pika_image_get_file (image), save_file));
  g_assert (pika_image_get_imported_file (image) == NULL);
  g_assert (pika_image_get_exported_file (image) == NULL);

  g_file_delete (save_file, NULL, NULL);
  g_object_unref (save_file);
}

/**
 * exported_file_files:
 * @data:
 *
 * Tests that the URIs for an exported, newly created file are
 * correct.
 **/
static void
exported_file_files (gconstpointer data)
{
  GFile               *save_file;
  gchar               *save_filename;
  PikaPlugInProcedure *proc;
  Pika                *pika  = PIKA (data);
  PikaImage           *image = pika_test_utils_create_image_from_dialog (pika);

  save_filename = g_build_filename (g_get_tmp_dir (), "pika-test.png", NULL);
  save_file = g_file_new_for_path (save_filename);
  g_free (save_filename);

  proc = pika_plug_in_manager_file_procedure_find (image->pika->plug_in_manager,
                                                   PIKA_FILE_PROCEDURE_GROUP_EXPORT,
                                                   save_file,
                                                   NULL /*error*/);
  file_save (pika,
             image,
             NULL /*progress*/,
             save_file,
             proc,
             PIKA_RUN_NONINTERACTIVE,
             FALSE /*change_saved_state*/,
             FALSE /*export_backward*/,
             TRUE /*export_forward*/,
             NULL /*error*/);

  g_assert (pika_image_get_file (image) == NULL);
  g_assert (pika_image_get_imported_file (image) == NULL);
  g_assert (g_file_equal (pika_image_get_exported_file (image), save_file));

  g_file_delete (save_file, NULL, NULL);
  g_object_unref (save_file);
}

/**
 * clear_import_file_after_export:
 * @data:
 *
 * Tests that after a XCF file that was imported has been exported,
 * the import URI is cleared. An image can not be considered both
 * imported and exported at the same time.
 **/
static void
clear_import_file_after_export (gconstpointer data)
{
  Pika                *pika = PIKA (data);
  PikaImage           *image;
  GFile               *file;
  gchar               *filename;
  GFile               *save_file;
  gchar               *save_filename;
  PikaPlugInProcedure *proc;
  PikaPDBStatusType    status;

  filename = g_build_filename (g_getenv ("PIKA_TESTING_ABS_TOP_SRCDIR"),
                               "desktop/64x64/pika.png",
                               NULL);
  file = g_file_new_for_path (filename);
  g_free (filename);

  image = file_open_image (pika,
                           pika_get_user_context (pika),
                           NULL /*progress*/,
                           file,
                           FALSE /*as_new*/,
                           NULL /*file_proc*/,
                           PIKA_RUN_NONINTERACTIVE,
                           &status,
                           NULL /*mime_type*/,
                           NULL /*error*/);

  g_assert (pika_image_get_file (image) == NULL);
  g_assert (g_file_equal (pika_image_get_imported_file (image), file));
  g_assert (pika_image_get_exported_file (image) == NULL);

  g_object_unref (file);

  save_filename = g_build_filename (g_get_tmp_dir (), "pika-test.png", NULL);
  save_file = g_file_new_for_path (save_filename);
  g_free (save_filename);

  proc = pika_plug_in_manager_file_procedure_find (image->pika->plug_in_manager,
                                                   PIKA_FILE_PROCEDURE_GROUP_EXPORT,
                                                   save_file,
                                                   NULL /*error*/);
  file_save (pika,
             image,
             NULL /*progress*/,
             save_file,
             proc,
             PIKA_RUN_NONINTERACTIVE,
             FALSE /*change_saved_state*/,
             FALSE /*export_backward*/,
             TRUE /*export_forward*/,
             NULL /*error*/);

  g_assert (pika_image_get_file (image) == NULL);
  g_assert (pika_image_get_imported_file (image) == NULL);
  g_assert (g_file_equal (pika_image_get_exported_file (image), save_file));

  g_file_delete (save_file, NULL, NULL);
  g_object_unref (save_file);
}

int
main(int    argc,
     char **argv)
{
  Pika *pika   = NULL;
  gint  result = -1;

  pika_test_bail_if_no_display ();
  gtk_test_init (&argc, &argv, NULL);

  pika_test_utils_setup_menus_path ();

  /* Start up PIKA */
  pika = pika_init_for_gui_testing (TRUE /*show_gui*/);
  pika_test_run_mainloop_until_idle ();

  ADD_TEST (new_file_has_no_files);
  ADD_TEST (opened_xcf_file_files);
  ADD_TEST (imported_file_files);
  ADD_TEST (saved_imported_file_files);
  ADD_TEST (exported_file_files);
  ADD_TEST (clear_import_file_after_export);

  /* Run the tests and return status */
  g_application_run (pika->app, 0, NULL);
  result = pika_core_app_get_exit_status (PIKA_CORE_APP (pika->app));

  g_application_quit (G_APPLICATION (pika->app));
  g_clear_object (&pika->app);

  return result;
}
