/*
 *  $Id: ambfile.c 29571 2026-03-05 15:49:32Z yeti-dn $
 *  Copyright (C) 2005-2025 David Necas (Yeti), Petr Klapetek.
 *  E-mail: yeti@gwyddion.net, klapetek@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.
 */

/**
 * [FILE-MAGIC-FREEDESKTOP]
 * <mime-type type="application/x-ambios-amb">
 *   <comment>Ambios AMB data</comment>
 *   <magic priority="80">
 *     <match type="string" offset="0" value="Binary TrueMap Data File \\ Ambios File Format\r\n"/>
 *   </magic>
 *   <glob pattern="*.amb"/>
 *   <glob pattern="*.AMB"/>
 * </mime-type>
 **/

/**
 * [FILE-MAGIC-FILEMAGIC]
 * # Ambios/TrueMap surface (profiles?) data.
 * 0 string Binary\ TrueMap\ Data\ File\ \\\ Ambios\ File\ Format\x0d\x0a Ambios/TrueMap surface topography data.
 **/

/**
 * [FILE-MAGIC-USERGUIDE]
 * Ambios AMB
 * .amb
 * Read[1]
 * [1] The import module is unfinished due to the lack of documentation, testing files and/or people willing to help
 * with the testing.  If you can help please contact us.
 **/

#include "config.h"
#include <glib/gi18n-lib.h>
#include <string.h>
#include <gwy.h>

#include "err.h"
#include "get.h"

#define MAGIC "Binary TrueMap Data File \\ Ambios File Format\r\n"
#define MAGIC_SIZE (sizeof(MAGIC)-1)

#define EXTENSION ".amb"

enum {
    HEADER_SIZE = 65,
    PARAM_OFFSET = 0x31,
};

static gboolean module_register(void);
static gint     detect_file    (const GwyFileDetectInfo *fileinfo,
                                gboolean only_name);
static GwyFile* load_file      (const gchar *filename,
                                GwyRunModeFlags mode,
                                GError **error);

static GwyModuleInfo module_info = {
    GWY_MODULE_ABI_VERSION,
    &module_register,
    N_("Imports Ambios AMB data files."),
    "Yeti <yeti@gwyddion.net>",
    "0.4",
    "David Nečas (Yeti)",
    "2011",
};

GWY_MODULE_QUERY2(module_info, ambfile)

static gboolean
module_register(void)
{
    gwy_file_func_register("ambfile",
                           N_("Ambios amb files (.amb)"),
                           detect_file, load_file, NULL, NULL);
    gwy_file_func_set_is_unfinished("ambfile", TRUE);

    return TRUE;
}

static gint
detect_file(const GwyFileDetectInfo *fileinfo, gboolean only_name)
{
    if (only_name)
        return g_str_has_suffix(fileinfo->name_lowercase, EXTENSION) ? 20 : 0;

    if (fileinfo->file_size >= HEADER_SIZE
        && fileinfo->buffer_len >= MAGIC_SIZE
        && memcmp(fileinfo->head, MAGIC, MAGIC_SIZE) == 0)
        return 100;

    return 0;
}

static GwyFile*
load_file(const gchar *filename,
          G_GNUC_UNUSED GwyRunModeFlags mode,
          GError **error)
{
    GwyFile *file = NULL;
    const guchar *p, *buffer = NULL;
    gsize size = 0;
    GError *err = NULL;
    guint xres, yres;
    gdouble xreal;
    G_GNUC_UNUSED gdouble q;
    GwyField *dfield;

    if (!gwy_map_file_contents(filename, &buffer, &size, &err)) {
        err_GET_FILE_CONTENTS(error, &err);
        return NULL;
    }
    if (size <= HEADER_SIZE) {
        err_TOO_SHORT(error);
        goto fail;
    }

    /* The two bytes before are usually zeroes */
    p = buffer + PARAM_OFFSET;
    xres = gwy_get_guint32_le(&p);
    yres = gwy_get_guint32_le(&p);
    gwy_debug("xres: %u yres: %u", xres, yres);
    /* The four bytes after might be a float, then there are four more bytes. */
    if (err_DIMENSION(error, xres) || err_DIMENSION(error, yres))
        goto fail;
    if (err_SIZE_MISMATCH(error, 4*xres*yres + HEADER_SIZE, size, TRUE))
        goto fail;

    xreal = gwy_get_gfloat_le(&p) * 1e-3;
    /* FIXME: I do not know what the second number means.  It does not seem to be z-scale because z scaling does not
     * change when the number changes. */
    q = gwy_get_gfloat_le(&p);
    gwy_debug("xreal: %g, q: %g", xreal, q);

    dfield = gwy_field_new(xres, yres, xreal, xreal, FALSE);
    gwy_convert_raw_data(buffer + HEADER_SIZE, xres*yres, 1, GWY_RAW_DATA_FLOAT, GWY_BYTE_ORDER_LITTLE_ENDIAN,
                         gwy_field_get_data(dfield), 1e-3, 0.0);
    gwy_unit_set_from_string(gwy_field_get_unit_xy(dfield), "m");
    gwy_unit_set_from_string(gwy_field_get_unit_z(dfield), "m");

    file = gwy_file_new_in_construction();
    gwy_file_pass_image(file, 0, dfield);
    gwy_file_set_title(file, GWY_FILE_IMAGE, 0, "Topography", FALSE);
    gwy_check_nonsquare_image(file, 0);

    gwy_log_add_import(file, GWY_FILE_IMAGE, 0, NULL, filename);

fail:
    gwy_unmap_file_contents(buffer);

    return file;
}

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