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

/*

   B.Raoult
   ECMWF Oct-93

 */

#include <errno.h>
#include "mars.h"

err feed(database *bout,request *r)
{
	extern base_class *netbase;
	extern base_class *gribbase;
    static long  buflen = 4*1024*1024;
	static char *buffer = NULL;
	database   *bin;
	int i;
	int cnt = 0;
	err ret;

	bin  = database_open(gribbase,NULL,r,get_environ(),READ_MODE);
	if(!bin) return -2;

	if(!buffer) buffer = reserve_mem(buflen);

	if(observation(r)) r = 0;

	do
	{
		request *s = clone_all_requests(r);
		long length = buflen;

		ret = database_read(bin,s,buffer,&length);

		if(ret == BUF_TO_SMALL)
		{
			release_mem(buffer);
			buflen = length;
			buffer = reserve_mem(buflen);

			ret = 0;
			database_close(bin);
			bin  = database_open(gribbase,NULL,r,get_environ(),
					READ_MODE);

			for(i=0;i<(cnt+1);i++)
				ret = database_read(bin,s,buffer,&length);
		}

		if(ret == 0) {
			ret = database_write(bout,s,buffer,&length);
			cnt++;
		}

		free_all_requests(s);

		if(ret == EOF)
		{
			ret = 0;
			break;
		}

	}while(ret == 0);

	database_close(bin);

	marslog(LOG_INFO,"%d records fed to database '%s'",cnt,bout->name);

	return ret;

}

static request* make_arc_request(const char *path)
{
	const char *x;
	long buflen = 0;
	long length = 0;
	char *buffer;
	request *a = empty_request("ARCHIVE");
	err e;
	int cnt = 0;

	buflen = mars.readany_buffer_size;
	length = buflen;

	FILE *f = fopen(path,"r");
	if(f == NULL)
	{
		marslog(LOG_EROR|LOG_PERR,"ARCHIVE : '%s'",path);
		marsexit(1);
	}

	buffer = reserve_mem(length);
	length = buflen;
	while((e = _readany(f,buffer,&length)) == NOERR || (e == BUF_TO_SMALL))
	{
		request *g = empty_request(0);
		grib_to_request(g,buffer,length);
		reqmerge(a,g);
		free_all_requests(g);
		length = buflen;
		cnt++;
	}

#if 0
	x = get_value(a,"_RESOL",0);    if(x) add_value(a,"RESOL",x);
	x = get_value(a,"_GAUSSIAN",0); if(x) add_value(a,"RESOL",x);
	x = get_value(a,"_GRID_EW",0);  if(x) add_value(a,"RESOL","%d",
			(int)(360.0/atof(x)));
	x = get_value(a,"_GRID_NS",0);  if(x) add_value(a,"RESOL","%d",
			(int)(360.0/atof(x)));
#endif

	set_value(a,"EXPECT","%d",cnt);

	return a;
}

err handle_archive(request *r,void *data)
{
	int i    = 0;
	err e = 0;
	const char *s  = 0;

	mars.fields_are_ok = true;
	mars.fields_in_order = true;
	mars.fields_have_same_size = true;

	if(mars.autoarch)
	{
		const char *s = no_quotes(get_value(r,"SOURCE",0));
		request *a = make_arc_request(s);

		if(mars.autoarch != 2)
		{
			unset_value(r,"CLASS");
			unset_value(r,"TYPE");
			unset_value(r,"STREAM");
			unset_value(r,"EXPVER");
			unset_value(r,"LEVTYPE");
			unset_value(r,"LEVELIST");
			unset_value(r,"REPRES");
			unset_value(r,"DOMAIN");
			unset_value(r,"PARAM");
			unset_value(r,"DATE");
			unset_value(r,"TIME");
			unset_value(r,"STEP");
			unset_value(r,"DISP");
			unset_value(r,"RESOL");
			unset_value(r,"NUMBER");
			unset_value(r,"METHOD");
			unset_value(r,"SYSTEM");
		}

		reqcpy(r,a);
		free_all_requests(a);

		marslog(LOG_INFO,"Archive request changed to: ");
		print_one_request(r);
	}

	while( (s = get_value(r,"DATABASE",i++)) != NULL )
	{
		database   *base;
		const char *name = 0;
		request    *cache = 0;
		int retry = 0;
		int slp = 1;

		request *b = findbase(s);
		if(!b) return -2;

		for(;;)
		{

			base = openbase(b,r,&name,&cache,WRITE_MODE);
			if(base) {
                int e1 = database_archive(base, r);
                marslog(LOG_INFO, "database_archive return %d", e1);
                int e2 = database_close(base);
                marslog(LOG_DBUG, "database_close return %d", e2);
                e = e1 ? e1 : e2;
            } else {
                e = -2;
            }

			if(e != RETRY_FOREVER_ERR && e != RETRY_ERR)
				break;

			if(e == RETRY_ERR)
			{
				if(retry<mars.maxretries)
				{
					retry++;
					marslog(LOG_WARN,"Sleeping %d minutes",slp);
					sleep(slp*60);
				}
				else
				{
					e = -2;
					marslog(LOG_WARN,"Giving up after %d retries",retry);
					break;
				}
			}

			if(e == RETRY_FOREVER_ERR)
			{
				if(slp<5)
					slp += 1;
				marslog(LOG_WARN,"Sleeping %d minutes",slp);
				sleep(slp*60);
			}

		}

		if(e != 0)
			break;

	}

	return e;
}
