/* 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 <string.h>
#include <glib.h>

#include <libpika/pika.h>

#include "scheme-wrapper.h"       /* type "pointer" */

#include "script-fu-types.h"
#include "script-fu-interface.h"  /* ScriptFu's GUI implementation. */
#include "script-fu-dialog.h"     /* Pika's GUI implementation. */
#include "script-fu-script.h"
#include "script-fu-scripts.h"    /* script_fu_find_script */
#include "script-fu-command.h"

#include "script-fu-run-func.h"

/* Outer run_funcs
 * One each for PikaProcedure and PikaImageProcedure.
 * These are called from Gimp, with two different signatures.
 * These form and interpret "commands" which are calls to inner run_funcs
 * defined in Scheme by a script.

 * These return the result of interpretation,
 * in a PikaValueArray whose only element is a status.
 * !!! ScriptFu does not let authors define procedures that return values.
 */

/* run_func for a PikaImageProcedure
 *
 * Type is PikaRunImageFunc.
 *
 * Uses Pika's config and gui.
 *
 * Since 3.0
 */
PikaValueArray *
script_fu_run_image_procedure (PikaProcedure        *procedure, /* PikaImageProcedure */
                               PikaRunMode           run_mode,
                               PikaImage            *image,
                               guint                 n_drawables,
                               PikaDrawable        **drawables,
                               PikaProcedureConfig  *config,
                               gpointer              data)
{

  PikaValueArray *result = NULL;
  SFScript       *script;

  g_debug ("script_fu_run_image_procedure");
  script = script_fu_find_script (pika_procedure_get_name (procedure));

  if (! script)
    return pika_procedure_new_return_values (procedure, PIKA_PDB_CALLING_ERROR, NULL);

  ts_set_run_mode (run_mode);

  switch (run_mode)
    {
    case PIKA_RUN_INTERACTIVE:
      {
        guint n_specs;

        g_free (g_object_class_list_properties (G_OBJECT_GET_CLASS (config), &n_specs));
        if (n_specs > 1)
          {
            /* Let user choose "other" args in a dialog, then interpret. Maintain a config. */
            result = script_fu_dialog_run (procedure, script, image, n_drawables, drawables, config);
          }
        else
          {
            /* No "other" args for user to choose. No config to maintain. */
            result = script_fu_interpret_image_proc (procedure, script, image, n_drawables, drawables, config);
          }
        break;
      }
    case PIKA_RUN_NONINTERACTIVE:
      {
        /* A call from another PDB procedure.
         * Use the given config, without interacting with user.
         * Since no user interaction, no config to maintain.
         */
        result = script_fu_interpret_image_proc (procedure, script, image, n_drawables, drawables, config);
        break;
      }
    case PIKA_RUN_WITH_LAST_VALS:
      {
        /* User invoked from a menu "Filter>Run with last values".
         * Do not show dialog. config are already last values.
         */
        result = script_fu_interpret_image_proc (procedure, script, image, n_drawables, drawables, config);
        break;
      }
    default:
      {
        result = pika_procedure_new_return_values (procedure, PIKA_PDB_CALLING_ERROR, NULL);
      }
    }

  return result;
}


/* run_func for a PikaProcedure.
 *
 * Type is PikaRunFunc
 *
 * Uses ScriptFu's own GUI implementation, and retains settings locally.
 *
 * Since prior to 3.0 but formerly named script_fu_script_proc
 */
PikaValueArray *
script_fu_run_procedure (PikaProcedure       *procedure,
                         PikaProcedureConfig *config,
                         gpointer             data)
{
  PikaPDBStatusType   status = PIKA_PDB_SUCCESS;
  SFScript           *script;
  GParamSpec        **pspecs;
  guint               n_pspecs;
  gint                n_aux_args;
  PikaRunMode         run_mode;
  GError             *error = NULL;

  script = script_fu_find_script (pika_procedure_get_name (procedure));

  if (! script)
    return pika_procedure_new_return_values (procedure,
                                             PIKA_PDB_CALLING_ERROR,
                                             NULL);

  pspecs = g_object_class_list_properties (G_OBJECT_GET_CLASS (config), &n_pspecs);
  pika_procedure_get_aux_arguments (procedure, &n_aux_args);

  g_object_get (config, "run-mode", &run_mode, NULL);

  ts_set_run_mode (run_mode);

  switch (run_mode)
    {
    case PIKA_RUN_INTERACTIVE:
      {
        gint min_args = 0;

        /*  First, try to collect the standard script arguments...  */
        min_args = script_fu_script_collect_standard_args (script, pspecs, n_pspecs, config);

        /*  ...then acquire the rest of arguments (if any) with a dialog  */
        if (script->n_args > min_args)
          {
            status = script_fu_interface (script, min_args);
            break;
          }
        /*  otherwise (if the script takes no more arguments), skip
         *  this part and run the script directly (fallthrough)
         */
      }

    case PIKA_RUN_NONINTERACTIVE:
      /* Verify actual args count equals declared arg count.
       * Scripts declare args except run_mode (SF hides it.)
       * pspecs have run_mode and one extra internal pspec, thus +2.
       */
      if (n_pspecs != script->n_args + n_aux_args + 2)
        status = PIKA_PDB_CALLING_ERROR;

      if (status == PIKA_PDB_SUCCESS)
        {
          gchar *command;

          command = script_fu_script_get_command_from_params (script, pspecs, n_pspecs, config);

          /*  run the command through the interpreter  */
          if (! script_fu_run_command (command, &error))
            {
              return pika_procedure_new_return_values (procedure,
                                                       PIKA_PDB_EXECUTION_ERROR,
                                                       error);
            }

          g_free (command);
        }
      break;

    case PIKA_RUN_WITH_LAST_VALS:
      {
        gchar *command;

        /*  First, try to collect the standard script arguments  */
        script_fu_script_collect_standard_args (script, pspecs, n_pspecs, config);

        command = script_fu_script_get_command (script);

        /*  run the command through the interpreter  */
        if (! script_fu_run_command (command, &error))
          {
            return pika_procedure_new_return_values (procedure,
                                                     PIKA_PDB_EXECUTION_ERROR,
                                                     error);
          }

        g_free (command);
      }
      break;

    default:
      break;
    }

  return pika_procedure_new_return_values (procedure, status, NULL);
}
