/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "mars.h"

#include <MvGribParC.h>

#if defined(_STDC_) || defined(c_plusplus) || defined(__cplusplus)
#define P_(s) s
#else
#define P_(s) ()
#endif

static MvGribTStruct*      MvGribTOpen P_((int));
static void                MvGribTClose P_((MvGribTStruct*));

static MvGribTEntryStruct* MvGribTParameter P_((MvGribTStruct*,int));
static int                 MvGribTIndex P_((MvGribTStruct*,char*));
static int                 compare P_((char*,char*));

#undef P_

MvGribParStruct* MvGribParOpen()
{
	MvGribParStruct* list;

	list = (MvGribParStruct*) malloc(sizeof(MvGribParStruct));
	list->nelems = 0;
#if 0
	if (list->partable[list->nelems] = MvGribTOpen(0)) list->nelems++;
	if (list->partable[list->nelems] = MvGribTOpen(1)) list->nelems++;
	if (list->partable[list->nelems] = MvGribTOpen(2)) list->nelems++;
#endif

	if ( (list->partable[list->nelems] = MvGribTOpen(1)) ) list->nelems++;

#if 0
	if (list->partable[list->nelems] = MvGribTOpen(140)) list->nelems++;
	if (list->partable[list->nelems] = MvGribTOpen(254)) list->nelems++;

	if (!list->nelems)
	{	free (list);
		return NULL;
	}
#endif

	return list;
}

void MvGribParClose(list)
MvGribParStruct* list;
{
	int i;

	if (!list) return;

	for (i = 0; i < list->nelems; i++)
		MvGribTClose(list->partable[i]);
	free(list);
}

MvGribTEntryStruct* MvGribParEntry(list, version, npar)
MvGribParStruct* list;
int version, npar;
{
	int i;

	/*-- is this table version already in memory? --*/
	for (i = 0; i < list->nelems; i++)
	{
		if (list->partable[i]->version == version)
			return MvGribTParameter(list->partable[i],npar);
	}

	/*-- do we have space for one more version? --*/
	if( list->nelems >= MAX_TABLE2_VERSIONS )
	  {
	    marslog( LOG_EROR, "No more space for GRIB Table 2 version %d", version );
	    return NULL;
	  }

	/*-- read this version into memory -*/
	list->partable[list->nelems] = MvGribTOpen( version );
	if( list->partable[list->nelems] == NULL )
	  {
	    marslog( LOG_EROR, "Problems reading GRIB Table 2 version %d", version );
	    return NULL;
	  }

	list->nelems++;
	return MvGribTParameter( list->partable[ list->nelems - 1 ], npar );
}

int MvGribParIndex(MvGribParStruct* list, int version, const char *parname)
{
	int i;

	for (i = 0; i < list->nelems; i++)
	{
		if (list->partable[i]->version == version)
			return MvGribTIndex(list->partable[i],parname);
	}
	return -1; /* no match (this missing return added by vk/970725) */
}

static MvGribTStruct* MvGribTOpen(version)
int version;
{
	int		i, ival;
	FILE*		fp;
	MvGribTStruct*	table;
	char*		fname;
	char		line[201], *dir;

	if (version < 0 || version > 255) return NULL;

	dir = getenv("METVIEW_DIR");
	if (!dir)
	  return NULL;

	fname = (char*)malloc(strlen(dir) + 19);
	if (!fname)
	  return NULL;
	sprintf (fname, "%s/sys/metv_%d.par", dir, version);

	fp = fopen(fname,"r");
	if (!fp)
	  {
	    marslog( LOG_EROR, "No file %s", fname );
	    free(fname);
	    return NULL;
	  }
	printf("\n--- Reading Table 2 version file into memory: %s ---\n", fname );
	free(fname);

	table = (MvGribTStruct*) malloc(sizeof(MvGribTStruct));

	do
	  {
	    fgets (line, 200, fp);
	  } while (line[0] == '*');

	table->version = version;
	sscanf(line, "%d %d", &table->start, &table->end);

	if (table->start < 0 || table->end < 0 ||
	    table->start > 255 || table->end > 255 ||
	    table->start > table->end)
	{
	  free(table);
	  return NULL;
	}

	i = 0;
	table->entry = (MvGribTEntryStruct*)
		malloc((table->end - table->start+1) *
		sizeof(MvGribTEntryStruct));

	while (fgets(line, 200, fp))
	{
#if 0
		sscanf(line, "%d %s %s",
		&ival, table->entry[i].shortName, table->entry[i].longName);
#endif
		sscanf( line, "%d %s", &ival, table->entry[i].shortName );
		table->entry[i].longName[ 0 ] = NULL; /* not used */
		table->entry[i].fieldType = line[35];
		i++;
	}

	fclose(fp);

	return table;
}

static void MvGribTClose (table)
MvGribTStruct* table;
{
	if (!table) return;
	free (table->entry);
	free (table);
}

static MvGribTEntryStruct* MvGribTParameter (table,npar)
MvGribTStruct* table;
int npar;
{
	if (npar < table->start || npar > table->end) return NULL;
	return &table->entry[npar - table->start];
}

/* MvGribTIndex returns the code, given the parameter name */

#ifndef MAX
# define MAX(a,b)    (a)>(b)?(a):(b)
#endif

static int MvGribTIndex(table,name)
MvGribTStruct* table;
char* name;
{
	int i, j, k, n, n1, n2;
	int exact_match = 0;
	int max = -1;

	j = k = -1;
	for (i = table->start; i <= table->end; i++)
	{
		n1 = compare(name, table->entry[i - table->start].shortName);
		if(n1==strlen(name)) {
			exact_match = 1;
			n=n1;
		}
		else {
			n2 = compare(name, table->entry[i - table->start].longName);
			if(n2==strlen(name)) {
				exact_match = 1;
				n=n2;
			}
			else n = MAX(n1,n2);
		}
		/* Test for size of match */
		if(n) {
			if(exact_match) {
				j = i;
				break;
			}
			else if(n == max) k = i;
			else if(n>max) {
				max = n;
				j = i;
				k = -1;
			}
		}
	}

	if(j==-1) return -1;	/* no match */
	else if(j==k) return -2; /* Ambiguous match */
	else return j;
}


/*===============================================================*/
/* compare returns the offset of the first different character   */
/* of two strings. The comparaison is not case sensitive         */
/*===============================================================*/

#define UP(a)       (islower(a)?toupper(a):a)

static int compare(p,q)
char *p;
char *q;
{
	int  n=0;

	while(*q && *p )
	{
		if (UP(*q) != UP(*p)) return n;
		q++;
		p++;
		n++;
	}

	if (!*q && *p )return n-1;
	if (!*p && *q )return n-1;
	return n;
}

