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

int one     = 0;
int obs     = 0;
int compare = 0;

char* sorted[] = {
	"level",
	"levelist",
};

int sort_cnt = NUMBER(sorted);

FILE *out = NULL;

void clean_exit(int s)
{
	if(out != stdout && out != NULL)
		fclose(out);

	exit(s);
}

void p_values(value *r)
{
	int col = 0;

	while(r)
	{
		col += fprintf(out,"%s",r->name);
		if(r->next) {
			putc('/',out);
			col++;
			if(col>50) {
				putc('\n',out);
				col=0;
			}
		}
		r = r->next;
	}
}

void p_sorted_values(value *r)
{
	request *d = empty_request("dummy");
	value *s = r;
	int ok = 1;

	while(s)
	{
		if(!is_number(s->name))
			ok = 0;
		s = s->next;
	}

	if(!ok)
	{
		 p_values(r);
		 return;
	}


	while(r)
	{
		add_ordered_value(d,"dummy","%s",r->name);
		r = r->next;
	}
	p_values(d->params->values);
	free_all_requests(d);
}

void p_parameters(const char *name,parameter *r)
{
	while(r)
	{
		if((r->default_values == NULL) ||
		    (strcasecmp(r->default_values->name,name) == 0))
		{
			if(*r->name != '_')
			{
				int sort = 0;
				int i;

				fprintf(out,",\n    %-10s = ",r->name);
				for(i = 0; i < sort_cnt; i++)
				{
					if(EQ(r->name,sorted[i]))
						sort = 1;
				}
				if(sort)
					p_sorted_values(r->values);
				else
					p_values(r->values);
			}
		}

		r = r->next;
	}
	putc('\n',out);
}


void p_requests(const char *name,request *r)
{
	while(r)
	{
		fprintf(out,"%s",r->name);
		p_parameters(name,r->params);
		putc('\n',out);
		r = r->next;
	}
}



static void setverb(request *r,const char *name,const char *file1,const char *file2,const char *unset)
{
	while(r)
	{
		strfree(r->name);
		r->name = strcache(name);

		unset_value(r,unset);
		set_value(r,file2,"%s",get_value(r,file1,0));
		r = r->next;
	}
}

void usage()
{
	fprintf(stderr,"marsgen [-c][-o][-1][-s sorted_param][-f <output file>]\n");
	clean_exit(1);
}

void dump(request *r)
{
	int cnt = 0;
	request *s = r;

	while(s)
	{
		set_value(s,"_MARSBLK_","\"marsblk.%d\"",cnt);
		set_value(s,"_MARSUBK_","\"marsubk.%d\"",cnt);
		set_value(s,"_MARSRET_","\"marsret.%d\"",cnt);
		s = s->next;
		cnt++;
	}

	if(obs)
	{
		int cnt = 0;
		s = r;
		while(s)
		{
			++cnt;
			fprintf(out,"$PREOBS $header.%d $data.%d %s\n", cnt, cnt,
			    get_value(s,"_MARSUBK_",0));
			s = s->next;
		}
	}
	else
	{
		fprintf(out,"$MARS_FROM_FDB << @\n\n");
		setverb(r,"RETRIEVE","_MARSBLK_","TARGET","SOURCE");
		p_requests("FDB_RETRIEVE",r);
		fprintf(out,"\n\n@\n\n$FDB_COMPLETE\n\n");

		s = r;
		while(s)
		{
			fprintf(out,"$UNBLOCK %s %s\n",
			    get_value(s,"_MARSBLK_",0),
			    get_value(s,"_MARSUBK_",0));
			s = s->next;
		}
	}
	fprintf(out,"\n\n");


	fprintf(out,"$MARS_TO_IBM << @\n\n");
	setverb(r,"ARCHIVE","_MARSUBK_","SOURCE","TARGET");
	p_requests("ARCHIVE",r);
	fprintf(out,"\n\n@\n\n$ARC_COMPLETE\n\n");

	if(compare)
	{

		fprintf(out,"$MARS_FROM_IBM << @\n\n");
		setverb(r,"RETRIEVE","_MARSRET_","TARGET","SOURCE");
		p_requests("IBM_RETRIEVE",r);
		fprintf(out,"\n\n@\n\n");

		s = r;
		while(s)
		{
			fprintf(out,"%s %s %s\n",
			    obs?"$COMPOBS":"$COMPARE",
			    get_value(s,"_MARSBLK_",0),
			    get_value(s,"_MARSRET_",0));
			s = s->next;
		}
		fprintf(out,"\n\n$CMP_COMPLETE\n\n");
	}
}

void sorting(char *order)
{
	fprintf(stderr,"Sorting not implemented\n");
	exit(1);
}

int main(int argc,char **argv)
{
	request   *r = read_request_file(NULL);
	request   *s;
	int       cnt = 0;
	parameter *p;
	int       c;
	extern    int   optind;
	extern    char *optarg;
	int       test;

	out = stdout;
	while((c=getopt(argc, argv, "co1f:s:")) != -1)
	{
		switch(c)
		{
		case 'c':
			compare = 1;
			break;

		case 'o':
			obs = 1;
			break;

		case 's':
			sorting(optarg);
			break;

		case '1':
			one = 1;
			one = 0;
			break;

		case 'f':
			if((out = fopen(optarg,"w")) == NULL)
			{
				printf("Error opening %s\n",optarg);
				clean_exit(1);
			}
			break;

		default:
			usage();
			break;
		}

	}

	if(argc != optind) usage();

	if(r == NULL) clean_exit(1);

	if(strcasecmp(r->name,"loop")==0)
	{
		request *z = NULL;
		request *y = NULL;
		p = r->params;
		r = r->next;

		while(p)
		{
			value *v = p->values;
			while(v)
			{
				request *t = r;
				s = clone_all_requests(r);

				if(z == NULL) z = s;
				else y->next = s;

				while(s)
				{
					/* copy def values */

					parameter *a = t->params;
					parameter *b = s->params;

					while(a && b)
					{
						b->default_values = a->default_values;
						a = a->next;
						b = b->next;
					}

					y = s;
					set_value(s,p->name,"%s",v->name);


					/* check for tests */
					test = 0;
					a = t->params;
					b = s->params;
					while(a)
					{
						if(a->default_values)
						if(strcasecmp(a->default_values->name,"if")==0)
						{
							const char *q = get_value(s,a->name,0);
							b->default_values = NULL;
							if(q)
							{
								value *w = a->values;
								while(w)
								{
									if(strcasecmp(w->name,q)==0)
										test = 1;
										w = w->next;
								}
							}
						}
						a = a->next;
						b = b->next;
					}

					/* check for tests */
					a = t->params;
					b = s->params;
					while(a)
					{
						if(a->default_values)
						if(strcasecmp(a->default_values->name,"then")==0)
						{
							value *w = a->values;
							b->default_values = NULL;
							b->name = strcache("_dummy");
							if(test)
							{
							unset_value(s,a->name);
							while(w)
							{
							if(w == a->values)
							set_value(s,a->name,"%s",w->name);
							else
								add_value(s,a->name,"%s",w->name);
								fprintf(out,"%s ",w->name);
								w = w->next;
							}
							fprintf(out,"\n");
							}
						}
						a = a->next;
						b = b->next;
					}

					s = s->next;
					t = t->next;
				}
				v = v->next;
			}
			p = p->next;
		}
		r = z;
	}

	if(one)
	{
		request *u = empty_request("dummy");
		while(r)
		{
			request *s = r->next;
			r->next  = 0;
			reqcpy(u,r);
			dump(u);
			r = s;
		}
	}
	else dump(r);

	clean_exit(0);
}

