/*
 *  $Id: gwyapp.c 30115 2026-06-22 15:10:37Z yeti-dn $
 *  Copyright (C) 2025 David Necas (Yeti).
 *  E-mail: yeti@gwyddion.net.
 *
 *  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 2 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, write to the
 *  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "config.h"
#include <string.h>
#include <stdarg.h>
#include <math.h>
#include <gtk/gtk.h>

#include "libgwyddion/gwyddion.h"
#include "libgwyui/gwyui.h"
#include "libgwyapp/gwyapp.h"

#include "libgwyapp/internal.h"

/**
 * gwy_app_init_widget_styles:
 * @screen: Gdk screen to set the styles for.
 *
 * Sets up style properties for special Gwyddion widgets.
 *
 * Usually it is done as a part of gwy_app_init(). It exists for the case when you need to do the initialisation steps
 * separately.
 **/
void
gwy_app_init_widget_styles(GdkScreen *screen)
{
    /* TODO GTK3: use CSS theming as needed. It does not seem we use toolboxheader and cornerbutton anywhere.
     * But toolboxmenubar and toolboxbutton are used. */
#if 0
    static const gchar gwyrcstyle[] =
        /* data window corner buttons */
        "style \"cornerbutton\" {\n"
        "GtkButton::focus_line_width = 0\n"
        "GtkButton::focus_padding = 0\n"
        "}\n"
        "widget \"*.cornerbutton\" style \"cornerbutton\"\n"
        "\n"
        /* toolbox group header buttons */
        "style \"toolboxheader\" {\n"
        "GtkButton::focus_line_width = 0\n"
        "GtkButton::focus_padding = 0\n"
        "}\n"
        "widget \"*.toolboxheader\" style \"toolboxheader\"\n"
        "\n"
        /* toolbox single-item menubars */
        "style \"toolboxmenubar\" {\n"
        "GtkMenuBar::shadow_type = 0\n"
        "}\n"
        "widget \"*.toolboxmenubar\" style \"toolboxmenubar\"\n"
        "\n"
        /* toolbox buttons (XXX: perhaps we would like to inherit the style for
         * toolbar buttons, but I am unable to extract the right style using
         * gtk_rc_get_style_by_paths() and gtk_style_get()...) */
        "style \"toolboxbutton\" {\n"
        "GtkButton::inner_border = {1, 1, 2, 2}\n"
        "}\n"
        "widget \"*.toolboxbutton\" style \"toolboxbutton\"\n"
        "\n";

    gtk_rc_parse_string(gwyrcstyle);
#endif
    static const gchar gwycssstyle[] =
        "progressbar trough {\n"
        "    min-height: 3.2ex;\n"
        "}\n"
        "progressbar trough progress {\n"
        "    min-height: 3ex;\n"
        "}\n"
        "\n";
    static GtkCssProvider *provider = NULL;

    if (!provider) {
        provider = gtk_css_provider_new();
        gtk_css_provider_load_from_data(provider, gwycssstyle, sizeof(gwycssstyle)-1, NULL);
    }
    gtk_style_context_add_provider_for_screen(screen, GTK_STYLE_PROVIDER(provider),
                                              GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}

/**
 * gwy_app_init:
 * @for_gui: %TRUE to do initialisation suitable for a GUI program; %FALSE for a non-GUI program.
 * @option: Name of the first initialisation option, or %NULL if there are no options.
 * @...: Value of the first option, if any, followed by another option name and value, etc.  Terminated by %NULL.
 *
 * Performs common initialisations useful for programs utilising Gwyddion libraries.
 *
 * Regardless of the value of @for_gui, the function initialises gwyddion libraries, loads resources, loads settings
 * and imports modules (see below for pygwy). It also disables undo and GUI for the data browser as they are unlikely
 * to be useful outside Gwyddion itself.
 *
 * If @for_gui is %TRUE the function initialises GTK+ as follows
 *
 * |[
 * gtk_init(NULL, NULL);
 * ]|
 *
 * GUI programs which wish to initialise GTK+ differently need to call gtk_init() or some other GTK+ initialisation
 * function explicitly prior to calling gwy_app_init(), making the default call no-op. It also sets up
 * Gwyddion-specific widget styles.
 *
 * If @for_gui is %FALSE the function sets up logging to console (see also below) and does additional setup for for
 * non-GUI operation. In particular, it disables GUI for waiting.
 *
 * There are currently the following options:
 *
 * "enable-threads" with #gboolean value. If %TRUE or %FALSE is passed gwy_threads_set_enabled() will be called with
 * this settings. By default, the multithread processing state is unchanged.
 *
 * "enable-pygwy" with #gboolean value. If %TRUE is passed then pygwy will not be prevented from loading.  Passing
 * %FALSE is the same as not setting the option at all and will result in pygwy being prevented from loading using
 * gwy_module_disable_registration().
 *
 * "no-logging-setup" with #gboolean value. If %TRUE is passed then logging setup is unchanged. Passing %FALSE is the
 * same as not setting the option at all and will set up logging to console in non-GUI mode.
 *
 * So, for instance a program non-GUI wanting to enable multithread processing in Gwyddion functions (provided it is
 * built in) can run
 *
 * |[
 * gwy_app_init(FALSE, "enable-threads", TRUE, NULL);
 * ]|
 **/
void
gwy_app_init(gboolean for_gui,
             const gchar *option,
             ...)
{
    gboolean want_threads = FALSE, want_threads_set = FALSE;
    gboolean want_pygwy = FALSE, want_pygwy_set = FALSE;
    gboolean prevent_logging_setup = FALSE;
    va_list ap;
    gchar *settings_file;
    gchar **module_dirs;

    va_start(ap, option);
    while (option) {
        if (gwy_strequal(option, "enable-threads")) {
            want_threads = va_arg(ap, gint);
            want_threads_set = TRUE;
        }
        else if (gwy_strequal(option, "enable-pygwy")) {
            want_pygwy = va_arg(ap, gint);
            want_pygwy_set = TRUE;
        }
        else if (gwy_strequal(option, "no-logging-setup")) {
            prevent_logging_setup = va_arg(ap, gint);
        }
        else {
            g_warning("Unknown init option %s.\n", option);
            break;
        }
        option = va_arg(ap, const gchar*);
    }
    va_end(ap);

    if (for_gui || !prevent_logging_setup)
        gwy_app_setup_logging(GWY_APP_LOGGING_TO_CONSOLE);

    if (for_gui)
        gtk_init(NULL, NULL);

    gwy_ui_init();
    g_type_class_peek(GWY_TYPE_FILE);
    if (want_threads_set)
        gwy_threads_set_enabled(want_threads);

    if (!want_pygwy_set || !want_pygwy)
        gwy_module_disable_registration("pygwy");

    gwy_undo_set_enabled(for_gui);
    gwy_data_browser_set_gui_enabled(for_gui);
    gwy_app_wait_set_enabled(for_gui);
    if (for_gui) {
        gwy_app_init_widget_styles(gdk_screen_get_default());
    }
    else {
    }

    /* Register resources */
    gwy_load_resources();

    /* Load settings */
    settings_file = gwy_app_settings_get_settings_filename();
    if (g_file_test(settings_file, G_FILE_TEST_IS_REGULAR))
        gwy_app_settings_load(settings_file, NULL);
    g_free(settings_file);
    gwy_app_settings_get();

    /* Register modules */
    module_dirs = gwy_app_settings_get_module_dirs();
    for (guint i = 0; module_dirs && module_dirs[i]; i++) {
        gwy_module_register_modules(module_dirs[i], NULL);
        g_free(module_dirs[i]);
    }
    g_free(module_dirs);

    /* The Python initialisation somehow overrides SIGINT and Gwyddion can no longer be terminated with Ctrl-C.  Fix
     * it. Reset the signal regardless of pygwy state, for predictability. */
    signal(SIGINT, SIG_DFL);
}

/**
 * SECTION: gwyapp
 * @title: gwyapp
 * @short_description: Base functions, library initialisation
 *
 * Gwyddion classes has to be initialised before they can be safely deserialised. The function gwy_type_init()
 * performs this initialisation alongside with loading of settings, resources and modules.
 **/

/* vim: set cin columns=120 tw=118 et ts=4 sw=4 cino=>1s,e0,n0,f0,{0,}0,^0,\:1s,=0,g1s,h0,t0,+1s,c3,(0,u0 : */
