/*
 *  $Id: graph_dos_spectrum.c 29754 2026-04-09 09:35:42Z yeti-dn $
 *  Copyright (C) 2010-2025 David Necas (Yeti), Petr Klapetek, Daniil Bratashov
 *  E-mail: yeti@gwyddion.net, klapetek@gwyddion.net, dn2010@gmail.com
 *
 *  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 <glib/gi18n-lib.h>
#include <string.h>
#include <stdlib.h>
#include <gtk/gtk.h>
#include <gwy.h>

#define DELTA (1e-15)

static gboolean    module_register (void);
static void        module_main     (GwyGraph *graph);

static GwyModuleInfo module_info = {
    GWY_MODULE_ABI_VERSION,
    &module_register,
    N_("DOS Spectrum"),
    "Daniil Bratashov <dn2010@gmail.com>",
    "0.2",
    "David Nečas (Yeti) & Petr Klapetek & Daniil Bratashov",
    "2010",
};

GWY_MODULE_QUERY2(module_info, graph_dos_spectrum)

static gboolean
module_register(void)
{
    gwy_graph_func_register("dos_spectrum",
                            &module_main,
                            N_("/Measure _Features/_DOS Spectrum"),
                            GWY_ICON_GRAPH_DOS,
                            GWY_MENU_FLAG_GRAPH_CURVE,
                            N_("Calculate DOS spectrum from I-V tunneling spectroscopy"));

    return TRUE;
}

static void
module_main(GwyGraph *graph)
{
    GtkWidget *dialog;
    GwyFile *data;
    GwyGraphModel *gmodel, *ngmodel;
    GwyGraphCurveModel *gcmodel, *ngcmodel;
    const gdouble *xdata, *ydata;
    gdouble *nxdata, *nydata;
    guint i, j, k, ncurves, ndata, nndata;
    gchar *graphtitle, *newtitle;
    GwyUnit *siunitx, *siunity;

    gwy_data_browser_get_current(GWY_APP_FILE, &data, NULL);
    gmodel = gwy_graph_get_model(GWY_GRAPH(graph));
    g_object_get(gmodel,
                 "title", &graphtitle,
                 "unit-x", &siunitx,
                 "unit-y", &siunity,
                 NULL);

    /* Checking axis units to be voltage-current spectroscopy */
    if (!(gwy_unit_equal_string(siunitx, "V") && gwy_unit_equal_string(siunity, "A"))) {
        dialog = gtk_message_dialog_new(gwy_data_browser_get_window_for_data(data, GWY_FILE_IMAGE, -1),
                                        GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
                                        _("%s: Graph should be I-V spectroscopy."),
                                        "dos_spectrum");
        gtk_dialog_run(GTK_DIALOG(dialog));
        gtk_widget_destroy(dialog);

        g_free(graphtitle);
        g_object_unref(siunitx);
        g_object_unref(siunity);
        return;
    }
    g_object_unref(siunity);

    ngmodel = gwy_graph_model_new_alike(gmodel);

    siunity = gwy_unit_new("a.u.");
    newtitle = g_strdup_printf(_("DOS Spectrum for \"%s\""), graphtitle);

    g_object_set(ngmodel,
                 "title", newtitle,
                 "unit-y", siunity,
                 NULL);

    g_free(graphtitle);
    g_free(newtitle);
    g_object_unref(siunitx);
    g_object_unref(siunity);

    ncurves = gwy_graph_model_get_n_curves(gmodel);

    for (k = 0; k < ncurves; k++) {
        gcmodel = gwy_graph_model_get_curve(gmodel, k);

        xdata = gwy_graph_curve_model_get_xdata(gcmodel);
        ydata = gwy_graph_curve_model_get_ydata(gcmodel);
        ndata = gwy_graph_curve_model_get_n_data(gcmodel);
        nndata = ndata-1;
        for (i = 1; i < ndata; i++) {
            if (fabs(ydata[i]) < DELTA)
                nndata--;
            if (fabs(xdata[i]-xdata[i-1]) < DELTA)
                nndata--;
        }

        if (nndata == 0)
            continue;

        ngcmodel = gwy_graph_curve_model_copy(gcmodel);
        nxdata = g_new(gdouble, nndata);
        nydata = g_new(gdouble, nndata);

        j = 0;
        for (i = 1; i < ndata; i++) {
            if (fabs(ydata[i]) < DELTA)
                continue;
            if (fabs(xdata[i]-xdata[i-1]) < DELTA)
                continue;
            nxdata[j] = xdata[i];
            nydata[j] = fabs(((ydata[i]-ydata[i-1])/(xdata[i]-xdata[i-1])) * (xdata[i]/ydata[i]));
            j++;
        }


        gwy_graph_curve_model_set_data(ngcmodel, nxdata, nydata, nndata);

        gwy_graph_model_add_curve(ngmodel, ngcmodel);
        g_object_unref(ngcmodel);
    }

    gint newid = gwy_file_add_graph(data, ngmodel);
    gwy_file_set_visible(data, GWY_FILE_GRAPH, newid, TRUE);

    g_object_unref(ngmodel);
}

/* 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 : */
