/* 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
 *
 * The PIKA Help plug-in
 * Copyright (C) 1999-2008 Sven Neumann <sven@gimp.org>
 *                         Michael Natterer <mitch@gimp.org>
 *                         Henrik Brix Andersen <brix@gimp.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 <string.h>  /*  strlen  */

#include <glib.h>

#include "libpika/pika.h"

#include "pikahelp.h"

#include "libpika/stdplugins-intl.h"


/*  defines  */

#define PIKA_HELP_EXT_PROC        "extension-pika-help"
#define PIKA_HELP_TEMP_EXT_PROC   "extension-pika-help-temp"


typedef struct _Help      Help;
typedef struct _HelpClass HelpClass;

struct _Help
{
  PikaPlugIn parent_instance;
};

struct _HelpClass
{
  PikaPlugInClass parent_class;
};

typedef struct
{
  gchar *procedure;
  gchar *help_domain;
  gchar *help_locales;
  gchar *help_id;
} IdleHelp;


/*  forward declarations  */

#define HELP_TYPE  (help_get_type ())
#define HELP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), HELP_TYPE, Help))

GType                   help_get_type          (void) G_GNUC_CONST;

static GList          * help_query_procedures  (PikaPlugIn           *plug_in);
static PikaProcedure  * help_create_procedure  (PikaPlugIn           *plug_in,
                                                const gchar          *name);

static PikaValueArray * help_run               (PikaProcedure        *procedure,
                                                PikaProcedureConfig  *config,
                                                gpointer              run_data);
static PikaValueArray * help_temp_run          (PikaProcedure        *procedure,
                                                PikaProcedureConfig  *config,
                                                gpointer              run_data);

static void             help_temp_proc_install (PikaPlugIn           *plug_in);
static void             help_load              (const gchar          *procedure,
                                                const gchar          *help_domain,
                                                const gchar          *help_locales,
                                                const gchar          *help_id);
static gboolean         help_load_idle         (gpointer              data);

static PikaHelpProgress * help_load_progress_new (void);


static GMainLoop *main_loop = NULL;

G_DEFINE_TYPE (Help, help, PIKA_TYPE_PLUG_IN)

PIKA_MAIN (HELP_TYPE)
DEFINE_STD_SET_I18N


static void
help_class_init (HelpClass *klass)
{
  PikaPlugInClass *plug_in_class = PIKA_PLUG_IN_CLASS (klass);

  plug_in_class->query_procedures = help_query_procedures;
  plug_in_class->create_procedure = help_create_procedure;
  plug_in_class->set_i18n         = STD_SET_I18N;
}

static void
help_init (Help *help)
{
}

static GList *
help_query_procedures (PikaPlugIn *plug_in)
{
  return g_list_append (NULL, g_strdup (PIKA_HELP_EXT_PROC));
}

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

  if (! strcmp (name, PIKA_HELP_EXT_PROC))
    {
      procedure = pika_procedure_new (plug_in, name,
                                      PIKA_PDB_PROC_TYPE_EXTENSION,
                                      help_run, NULL, NULL);

      pika_procedure_set_attribution (procedure,
                                      "Sven Neumann <sven@gimp.org>, "
                                      "Michael Natterer <mitch@gimp.org>, "
                                      "Henrik Brix Andersen <brix@gimp.org>",
                                      "Sven Neumann, Michael Natterer & Henrik Brix Andersen",
                                      "1999-2008");

      PIKA_PROC_ARG_STRV (procedure, "domain-names",
                          "Domain Names",
                          "Domain names",
                          G_PARAM_READWRITE);

      PIKA_PROC_ARG_STRV (procedure, "domain-uris",
                          "Domain URIs",
                          "Domain URIs",
                          G_PARAM_READWRITE);
    }

  return procedure;
}

static PikaValueArray *
help_run (PikaProcedure        *procedure,
          PikaProcedureConfig  *config,
          gpointer              run_data)
{
  PikaPDBStatusType   status       = PIKA_PDB_SUCCESS;
  gchar             **domain_names = NULL;
  gchar             **domain_uris  = NULL;

  g_object_get (config,
                "domain-names", &domain_names,
                "domain-uris",  &domain_uris,
                NULL);
  if (! pika_help_init ((const gchar **) domain_names,
                        (const gchar **) domain_uris))
    status = PIKA_PDB_CALLING_ERROR;

  g_strfreev (domain_names);
  g_strfreev (domain_uris);

  if (status == PIKA_PDB_SUCCESS)
    {
      PikaPlugIn *plug_in = pika_procedure_get_plug_in (procedure);

      main_loop = g_main_loop_new (NULL, FALSE);

      help_temp_proc_install (plug_in);

      pika_procedure_extension_ready (procedure);
      pika_plug_in_extension_enable (plug_in);

      g_main_loop_run (main_loop);

      g_main_loop_unref (main_loop);
      main_loop = NULL;

      pika_plug_in_remove_temp_procedure (plug_in, PIKA_HELP_TEMP_EXT_PROC);
    }

  return pika_procedure_new_return_values (procedure, status, NULL);
}

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

  procedure = pika_procedure_new (plug_in, PIKA_HELP_TEMP_EXT_PROC,
                                  PIKA_PDB_PROC_TYPE_TEMPORARY,
                                  help_temp_run, NULL, NULL);

  pika_procedure_set_attribution (procedure,
                                  "Sven Neumann <sven@gimp.org>, "
                                  "Michael Natterer <mitch@gimp.org>"
                                  "Henrik Brix Andersen <brix@gimp.org",
                                  "Sven Neumann, Michael Natterer & "
                                  "Henrik Brix Andersen",
                                  "1999-2008");

  PIKA_PROC_ARG_STRING (procedure, "help-proc",
                        "The procedure of the browser to use",
                        "The procedure of the browser to use",
                        NULL,
                        G_PARAM_READWRITE);

  PIKA_PROC_ARG_STRING (procedure, "help-domain",
                        "Help domain to use",
                        "Help domain to use",
                        NULL,
                        G_PARAM_READWRITE);

  PIKA_PROC_ARG_STRING (procedure, "help-locales",
                        "Language to use",
                        "Language to use",
                        NULL,
                        G_PARAM_READWRITE);

  PIKA_PROC_ARG_STRING (procedure, "help-id",
                        "Help ID to open",
                        "Help ID to open",
                        NULL,
                        G_PARAM_READWRITE);

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

static PikaValueArray *
help_temp_run (PikaProcedure        *procedure,
               PikaProcedureConfig  *config,
               gpointer              run_data)
{
  PikaPDBStatusType  status       = PIKA_PDB_SUCCESS;
  gchar             *help_proc    = NULL;
  gchar             *help_domain  = NULL;
  gchar             *help_locales = NULL;
  gchar             *help_id      = NULL;

  g_object_get (config,
                "help-proc",    &help_proc,
                "help-domain",  &help_domain,
                "help-locales", &help_locales,
                "help-id",      &help_id,
                NULL);

  if (help_domain == NULL)
    help_domain = g_strdup (PIKA_HELP_DEFAULT_DOMAIN);

  if (help_id == NULL)
    help_id = g_strdup (PIKA_HELP_DEFAULT_ID);

  if (! help_proc)
    status = PIKA_PDB_CALLING_ERROR;

  if (status == PIKA_PDB_SUCCESS)
    help_load (help_proc, help_domain, help_locales, help_id);

  g_free (help_proc);
  g_free (help_domain);
  g_free (help_locales);
  g_free (help_id);

  return pika_procedure_new_return_values (procedure, status, NULL);
}

static void
help_load (const gchar *procedure,
           const gchar *help_domain,
           const gchar *help_locales,
           const gchar *help_id)
{
  IdleHelp *idle_help = g_slice_new (IdleHelp);

  idle_help->procedure    = g_strdup (procedure);
  idle_help->help_domain  = g_strdup (help_domain);
  idle_help->help_locales = g_strdup (help_locales);
  idle_help->help_id      = g_strdup (help_id);

  g_idle_add (help_load_idle, idle_help);
}

static gboolean
help_load_idle (gpointer data)
{
  IdleHelp       *idle_help = data;
  PikaHelpDomain *domain;

  domain = pika_help_lookup_domain (idle_help->help_domain);

  if (domain)
    {
      PikaHelpProgress *progress = NULL;
      GList            *locales;
      gchar            *uri;
      gboolean          fatal_error;

      locales = pika_help_parse_locales (idle_help->help_locales);

      if (! g_str_has_prefix (domain->help_uri, "file:"))
        progress = help_load_progress_new ();

      uri = pika_help_domain_map (domain, locales, idle_help->help_id,
                                  progress, NULL, &fatal_error);

      if (progress)
        pika_help_progress_free (progress);

      g_list_free_full (locales, (GDestroyNotify) g_free);

      if (uri)
        {
          PikaProcedure  *procedure;
          PikaValueArray *return_vals;

#ifdef PIKA_HELP_DEBUG
          g_printerr ("help: calling '%s' for '%s'\n",
                      idle_help->procedure, uri);
#endif

          procedure   = pika_pdb_lookup_procedure (pika_get_pdb (),
                                                   idle_help->procedure);
          return_vals = pika_procedure_run (procedure, "domain-names", uri, NULL);
          pika_value_array_unref (return_vals);

          g_free (uri);
        }
      else if (fatal_error)
        {
          g_main_loop_quit (main_loop);
        }
    }

  g_free (idle_help->procedure);
  g_free (idle_help->help_domain);
  g_free (idle_help->help_locales);
  g_free (idle_help->help_id);

  g_slice_free (IdleHelp, idle_help);

  return FALSE;
}

static void
help_load_progress_start (const gchar *message,
                          gboolean     cancelable,
                          gpointer     user_data)
{
  pika_progress_init (message);
}

static void
help_load_progress_update (gdouble  value,
                           gpointer user_data)
{
  pika_progress_update (value);
}

static void
help_load_progress_end (gpointer user_data)
{
  pika_progress_end ();
}

static PikaHelpProgress *
help_load_progress_new (void)
{
  static const PikaHelpProgressVTable vtable =
  {
    help_load_progress_start,
    help_load_progress_end,
    help_load_progress_update
  };

  return pika_help_progress_new (&vtable, NULL);
}
