/*
 * © Copyright 1996-2012 ECMWF.
 * 
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0. 
 * In applying this licence, ECMWF does not waive the privileges and immunities 
 * granted to it by virtue of its status as an intergovernmental organisation nor
 * does it submit to any jurisdiction.
 */

#include "mars.h"

/********************************************************/
/*                  Definition 190                      */
/********************************************************/
#ifdef FORTRAN_UPPERCASE
#define d_def_x_ D_DEF_X
#endif

#ifdef FORTRAN_NO_UNDERSCORE
#define d_def_x_ d_def_x
#endif

#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif

extern fortint d_def_x_(fortint *n, fortint *output, unsigned char * input);

#if defined(__cplusplus) || defined(c_plusplus)
}
#endif


static int decode_local_def(fortint number, fortint length, unsigned char *buffer, request *r, gribsec1 *orig_s1)
{
	int e = 0;
	griblocsec1 s1;
	gribsec1 sec1;
	
	CLEAR(s1);
	e = d_def_x_(&number,(fortint *)&s1,buffer);
	marslog(LOG_DBUG,"Calling decoder for definition %d, returns %d",number,e);
	if(e > length)
	{
		marslog(LOG_EROR,"Decoder D_DEF_%d returns %d (> %d from GRIB header)",number,e,length);	
		return -7;
	}

	if(s1.ecmwf_local_id != number)
	{
		marslog(LOG_EROR,"Mistmatch in Multi-local definition");
		marslog(LOG_EROR,"Main GRIB header has local def. %d",number);
		marslog(LOG_EROR,"Local definition is %d",s1.ecmwf_local_id);
		return -7;
	}

	/* Fill the request with values from this local definition 
       Copy the original GRIB section 1, then replace the contents
	   with the just read local section 1
	*/
	CLEAR(sec1);
	memcpy((unsigned char *)&sec1,(unsigned char *)orig_s1,sizeof(gribsec1));
	memcpy((unsigned char *)&(sec1.local),(unsigned char *)&s1,sizeof(s1));
	if((e = localdefinition(&sec1,r)) != NOERR)
	{
		marslog(LOG_WARN,"Error %d when inspecting local definition %d",e,number);
		return e;
	}

	return e;
}

int decode_multi_local_definition_190(gribsec1 *s1, request *r, char* grib )
{
	int i      = 0;
	int e      = 0;
	int offset = 0;
	unsigned char *startdef = (unsigned char *)&(s1->local.u.multi_definition_190.number) + sizeof(fortint) + 
												(s1->local.u.multi_definition_190.number * sizeof(multilocaldef_190));

	for(i=0; i<s1->local.u.multi_definition_190.number; ++i)
	{
		fortint    defnumber = s1->local.u.multi_definition_190.def[i].number; 
		fortint    deflength = s1->local.u.multi_definition_190.def[i].length; 

		unsigned char  *localdef = (unsigned char *)startdef;
		localdef += offset;

		e = decode_local_def(defnumber, deflength, localdef,r, s1);
		if(e)
			return e;

		offset += deflength;
	}

	set_mars_class(&s1->local,r);
	set_mars_type(&s1->local,r);
	set_mars_stream(s1,&s1->local,r);
	set_mars_expver(&s1->local,r);

	return e;
}

/********************************************************/
/*                  Definition 192                      */
/********************************************************/
int decode_multi_local_definition(gribsec1 *s1, request *r, char* grib )
{
	int i      = 0;
	int e      = 0;
	int offset = 0;
	fortint *p = (fortint *)&(s1->local.u.multi_definition.localdef);

	marslog(LOG_DBUG,"Found %d defitions within def 192",s1->local.u.multi_definition.number);
	for(i=0; i<s1->local.u.multi_definition.number; ++i)
	{
		fortint  deflength = p[0];
		gribsec1 sec1;
	
		CLEAR(sec1);
		memcpy((unsigned char *)&sec1,(unsigned char *)s1,sizeof(gribsec1));
		memcpy((unsigned char *)&(sec1.local),(unsigned char *)&p[1],deflength*sizeof(fortint));

		marslog(LOG_DBUG,"Processing definition %d => ECMWF local definition %"D" [%"D"]",i,sec1.local.ecmwf_local_id,p[1]);

		if((e = localdefinition(&sec1,r)) != NOERR)
		{
			marslog(LOG_WARN,"Error %d when inspecting local definition %"D"",e,sec1.local.ecmwf_local_id);
			return e;
		}
			
		p += deflength + 1;
	}

    set_mars_class(&s1->local,r);
    set_mars_type(&s1->local,r);
    set_mars_stream(s1,&s1->local,r);
    set_mars_expver(&s1->local,r);

    return e;
}
