/*
 ****************************************************************************
 *
 * MODULE:       gis library
 * AUTHOR(S):    Andreas Lange - andreas.lange@rhein-main.de
 *               Paul Kelly - paul-grass@stjohnspoint.co.uk
 * PURPOSE:      provide functions for reading datum parameters from the
 *               location database.     
 * COPYRIGHT:    (C) 2000, 2003 by the GRASS Development Team
 *
 *               This program is free software under the GNU General Public
 *               License (>=v2). Read the file COPYING that comes with GRASS
 *               for details.
 *
 *****************************************************************************/

#define DATUMTABLE "/etc/proj/datum.table"

#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

#include <grass/gis.h>
#include <grass/glocale.h>

static struct table
{
    struct datum
    {
	char *name;		/* Short Name / acronym of map datum */
	char *descr;		/* Long Name for map datum */
	char *ellps;		/* acronym for ellipsoid used with this datum */
	double dx;		/* delta x */
	double dy;		/* delta y */
	double dz;		/* delta z */
    } *datums;
    int size;
    int count;
    int initialized;
} table;

static int compare_table_names(const void *, const void *);

int G_get_datum_by_name(const char *name)
{
    int i;

    G_read_datum_table();

    for (i = 0; i < table.count; i++)
	if (G_strcasecmp(name, table.datums[i].name) == 0)
	    return i;

    return -1;
}

const char *G_datum_name(int n)
{
    G_read_datum_table();

    if (n < 0 || n >= table.count)
	return NULL;

    return table.datums[n].name;
}

const char *G_datum_description(int n)
{
    G_read_datum_table();

    if (n < 0 || n >= table.count)
	return NULL;

    return table.datums[n].descr;
}

const char *G_datum_ellipsoid(int n)
{
    G_read_datum_table();

    if (n < 0 || n >= table.count)
	return NULL;

    return table.datums[n].ellps;
}

/***********************************************************
 *  G_get_datumparams_from_projinfo(projinfo, datumname, params)
 *     struct Key_Value *projinfo Set of key_value pairs containing
 *                       projection information in PROJ_INFO file
 *                       format
 *     char *datumname   Pointer into which a string containing
 *                       the datum name (if present) will be
 *                       placed.
 *     char *params      Pointer into which a string containing
 *                       the datum parameters (if present) will
 *                       be placed.
 *
 *  Extract the datum transformation-related parameters from a 
 *  set of general PROJ_INFO parameters.
 *  This function can be used to test if a location set-up 
 *  supports datum transformation.
 *  
 *  returns: -1 error or no datum information found, 
 *           1 only datum name found, 2 params found
 ************************************************************/

int G_get_datumparams_from_projinfo(const struct Key_Value *projinfo,
				    char *datumname, char *params)
{
    int returnval = -1;

    if (NULL != G_find_key_value("datum", projinfo)) {
	sprintf(datumname, G_find_key_value("datum", projinfo));
	returnval = 1;
    }

    if (G_find_key_value("datumparams", projinfo) != NULL) {
	sprintf(params, G_find_key_value("datumparams", projinfo));
	returnval = 2;
    }
    else if (G_find_key_value("nadgrids", projinfo) != NULL) {
	sprintf(params, "nadgrids=%s",
		G_find_key_value("nadgrids", projinfo));
	returnval = 2;
    }
    else if (G_find_key_value("towgs84", projinfo) != NULL) {
	sprintf(params, "towgs84=%s", G_find_key_value("towgs84", projinfo));
	returnval = 2;
    }
    else if (G_find_key_value("dx", projinfo) != NULL
	     && G_find_key_value("dy", projinfo) != NULL
	     && G_find_key_value("dz", projinfo) != NULL) {
	sprintf(params, "towgs84=%s,%s,%s",
		G_find_key_value("dx", projinfo),
		G_find_key_value("dy", projinfo),
		G_find_key_value("dz", projinfo));
	returnval = 2;
    }

    return returnval;

}

void G_read_datum_table(void)
{
    FILE *fd;
    char file[GPATH_MAX];
    char buf[1024];
    int line;

    if (G_is_initialized(&table.initialized))
	return;

    sprintf(file, "%s%s", G_gisbase(), DATUMTABLE);

    fd = fopen(file, "r");
    if (!fd) {
	G_warning(_("unable to open datum table file: %s"), file);
	G_initialize_done(&table.initialized);
	return;
    }

    for (line = 1; G_getl2(buf, sizeof(buf), fd); line++) {
	char name[100], descr[100], ellps[100];
	struct datum *t;

	G_strip(buf);
	if (*buf == '\0' || *buf == '#')
	    continue;

	if (table.count >= table.size) {
	    table.size += 50;
	    table.datums = G_realloc(table.datums, table.size * sizeof(struct datum));
	}

	t = &table.datums[table.count];

	if (sscanf(buf, "%s \"%99[^\"]\" %s dx=%lf dy=%lf dz=%lf",
		   name, descr, ellps, &t->dx, &t->dy, &t->dz) != 6) {
	    G_warning(_("error in datum table file, line %d"), line);
	    continue;
	}

	t->name = G_store(name);
	t->descr = G_store(descr);
	t->ellps = G_store(ellps);

	table.count++;
    }

    qsort(table.datums, table.count, sizeof(struct datum), compare_table_names);

    G_initialize_done(&table.initialized);
}

static int compare_table_names(const void *aa, const void *bb)
{
    const struct datum *a = aa;
    const struct datum *b = bb;

    return G_strcasecmp(a->name, b->name);
}
