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

/*

B.Raoult
ECMWF Oct-93

*/

#include "Metview.h"
#include "MvPath.hpp"
#include <stdlib.h>

//static Cached METVIEW_ICON ("METVIEW_ICON");

class Retrieve : public MvService {
public:
	Retrieve(char *c);
	void serve(MvRequest&,MvRequest&);
	virtual void marsServe(MvRequest&,MvRequest&);
};


class Read : public Retrieve {
public:
	Read(char *c) : Retrieve(c) {}
	virtual void marsServe(MvRequest&,MvRequest&);
};

class Stage : public Retrieve {
public:
	Stage(char *c) : Retrieve(c) {}
};

Retrieve::Retrieve(char *c) : MvService(c)
{

  //-- if flag -mlog was set in startup script then
  //-- activate more log output from Mars processes

  const char* mlog = getenv("MV_MLOG");
  if( mlog && strcmp(mlog,"yes") == 0  )
    {
      mars.info    = true;
      mars.warning = true;
      putenv("MV_DEBUG_PRINT=1");
      marslog(LOG_DBUG,"Spotted -mlog, set all kind of flags...");
    }
}

void Retrieve::marsServe(MvRequest& in,MvRequest& out)
{
	Cached name       =  (const char*)in("_NAME");
	Cached icon_class =  (const char*)in("_CLASS");

	Cached mode = getenv("METVIEW_MODE");
	Cached appl = "metview";

	if(mode) appl = appl + "-" + mode;

	in("_APPL") = appl;


	//-- make the verb MARS understandable

	if( strcmp( in.getVerb(), "READ_G2" ) == 0 )
		in.setVerb("READ");     
	else if( strcmp( in.getVerb(), "RETRIEVE_G2" ) == 0 )
		in.setVerb("RETRIEVE");
	else if( strcmp( in.getVerb(), "READ_TIGGE" ) == 0 )
		in.setVerb("READ");
	else if( strcmp( in.getVerb(), "RETRIEVE_TIGGE" ) == 0 )
		in.setVerb("RETRIEVE");
	else if( strcmp( in.getVerb(), "READ_ODB" ) == 0 )
		in.setVerb("READ");
	else if( strcmp( in.getVerb(), "RETRIEVE_ODB" ) == 0 )
		in.setVerb("RETRIEVE");


	if(is_bufr(in)) {

		in("TARGET")   = marstmp();
		in.print();

		err  e = handle_request(in,this);
		if(e != 0)
		  { setError(e); return ; }

		MvRequest r = "BUFR";
		r("PATH") = in("TARGET");
		r("TEMPORARY") = 1;

		out = r;

	}
	else if(is_odb(in)) {


		// Check double quotes in FILTER
		// if we don't have double quotes around the FILTER expression	
		// then it won't work (actually, any characters will do - ODB
		// removes the first and last characters from the string!
		const char *filter=in("FILTER");
		if(filter)
		{ 
	  		string fstr(filter);
			if(fstr.size() > 0)
			{
				if(fstr.substr(0,1) != "\"")
					fstr.insert(0,"\"");			

				int n=fstr.size();
				if(fstr.substr(n-1,1) != "\"")
					fstr.append("\"");

				in("FILTER")=fstr.c_str();	
			}	
		}	



		in("TARGET")   = marstmp();
		in.print();

		err  e = handle_request(in,this);
		if(e != 0)
		  { setError(e); return ; }

		// If size of the target file is 0
		// then there is no data retrieved
		if ( !FileHasValidSize(in("TARGET")) )
		{
			request* field = NULL;
			out = field;
		}
		else
		{
			MvRequest r = "ODB_DB";
			r("PATH") = in("TARGET");
			r("TEMPORARY") = 1;

			out = r;
		}
	}
	else if(image(in) || simulated_image(in)) {

		in("TARGET")   = marstmp();
		in.print();

		err  e = handle_request(in,this);
		if(e != 0)
		 { setError(e); return ; }

		// If size of the target file is 0
		// then there is no data retrieved
		if ( !FileHasValidSize(in("TARGET")) )
		{
			request* field = NULL;
			out = field;
		}
		else
		{
//		MvRequest r = "IMAGE";
		MvRequest r = "GRIB";  // we don't want to distinguish between IMAGEs and other GRIBs now
		r("PATH") = in("TARGET");
		r("TEMPORARY") = 1;
		out = r;
		}
	}
	else {

	        in.print();

		err e = handle_request(in,this);
		if(e != 0)
		  { setError(e); return ; }

		variable *v = find_variable((const char*)in("FIELDSET"));
		if(v == NULL)
		  { setError(-2); return ; }

		if(v->scalar)
		{
			MvRequest r = "NUMBER";
			r("VALUE") = v->val;

			out = r;
		}
		else
		{
			out = fieldset_to_request(v->fs);
		}
	}

	out.print();


}

void Read::marsServe(MvRequest& in,MvRequest& out)
{
	const char *data = in( "DATA" );
	const char *path = in( "SOURCE" );

	if( data && path )  //-- do not allow two data sources
	{
		setError( 1, "READ: two input files: both Source and Data have values!" );
		return;
	}
	if( ( ! data ) && ( ! path ) ) //-- one data source required
	{
		setError( 1, "READ: no input file: both Source and Data are empty!" );
		return;
	}

	if( data )
	{
		MvRequest grib;
		in.getValue(grib,"DATA");
		path = grib("PATH");
		in("SOURCE") = path;
	}

	int temp = 0;
	char *name = guess_class(path);

	FILE *f = fopen(path,"r");

	if(!f) {
		marslog(LOG_EROR|LOG_PERR,"%s",path);
		setError(1,"READ: unable to open file!");
		return;
	}

	fclose(f);



	if(strcmp(name,"GRIB") == 0)
	  {
	    Retrieve::marsServe(in,out);

	    // Check whether the request should be sorted.
	    const char *field_order = in("ORDER");
	    if ( field_order && strcmp(field_order,"1") == 0 )
	      {

		marslog(LOG_DBUG, "============== Before sorting:");
		out.print();

		MvFieldSet fs(out);
		MvFieldSetIterator ii(fs);
		MvField ff;
		MvRequest one_field;

		out.unsetParam("OFFSET");
		out.unsetParam("LENGTH");

		ii.sort("PARAM");
		ii.sort("LEVELIST");
		ii.sort("LEVTYPE");
		ii.sort("NUMBER");
		ii.sort("_DIAGITER");
		ii.sort("STEP");
		ii.sort("TIME");
		ii.sort("DATE");
		while ( ff = ii() )
		  {
		    one_field = ff.getRequest();
		    out.addValue("OFFSET",ff.getOffset() );
		    out.addValue("LENGTH",ff.getLength() );
		  }

		marslog(LOG_DBUG, "============== After sorting:");
		out.print();

	      }
	    else
	      {
		marslog(LOG_INFO, "READ: No sorting done");
	      }
	  }
	else
	{
		out              = MvRequest(name);
		out("PATH")      = path;
		out("TEMPORARY") = temp;
	}
}

void Retrieve::serve(MvRequest& in,MvRequest& out)
{
	// Make sure the request is clean...

	marslog(LOG_DBUG, "--> request in -->");
	in.print();

	reset_language(mars_language());
	expand_flags(EXPAND_MARS);

	MvRequest clean(
		expand_all_requests(
			mars_language(),
			mars_rules(),
//			in));
			trim_all_requests(mars_language(),in)));

	// Make sure we have a fieldset

	clean("FIELDSET") = iconName();

	marslog(LOG_DBUG, "<-- request out <--");
	clean.print();

	// Do the real job there

	marsServe(clean,out);
}

int main(int argc,char **argv)
{
    // from the environment, check whether we're in 'standard', 'G2' or 'TIGGE' mode
    // - note that 'G2' and 'TIGGE' are identical; TIGGE is really just the new name
    // for G2, but G2 is retained for backwards compatibility.
    
    char *marsmode = getenv ("MV_MARS_MODE");
    char *servicename = "mars";
    
    if (marsmode && strcmp (marsmode, "G2") == 0)
    {
        servicename = "Mars_G2";
    }
    else if (marsmode && strcmp (marsmode, "TIGGE") == 0)
    {
        servicename = "Mars_TIGGE";
    }
    else if (marsmode && strcmp (marsmode, "odb") == 0)
    {
        servicename = "marsOdb";
    }

	MvApplication theApp(argc,argv,servicename);

	mars.appl     = servicename;

	Retrieve r  ("RETRIEVE");
	Retrieve r2 ("RETRIEVE_G2");
	Retrieve rt ("RETRIEVE_TIGGE");
	Retrieve ro ("RETRIEVE_ODB");
	Read     x  ("READ");
	Read     x2 ("READ_G2");
	Read     xt ("READ_TIGGE");
	Read     xo ("READ_ODB");
	Stage    y  ("STAGE");

	theApp.run();
}
