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

/* 
   Quick & dirty BUFR (tropical cyclones) to FDB
   Manuel Fuentes 31-Aug-2004
*/


extern int initfdb(void);
extern int openfdb(char*,int*,char*);
extern int openfdb_remote(char*,int*,char*,char*);
extern int readfdb(int*,void*,int*);
extern int writefdb(int*,void*,int*);
extern int closefdb(int*);
extern int setvalfdb(int*,char*,char*);

typedef struct data {
	char *FdbHost;
	char *Fdbroot;
	char *Fdbname;
	char *mode;

	char *mars_class;
	char *mars_type;
	char *mars_expver;
	char *mars_stream;
	char *mars_domain;

	char *mars_date;
	char *mars_time;

	char *file;
	int ref;
	long fdbbufrlen;
	boolean section2;
} data;

static data setup;

static option opts[] = {    
{NULL,"FDB_SERVER_HOST","-host","hpcbfdb",t_str,sizeof(char*),OFFSET(data,FdbHost),},
{NULL,"FDB_ROOT","-R","/ma_fdb",t_str,sizeof(char*),OFFSET(data,Fdbroot),},
{NULL,"FDB_NAME","-n","fdb",t_str,sizeof(char*),OFFSET(data,Fdbname),},
{NULL,"FDB_CONFIG_MODE","-m","client",t_str,sizeof(char*),OFFSET(data,mode),},
{NULL,NULL,"-c","od",t_str,sizeof(char*),OFFSET(data,mars_class),},
{NULL,NULL,"-t","tf",t_str,sizeof(char*),OFFSET(data,mars_type),},
{NULL,NULL,"-v","0001",t_str,sizeof(char*),OFFSET(data,mars_expver),},
{NULL,NULL,"-s","oper",t_str,sizeof(char*),OFFSET(data,mars_stream),},
{NULL,NULL,"-d","g",t_str,sizeof(char*),OFFSET(data,mars_domain),},
{NULL,NULL,"-T",NULL,t_str,sizeof(char*),OFFSET(data,mars_time),},
{NULL,NULL,"-D",NULL,t_str,sizeof(char*),OFFSET(data,mars_date),},
{NULL,NULL,"-f",NULL, t_str,sizeof(char*),OFFSET(data,file),},
{NULL,"FDB_BUFR_LEN",NULL,"1048576",t_long,sizeof(long),OFFSET(data,fdbbufrlen),},
{NULL,"FDB_CHECK_RDB_KEY", NULL, "1", t_boolean, sizeof(boolean), OFFSET(data,section2),},
};

void marssetvalfdb(int *fdb, char *par, char *val)
{
	marslog(LOG_INFO,"setvalfdb '%s' '%s'",par,val);
	setvalfdb(fdb, par, val);
}

int main(int argc, char **argv)
{
	FILE *fd = 0;
	int e = NOERR;
	int cnt = 0;
	long  buflen = 1024*1024*1;  /* 1 Mb to read from file */
	long length = buflen;
	char *buffer = reserve_mem(length);

	int current_len = 0;
	char *fdbbufr;

	char buf[80];
	char date[24],time[24];

	marsinit(&argc,argv,&setup,NUMBER(opts),opts);

	fdbbufr = reserve_mem(setup.fdbbufrlen);

	if(!setup.file)
	{
		printf("Usage: %s -c cc [-t tt] -v vvvv -s ssss [-T HHMM] [-D YYYYMMDD] [-R root] [-host hhhhhhh] [-n nnnnn]-f <file>\n",argv[0]);
		printf("Defaults: %s -c %s -t %s -v %s -s %s -d %s -R %s -host %s -n %s\n",
						argv[0], 
						setup.mars_class,  setup.mars_type, setup.mars_expver, setup.mars_stream, setup.mars_domain,
						setup.Fdbroot, setup.FdbHost, setup.Fdbname);
		marsexit(1);
	}

	start_timer();
	if((fd = fopen(setup.file,"r")) == NULL)
	{
		marslog(LOG_EROR|LOG_PERR,"fopen: %s",setup.file);
		marsexit(1);
	}

	while((e = _readany(fd,buffer,&length)) == NOERR)
	{
		cnt++;

		if(setup.section2)
		{
			packed_key  ky;
			packed_key *k = &ky;

			marslog(LOG_INFO,"Reading section 2");
			if(!get_packed_key(buffer,k))
			{
				marslog(LOG_WARN,"BUFR message %d has no key. Skipping",cnt);
				return -1;
			}

			sprintf(date,"%04d%02d%02d",KEY_YEAR(k),KEY_MONTH(k),KEY_DAY(k));
			sprintf(time,"%02d%02d",KEY_HOUR(k),KEY_MINUTE(k));
			setup.mars_date = date;
			setup.mars_time = time;
		}
		else
		{
			if(!setup.mars_date || !setup.mars_time)
			{
				marslog(LOG_EROR,"FDB_CHECK_RDB_KEY = 0, but DATE or TIME missing");
				marslog(LOG_EROR,"Please, specify  -D YYYYMMDD -T HHMM");
				return -1;
			}
		}

		if(!e)
		{
			if((current_len + length) > setup.fdbbufrlen)
			{
				marslog(LOG_EROR,"Buffer too small (%sbyte) to write data to FDB",bytename(setup.fdbbufrlen));
				marslog(LOG_EROR,"Set env. var. FDB_BUFR_LEN to a larger number of bytes (currently %ld)",setup.fdbbufrlen);
				marsexit(1);
			}
			else
			{
				marslog(LOG_INFO,"Found %ld bytes long BUFR message",length);
			}
			memcpy(fdbbufr+current_len,buffer,length);
			current_len += length;

		}
		length = buflen;
	}

	if(current_len > 0)
	{
		e = initfdb();
		if(!e && (e = openfdb(setup.Fdbname,&setup.ref,"w") ) != NOERR)
		{
			marslog(LOG_EROR,"Error %d while openfdb_remote(%s,&ref,w,%s)",e,setup.Fdbname,setup.FdbHost);
			marsexit(1);
		}

		if(!e)
		{
			marssetvalfdb(&setup.ref,"class",setup.mars_class);
			marssetvalfdb(&setup.ref,"stream",setup.mars_stream);
			marssetvalfdb(&setup.ref,"expver",setup.mars_expver);
			marssetvalfdb(&setup.ref,"domain",setup.mars_domain);

			marssetvalfdb(&setup.ref,"type",setup.mars_type);
			marssetvalfdb(&setup.ref,"date",setup.mars_date);
			marssetvalfdb(&setup.ref,"time",setup.mars_time);
		}

		/* Write to FDB */
		if((e = writefdb(&setup.ref,fdbbufr,&current_len) ) != NOERR)
		{
			marslog(LOG_EROR,"Error %d while writefdb(&ref,buffer,%d)",e,current_len);
			marsexit(1);
		}

		if(closefdb(&setup.ref) != NOERR)
		{
			marslog(LOG_EROR,"Error while closefdb()",e);
			marsexit(1);
		}
	}

	marslog(LOG_INFO,"write %d bytes to fdb, %d BUFR messages",current_len, cnt);

	switch(e)
	{
		case EOF:
			e = NOERR;
		case NOERR:
			marslog(LOG_INFO,"Decoded %d BUFR messages",cnt);
			break;
		case BUF_TO_SMALL:
			marslog(LOG_WARN,"Buffer is too small (%d bytes, %d needed.)", buflen,length);
			break;
		case NOT_FOUND_7777:
			marslog(LOG_EROR,"Group 7777 not found at the end of BUFR message");
			break;
		default:
			marslog(LOG_EROR,"readany: got unknown error %d",e);
			break;
	}

	if(buffer) release_mem(buffer);
	if(fdbbufr) release_mem(fdbbufr);

	stop_timer(buf);
	timer_cpu();
	if(*buf) 
		marslog(LOG_INFO,"Request time: %s",buf);

	print_memory_usage(NULL);
	marsexit(e);
}
