/* 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 <libpika/pika.h>

#include "console/script-fu-console.h"
#include "script-fu-eval.h"
#include "script-fu-text-console.h"

#include "libscriptfu/script-fu-lib.h"
#include "libscriptfu/script-fu-intl.h"


#define SCRIPT_FU_TYPE (script_fu_get_type ())
G_DECLARE_FINAL_TYPE (ScriptFu, script_fu, SCRIPT, FU, PikaPlugIn)

struct _ScriptFu
{
  PikaPlugIn      parent_instance;
};

static GList          * script_fu_query_procedures (PikaPlugIn           *plug_in);
static PikaProcedure  * script_fu_create_procedure (PikaPlugIn           *plug_in,
                                                    const gchar          *name);

static PikaValueArray * script_fu_run              (PikaProcedure        *procedure,
                                                    PikaProcedureConfig  *config,
                                                    gpointer              run_data);
static PikaValueArray * script_fu_batch_run        (PikaProcedure        *procedure,
                                                    PikaRunMode           run_mode,
                                                    const gchar          *code,
                                                    PikaProcedureConfig  *config,
                                                    gpointer              run_data);
static void             script_fu_run_init         (PikaProcedure        *procedure,
                                                    PikaRunMode           run_mode);
static void             script_fu_extension_init   (PikaPlugIn           *plug_in);
static PikaValueArray * script_fu_refresh_proc     (PikaProcedure        *procedure,
                                                    PikaProcedureConfig  *config,
                                                    gpointer              run_data);


G_DEFINE_TYPE (ScriptFu, script_fu, PIKA_TYPE_PLUG_IN)

PIKA_MAIN (SCRIPT_FU_TYPE)
DEFINE_STD_SET_I18N


static void
script_fu_class_init (ScriptFuClass *klass)
{
  PikaPlugInClass *plug_in_class = PIKA_PLUG_IN_CLASS (klass);

  plug_in_class->query_procedures = script_fu_query_procedures;
  plug_in_class->create_procedure = script_fu_create_procedure;
  plug_in_class->set_i18n         = STD_SET_I18N;
}

static void
script_fu_init (ScriptFu *script_fu)
{
}

static GList *
script_fu_query_procedures (PikaPlugIn *plug_in)
{
  GList *list = NULL;

  list = g_list_append (list, g_strdup ("extension-script-fu"));
  list = g_list_append (list, g_strdup ("plug-in-script-fu-console"));
  list = g_list_append (list, g_strdup ("plug-in-script-fu-text-console"));
  list = g_list_append (list, g_strdup ("plug-in-script-fu-eval"));

  return list;
}

static PikaProcedure *
script_fu_create_procedure (PikaPlugIn  *plug_in,
                            const gchar *name)
{
  PikaProcedure *procedure = NULL;

  if (! strcmp (name, "extension-script-fu"))
    {
      procedure = pika_procedure_new (plug_in, name,
                                      PIKA_PDB_PROC_TYPE_EXTENSION,
                                      script_fu_run, NULL, NULL);

      pika_procedure_set_documentation (procedure,
                                        "A scheme interpreter for scripting "
                                        "PIKA operations",
                                        "More help here later",
                                        NULL);
      pika_procedure_set_attribution (procedure,
                                      "Spencer Kimball & Peter Mattis",
                                      "Spencer Kimball & Peter Mattis",
                                      "1997");
    }
  else if (! strcmp (name, "plug-in-script-fu-console"))
    {
      procedure = pika_procedure_new (plug_in, name,
                                      PIKA_PDB_PROC_TYPE_PLUGIN,
                                      script_fu_run, NULL, NULL);

      pika_procedure_set_menu_label (procedure, _("Script-Fu _Console"));
      pika_procedure_add_menu_path (procedure,
                                    "<Image>/Filters/Development/Script-Fu");

      pika_procedure_set_documentation (procedure,
                                        _("Interactive console for Script-Fu "
                                          "development"),
                                        "Provides an interface which allows "
                                        "interactive scheme development.",
                                        name);
      pika_procedure_set_attribution (procedure,
                                      "Spencer Kimball & Peter Mattis",
                                      "Spencer Kimball & Peter Mattis",
                                      "1997");

      PIKA_PROC_ARG_ENUM (procedure, "run-mode",
                          "Run mode",
                          "The run mode",
                          PIKA_TYPE_RUN_MODE,
                          PIKA_RUN_INTERACTIVE,
                          G_PARAM_READWRITE);
      PIKA_PROC_AUX_ARG_STRV (procedure, "history",
                              "Command history",
                              "History",
                              G_PARAM_READWRITE);
    }
  else if (! strcmp (name, "plug-in-script-fu-text-console"))
    {
      procedure = pika_procedure_new (plug_in, name,
                                      PIKA_PDB_PROC_TYPE_PLUGIN,
                                      script_fu_run, NULL, NULL);

      pika_procedure_set_documentation (procedure,
                                        "Provides a text console mode for "
                                        "script-fu development",
                                        "Provides an interface which allows "
                                        "interactive scheme development.",
                                        name);
      pika_procedure_set_attribution (procedure,
                                      "Spencer Kimball & Peter Mattis",
                                      "Spencer Kimball & Peter Mattis",
                                      "1997");

      PIKA_PROC_ARG_ENUM (procedure, "run-mode",
                          "Run mode",
                          "The run mode",
                          PIKA_TYPE_RUN_MODE,
                          PIKA_RUN_INTERACTIVE,
                          G_PARAM_READWRITE);
    }
  else if (! strcmp (name, "plug-in-script-fu-eval"))
    {
      procedure = pika_batch_procedure_new (plug_in, name, "Script-fu (scheme)",
                                            PIKA_PDB_PROC_TYPE_PLUGIN,
                                            script_fu_batch_run, NULL, NULL);

      pika_procedure_set_documentation (procedure,
                                        "Evaluate scheme code",
                                        "Evaluate the code under the scheme "
                                        "interpreter (primarily for batch mode)",
                                        name);
      pika_procedure_set_attribution (procedure,
                                      "Manish Singh",
                                      "Manish Singh",
                                      "1998");
    }

  return procedure;
}

static PikaValueArray *
script_fu_run (PikaProcedure        *procedure,
               PikaProcedureConfig  *config,
               gpointer              run_data)
{
  PikaPlugIn     *plug_in     = pika_procedure_get_plug_in (procedure);
  const gchar    *name        = pika_procedure_get_name (procedure);
  PikaValueArray *return_vals = NULL;
  PikaRunMode     run_mode    = PIKA_RUN_NONINTERACTIVE;

  if (g_object_class_find_property (G_OBJECT_GET_CLASS (config), "run-mode") != NULL)
    g_object_get (config, "run-mode", &run_mode, NULL);
  script_fu_run_init (procedure, run_mode);

  if (strcmp (name, "extension-script-fu") == 0)
    {
      /*
       *  The main script-fu extension.
       */

      /*  Acknowledge that the extension is properly initialized  */
      pika_procedure_extension_ready (procedure);

      /*  Go into an endless loop  */
      while (TRUE)
        pika_plug_in_extension_process (plug_in, 0);
    }
  else if (strcmp (name, "plug-in-script-fu-text-console") == 0)
    {
      /*
       *  The script-fu text console for interactive Scheme development
       */

      return_vals = script_fu_text_console_run (procedure, config);
    }
  else if (strcmp (name, "plug-in-script-fu-console") == 0)
    {
      /*
       *  The script-fu console for interactive Scheme development
       */

      return_vals = script_fu_console_run (procedure, config);
    }

  if (! return_vals)
    return_vals = pika_procedure_new_return_values (procedure,
                                                    PIKA_PDB_SUCCESS,
                                                    NULL);

  return return_vals;
}

static PikaValueArray *
script_fu_batch_run (PikaProcedure        *procedure,
                     PikaRunMode           run_mode,
                     const gchar          *code,
                     PikaProcedureConfig  *config,
                     gpointer              run_data)
{
  const gchar    *name        = pika_procedure_get_name (procedure);
  PikaValueArray *return_vals = NULL;

  script_fu_run_init (procedure, run_mode);

  if (strcmp (name, "plug-in-script-fu-eval") == 0)
    {
      /*
       *  A non-interactive "console" (for batch mode)
       */

      if (g_strcmp0 (code, "-") == 0)
        /* Redirecting to script-fu text console, for backward compatibility  */
        return_vals = script_fu_text_console_run (procedure, config);
      else
        return_vals = script_fu_eval_run (procedure, run_mode, code, config);
    }

  if (! return_vals)
    return_vals = pika_procedure_new_return_values (procedure,
                                                    PIKA_PDB_SUCCESS,
                                                    NULL);

  return return_vals;
}

static void
script_fu_run_init (PikaProcedure *procedure,
                    PikaRunMode    run_mode)
{
  PikaPlugIn     *plug_in     = pika_procedure_get_plug_in (procedure);
  const gchar    *name        = pika_procedure_get_name (procedure);
  GList          *path;

  path = script_fu_search_path ();

  /*  Determine before we allow scripts to register themselves
   *   whether this is the base, automatically installed script-fu extension
   */
  if (strcmp (name, "extension-script-fu") == 0)
    {
      /*  Setup auxiliary temporary procedures for the base extension  */
      script_fu_extension_init (plug_in);

      /*  Init the interpreter, allow register scripts */
      script_fu_init_embedded_interpreter (path, TRUE, run_mode);
    }
  else
    {
      /*  Init the interpreter, not allow register scripts */
      script_fu_init_embedded_interpreter (path, FALSE, run_mode);
    }

  script_fu_find_and_register_scripts (plug_in, path);

  g_list_free_full (path, (GDestroyNotify) g_object_unref);
}

static void
script_fu_extension_init (PikaPlugIn *plug_in)
{
  PikaProcedure *procedure;

  pika_plug_in_add_menu_branch (plug_in, "<Image>/Help", N_("_PIKA Online"));
  pika_plug_in_add_menu_branch (plug_in, "<Image>/Help", N_("_User Manual"));

  pika_plug_in_add_menu_branch (plug_in, "<Image>/Filters/Development",
                                N_("_Script-Fu"));
  pika_plug_in_add_menu_branch (plug_in, "<Image>/Filters/Development/Script-Fu",
                                N_("_Test"));

  pika_plug_in_add_menu_branch (plug_in, "<Image>/File/Create",
                                N_("_Buttons"));
  pika_plug_in_add_menu_branch (plug_in, "<Image>/File/Create",
                                N_("_Logos"));
  pika_plug_in_add_menu_branch (plug_in, "<Image>/File/Create",
                                N_("_Patterns"));

  pika_plug_in_add_menu_branch (plug_in, "<Image>/File/Create",
                                N_("_Web Page Themes"));
  pika_plug_in_add_menu_branch (plug_in, "<Image>/File/Create/Web Page Themes",
                                N_("_Alien Glow"));
  pika_plug_in_add_menu_branch (plug_in, "<Image>/File/Create/Web Page Themes",
                                N_("_Beveled Pattern"));
  pika_plug_in_add_menu_branch (plug_in, "<Image>/File/Create/Web Page Themes",
                                N_("_Classic.Pika.Org"));

  pika_plug_in_add_menu_branch (plug_in, "<Image>/Filters",
                                N_("Alpha to _Logo"));

  procedure = pika_procedure_new (plug_in, "script-fu-refresh",
                                  PIKA_PDB_PROC_TYPE_TEMPORARY,
                                  script_fu_refresh_proc, NULL, NULL);

  pika_procedure_set_menu_label (procedure, _("_Refresh Scripts"));
  pika_procedure_add_menu_path (procedure,
                                "<Image>/Filters/Development/Script-Fu");

  pika_procedure_set_documentation (procedure,
                                    _("Re-read all available Script-Fu scripts"),
                                    "Re-read all available Script-Fu scripts",
                                    "script-fu-refresh");
  pika_procedure_set_attribution (procedure,
                                  "Spencer Kimball & Peter Mattis",
                                  "Spencer Kimball & Peter Mattis",
                                  "1997");

  PIKA_PROC_ARG_ENUM (procedure, "run-mode",
                      "Run mode",
                      "The run mode",
                      PIKA_TYPE_RUN_MODE,
                      PIKA_RUN_INTERACTIVE,
                      G_PARAM_READWRITE);

  pika_plug_in_add_temp_procedure (plug_in, procedure);
  g_object_unref (procedure);
}

static PikaValueArray *
script_fu_refresh_proc (PikaProcedure        *procedure,
                        PikaProcedureConfig  *config,
                        gpointer              run_data)
{
  if (script_fu_extension_is_busy ())
    {
      g_message (_("You can not use \"Refresh Scripts\" while a "
                   "Script-Fu dialog box is open.  Please close "
                   "all Script-Fu windows and try again."));

      return pika_procedure_new_return_values (procedure,
                                               PIKA_PDB_EXECUTION_ERROR,
                                               NULL);
    }
  else
    {
      /*  Reload all of the available scripts  */
      GList *path = script_fu_search_path ();

      script_fu_find_and_register_scripts (pika_procedure_get_plug_in (procedure), path);

      g_list_free_full (path, (GDestroyNotify) g_object_unref);
    }

  return pika_procedure_new_return_values (procedure, PIKA_PDB_SUCCESS, NULL);
}
