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

#include "inc_iostream.h"
#include "Metview.h"

#include "MvDate.h"
#include "Tokenizer.h"

#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>

using namespace std;

#define FLEXPART_CHK(str) if(!(str)) return false

class Base : public MvService { 
protected:
	Base(const char* a) : MvService(a) {};
};

class FlexpartRun: public Base {	
public:
	FlexpartRun() : Base("FLEXPART_RUN") {initIds();}
	void serve(MvRequest&,MvRequest&);

  protected:	
	void initIds();
	bool getMvDate(const string& dd,const string& tt,MvDate&);
	bool getDate(const string& dd,string& res, const string&);
	bool getTime(const string& dd,string& res, const string&);
	bool getTimeLen(const string& tt,string& res, const string&,bool);
	bool getParamValueId(string&,MvRequest&,string,const map<string,string>&);
	bool getParamValue(string&,MvRequest&,string,bool);
	bool getParamValue(vector<string>&,MvRequest&,string);
	bool generateTmpPath(string&);
	bool generatePathnamesFile(const string&,MvRequest&,const string&,const string&);
	bool generateCommandFile(const string&,MvRequest&);
	bool generateOutGridFile(const string&,MvRequest& in);
	bool generateReleasesFile(const string&,MvRequest& in);
	bool generateAgeClassesFile(const string&,MvRequest& in);
	bool generateReceptorsFile(const string&,MvRequest& in);	
		
	map<string,string> directionIds_;
	map<string,string> outputIds_;
	map<string,string> particleDumpIds_;
	map<string,string> onOffIds_;
	map<string,string> sourceUnitsIds_;
	map<string,string> receptorUnitsIds_;
	map<string,string> writeInitIds_;
};

void FlexpartRun::initIds()
{
	directionIds_["FORWARD"]="1";
        directionIds_["BACKWARD"]="-1";
                
        outputIds_["CONCENTRATION"]="1"; 
        outputIds_["MIXING RATIO"]="2";
	outputIds_["BOTH"]="3";
	outputIds_["PLUME"]="4";
	outputIds_["CONCENTRATION AND PLUME"]="5";
	
	particleDumpIds_["NO"]="0"; 
        particleDumpIds_["AT OUTPUT"]="1";
	particleDumpIds_["AT END"]="2";
	
	onOffIds_["ON"]="1"; 
	onOffIds_["OFF"]="0";
	
	sourceUnitsIds_["MASS"]="1";
	sourceUnitsIds_["MASS MIXING RATIO"]="2";
	
	receptorUnitsIds_["MASS"]="1";
	receptorUnitsIds_["MASS MIXING RATIO"]="2";
	
	writeInitIds_["NO"]="0";
	writeInitIds_["MASS"]="1";
	writeInitIds_["MASS MIXING RATIO"]="2";
}	

bool FlexpartRun::getMvDate(const string& dd,const string& tt,MvDate& res)
{
	if(dd.size() != 8 || tt.size() != 6)
	  	return false;
  
  	string sDate=dd.substr(0,4) + "-" + dd.substr(4,2) + "-" + dd.substr(6,2);
	string sTime=tt.substr(0,2) + ":" + tt.substr(2,2) + ":" + dd.substr(4,2);

	string s=sDate + " " + sTime;

	res=MvDate(s.c_str());  

	return true;
}  


bool FlexpartRun::getDate(const string& dd,string& res,const string& parName)
{ 
  	res=dd;
	
	if(dd.size() < 8)
	{
		istringstream iss(dd);
 		double d;
		iss >> d; 
		char buf[9];
		MvDate md(julian_to_date(today() + d,1));
		md.Format("yyyymmdd", buf);
		res=string(buf);
	}
	
	bool retVal=(res.size() == 8)?true:false;
	
	if(!retVal)
	{
		marslog(LOG_EROR,"Invalid date format used for paramater: %s",parName.c_str());
		setError(13);
	}	
		
	return retVal;
}  

bool FlexpartRun::getTime(const string& tt,string& res,const string& parName)
{ 
  	string hh, mm="00", ss="00";
	bool retVal=true;
	
	vector<string> tok;
	Tokenizer parse(":");
	parse(tt,tok);
		
	if(tok.size() > 0)
	{	
		if(tok[0].size() == 1)	
	  		hh = "0" + tok[0];
		else
		  	hh=tok[0];
		
		if(hh.size() !=  2)
			retVal=false;
	}
	if(tok.size() > 1)
	{	
		mm = tok[1];
		if(mm.size() !=  2)
			retVal=false;
	}

	if(tok.size() > 2)
	{	
		ss = tok[2];
		if(ss.size() !=  2)
			retVal=false;
	}	
	
	res=hh + mm + ss;
	
	retVal=(res.size() == 6)?true:false;

	if(!retVal)
	{
		marslog(LOG_EROR,"Invalid time format used for paramater: %s",parName.c_str());
		setError(13);
	}	
		
	return retVal;
}  


bool FlexpartRun::getTimeLen(const string& tt,string& res,const string& parName,bool inSeconds)
{ 
  	string hh, mm="00", ss="00";
	bool retVal=true;
	
	vector<string> tok;
	Tokenizer parse(":");
	parse(tt,tok);
	
	if(tok.size() > 0)
	{	
		if(tok[0].size() == 1)
			hh = "00" + tok[0];
		else if(tok[0].size() == 2)	
	  		hh = "0" + tok[0];
		else
		  	hh=tok[0];
		
		if(hh.size() !=  3)
			retVal=false;
	}
	if(tok.size() > 1)
	{	
		mm = tok[1];
		if(mm.size() !=  2)
			retVal=false;
	}

	if(tok.size() > 2)
	{	
		ss = tok[2];
		if(ss.size() !=  2)
			retVal=false;
	}	
	
	if(inSeconds)
	{
	  	int sec,i;
		istringstream ish(hh);
		ish >> i;
		sec=i*3600;
		istringstream ism(mm);
		ism >> i;
		sec+=i*60;
		istringstream iss(ss);
		iss >> i;
		sec+=i;
		
		stringstream sst;
		sst << sec;	
		res=sst.str();
		retVal=true;		
	}	
	else
	{  	
		res=hh + mm + ss;
		retVal=(res.size() == 7)?true:false;
	}

	if(!retVal)
	{
		marslog(LOG_EROR,"Invalid time lenght format used for paramater: %s",parName.c_str());
		setError(13);
	}	

	return retVal;
}  

bool FlexpartRun::getParamValueId(string& value,MvRequest& in,string parName,const map<string,string>& idMap)
{	
	value.clear();
	
	const char *cval=in(parName.c_str());
	
	if(cval)
  	{
		value=string(cval);		
		
		if(idMap.empty() == false)
		{
		  	map<string,string>::const_iterator it=idMap.find(value); 
		  	if(it != idMap.end())
				value=it->second;
			else
			  	value.clear();
		}	
		
	}
	
	if(value.empty())
	{
		marslog(LOG_EROR,"No value found for paramater: %s",parName.c_str());
		setError(13);
		return false;
	}
	
	return true;	
}


bool FlexpartRun::getParamValue(string& value,MvRequest& in,string parName,bool canBeMissing=false)
{
	value.clear();
	
	const char *cval=in(parName.c_str());
	
	if(cval)
  	{
		value=string(cval);		
	}
	
	if(!canBeMissing && value.empty())
	{
		marslog(LOG_EROR,"No value found for paramater: %s",parName.c_str());
		setError(13);
		return false;
	}
	
	return true;	
}

bool FlexpartRun::getParamValue(vector<string>& value,MvRequest& in,string parName)
{
	value.clear();
	
	int cnt = in.countValues(parName.c_str());
	
	if(cnt == 1)
	{
	  	const char *cval=in(parName.c_str());
		if(cval)
  		{		
			value.push_back(string(cval)); 
		}
	}
	else
	{  
		string val;
		for( int i=0; i<cnt; i++)
	     	{
	      		const char *cval = in(parName.c_str(),i );
			if(cval)
			{					
				value.push_back(string(cval));
			}						
		}
	}
	
	return true;
}

bool FlexpartRun::generateTmpPath(string& tmpPath)
{
 	string tmpRoot;
	
	char *mvtmp=getenv("METVIEW_TMPDIR");
	if (mvtmp == 0)  
	{	
		marslog(LOG_EROR,"No env variable METVIEW_TMPDIR is not defined!");
		setError(13);
		return false;
	}
	else
	{
		tmpRoot=string(mvtmp);
	}

	time_t sec=time(NULL);
  	srand (sec);
  	int rNum = rand() % 1000 + 1;

 	std::stringstream out;
  	out << tmpRoot << "/flexpart_" << sec << "_" << rNum; 
	tmpPath=out.str();
	
	if(mkdir(tmpPath.c_str(),0777) != 0)
	{
		marslog(LOG_EROR,"Could not genarate work directory for FLEXPART run: %s",tmpPath.c_str());
		setError(13);
		return false;
	}
	
	return true;
}  


bool FlexpartRun::generatePathnamesFile(const string& fPathnames,MvRequest& in,const string& optionsPath,const string& outPath)
{
	string inPath,fAvailable;
		
	const char *input_mode=in("FLEXPART_INPUT_MODE");	
	if(!input_mode)
	{
	  	marslog(LOG_EROR,"No parameter FLEXPART_INPUT_MODE is defined!");
		setError(13);	
		return false;
	}
	  
	if(strcmp(input_mode,"ICON") == 0)
	{
		MvRequest dataR=in("FLEXPART_INPUT_DATA");
		const char* iconType=dataR.getVerb();
		//If no icon is specified
		if(!iconType || strcmp(iconType,"FLEXPART_INPUT") != 0)
		{
			marslog(LOG_EROR,"No FLEXPART_INPUT icon is specified!");
			setError(13);
			return false;
		}

		FLEXPART_CHK(getParamValue(inPath,dataR,"INPUT_DATA_PATH"));
		FLEXPART_CHK(getParamValue(fAvailable,dataR,"AVAILABLE_FILE_PATH"));
	}	
	else if(strcmp(input_mode,"PATH") == 0) 
	{
	  	FLEXPART_CHK(getParamValue(inPath,in,"FLEXPART_INPUT_PATH"));
		FLEXPART_CHK(getParamValue(fAvailable,in,"FLEXPART_AVAILABLE_FILE_PATH"));

		if(fAvailable == "SAME_AS_INPUT_PATH")
		{
			fAvailable = inPath + "/AVAILABLE";
		}	
	}
	else
	{
		marslog(LOG_EROR,"Invalid value for parameter FLEXPART_INPUT_MODE: %s",input_mode);
		setError(13);
		return false;
	}
	
	//Pathnames file	
	ofstream out(fPathnames.c_str());	
	out << optionsPath << "/" << endl;
	out << outPath << "/" << endl;
	out << inPath << "/" << endl;
	out << fAvailable << endl;
	out << "================================================" << endl;
	out << " ";
	out.close();
	
	return true;
}
	
bool FlexpartRun::generateCommandFile(const string& fCmd,MvRequest& in)
{
	ofstream out(fCmd.c_str());	
	
	string str,str2,trMode;
		
out << "*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n";
	
	//FLEXPART_CHK(getParamValue(str,in,"FLEXPART_RUN_LABEL"));
	//out << str << endl;
	
	FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_SIMULATION_DIRECTION",directionIds_));
	out << str << endl;
	
	FLEXPART_CHK(getParamValue(str,in,"FLEXPART_STARTING_DATE"));
	FLEXPART_CHK(getDate(str,str2,"FLEXPART_STARTING_DATE"));	
	out << str2 << " ";
		
	FLEXPART_CHK(getParamValue(str,in,"FLEXPART_STARTING_TIME"));
	FLEXPART_CHK(getTime(str,str2,"FLEXPART_STARTING_TIME"));
	out << str2 << endl;
		
	FLEXPART_CHK(getParamValue(str,in,"FLEXPART_ENDING_DATE"));
	FLEXPART_CHK(getDate(str,str2,"FLEXPART_ENDING_DATE"));	
	out << str2 << " ";
	
	FLEXPART_CHK(getParamValue(str,in,"FLEXPART_ENDING_TIME"));
	FLEXPART_CHK(getTime(str,str2,"FLEXPART_ENDING_TIME"));
	out << str2 << endl;
	
	FLEXPART_CHK(getParamValue(str,in,"FLEXPART_OUTPUT_INTERVAL"));
	FLEXPART_CHK(getTimeLen(str,str2,"FLEXPART_OUTPUT_INTERVAL",true));
	out << str2 << endl;
	
	FLEXPART_CHK(getParamValue(str,in,"FLEXPART_OUTPUT_AVERAGING_INTERVAL"));
	FLEXPART_CHK(getTimeLen(str,str2,"FLEXPART_OUTPUT_AVERAGING_INTERVAL",true));
	out << str2 << endl;
	
	FLEXPART_CHK(getParamValue(str,in,"FLEXPART_OUTPUT_SAMPLING_INTERVAL"));
	FLEXPART_CHK(getTimeLen(str,str2,"FLEXPART_OUTPUT_SAMPLING_INTERVAL",true));
	out << str2 << endl;
	
	FLEXPART_CHK(getParamValue(str,in,"FLEXPART_PARTICLE_SPLITTING_INTERVAL"));
	FLEXPART_CHK(getTimeLen(str,str2,"FLEXPART_PARTICLE_SPLITTING_INTERVAL",true));
	out << str2 << endl;
	
	FLEXPART_CHK(getParamValue(str,in,"FLEXPART_SYNC_INTERVAL"));
	FLEXPART_CHK(getTimeLen(str,str2,"FLEXPART_SYNC_INTERVAL",true));
	out << str2 << endl;
	
	FLEXPART_CHK(getParamValue(str,in,"FLEXPART_CTL"));
	out << str << endl;
	
	FLEXPART_CHK(getParamValue(str,in,"FLEXPART_VERT_REDUCTION"));
	out << str << endl;
	
	FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_OUTPUT_FORM",outputIds_));
	out << str << endl;
	
	FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_DUMP_PARTICLE_POSITIONS",particleDumpIds_));
	out << str << endl;
	
	FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_SUBGRID_TERRAIN",onOffIds_));
	out << str << endl;
	
	FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_CONVECTION",onOffIds_));
	out << str << endl;
	
	FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_AGE_SPECTRA",onOffIds_));
	out << str << endl;
		
	//Cont simulation with dumped particle data
	out << "0" << endl;
		
	FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_OUTPUT_FOR_EACH_RELEASE",onOffIds_));
	out << str << endl;
	
	FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_COMPUTE_FLUXES",onOffIds_));
	out << str << endl;
	
	FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_DOMAIN_FILL",onOffIds_));
	out << str << endl;
	
	FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_SOURCE_UNITS",sourceUnitsIds_));
	out << str << endl;
	
	FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_RECEPTOR_UNITS",receptorUnitsIds_));
	out << str << endl;
	
	FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_TRACK_PARTICLES",onOffIds_));
	out << str << endl;
	
	FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_NESTED_OUTPUT",onOffIds_));
	out << str << endl;
	
	FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_WRITE_INITIAL_CONDITIONS",writeInitIds_));
	out << str << endl;
	
	/*
	
	FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_OUTPUT_INTERVAL_MODE",intervalIds_));
	out << str << " ";
	FLEXPART_CHK(getParamValue(str,in,"FLEXPART_OUTPUT_INTERVAL_VALUE"));
	
	if(str.find("0") != string::npos &&  str.find_first_not_of("0") == string::npos)
	{
		marslog(LOG_EROR,"Invalid value specified for FLEXPART_OUTPUT_INTERVAL_VALUE: %s",str.c_str());		
		marslog(LOG_EROR,"It has to be greater than 0!");
		setError(13);
		return false;	
	}  
	
	FLEXPART_CHK(getTimeLen(str,str2,"FLEXPART_OUTPUT_INTERVAL_VALUE",true));
	out << str2 << endl;
	
	//It might be disabled in the inteface (for CET and FLIGHT modes) 
	getParamValue(str,in,"FLEXPART_UNCERTAINTY_TRAJECTORIES",true);
	if(str == "ON")
	{	
		FLEXPART_CHK(getParamValue(str,in,"FLEXPART_UNCERTAINTY_TRAJECTORY_NUMBER"));
		out << str << " ";
		FLEXPART_CHK(getParamValue(str,in,"FLEXPART_UNCERTAINTY_TRAJECTORY_DISTANCE"));
		out << str << " ";	
		FLEXPART_CHK(getParamValue(str,in,"FLEXPART_UNCERTAINTY_TRAJECTORY_TIME_CONSTANT"));
		out << str << " ";
		FLEXPART_CHK(getParamValue(str,in,"FLEXPART_U_RANDOM_ERROR"));
		out << str << " ";
		FLEXPART_CHK(getParamValue(str,in,"FLEXPART_V_RANDOM_ERROR"));
		out << str << " ";
		FLEXPART_CHK(getParamValue(str,in,"FLEXPART_W_RANDOM_ERROR"));
		out << str << endl;
	}
	else
	{
	   out << "0 0.5 2.0 0.08 0.08 0.08" << endl;
	  
	}  
	
	
	FLEXPART_CHK(getParamValue(str,in,"FLEXPART_INTERPOLATION_TYPE"));
	out << str << endl;	
	
	FLEXPART_CHK(getParamValue(str,in,"FLEXPART_CFL_SPATIAL"));
	out << str << endl;	
	
	FLEXPART_CHK(getParamValue(str,in,"FLEXPART_CFL_TEMPORAL"));
	out << str << endl;
	
	//FLEXPART_CHK(getParamValueId(str,in,"FLEXPART_RUN_MODE",modeIds_));
	out << trMode << endl;
	*/
	
	out.close();
	
	return true;
}	
	
bool FlexpartRun::generateReleasesFile(const string& fRelease,MvRequest& in)
{
	ofstream out(fRelease.c_str());	
	
	string str;
	
out << "*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n";
	
	vector<string> sp;	
	FLEXPART_CHK(getParamValue(sp,in,"FLEXPART_RELEASE_SPECIES"));
	if(sp.size() < 1 )
	{
	  	marslog(LOG_EROR,"No paramater FLEXPART_RELEASE_SPECIES is specified!");
		setError(13);
		return false;	
	}  
	
	//vector<string> name,startDate,startTime,endDate,endTime,
	//	west,east,south,north,topLevl,bottomLevel,levUnit,
	//	particles,mass;
		
	map<string,vector<string> > vals;
	vector<string> parLst;
	parLst.push_back("NAMES");
	parLst.push_back("STARTING_DATES");
	parLst.push_back("STARTING_TIMES");
	parLst.push_back("ENDING_DATES");
	parLst.push_back("ENDING_TIMES");
	parLst.push_back("AREAS_WEST");
	parLst.push_back("AREAS_EAST");
	parLst.push_back("AREAS_NORTH");
	parLst.push_back("AREAS_SOUTH");
	parLst.push_back("LEVELS_TOP");
	parLst.push_back("LEVELS_BOTTOM");
	parLst.push_back("LEVELS_UNITS");
	parLst.push_back("PARTICLES");
	parLst.push_back("MASSES");
	
	for(unsigned int i=0; i < parLst.size() ; i++)
	{
	  	string s="FLEXPART_RELEASE_" + parLst[i];
	  	FLEXPART_CHK(getParamValue(vals[s],in,s));
	}
	
	/*FLEXPART_CHK(getParamValue(name,in,"FLEXPART_RELEASE_NAMES"));
	FLEXPART_CHK(getParamValue(startDate,in,"FLEXPART_RELEASE_STARTING_DATES"));
	FLEXPART_CHK(getParamValue(startTime,in,"FLEXPART_RELEASE_STARTING_TIMES"));
	FLEXPART_CHK(getParamValue(endDate,in,"FLEXPART_RELEASE_ENDING_DATES"));
	FLEXPART_CHK(getParamValue(endTime,in,"FLEXPART_RELEASE_ENDING_TIMES"));
	FLEXPART_CHK(getParamValue(west,in,"FLEXPART_RELEASE_AREAS_WEST"));
	FLEXPART_CHK(getParamValue(east,in,"FLEXPART_RELEASE_AREAS_EAST"));
	FLEXPART_CHK(getParamValue(north,in,"FLEXPART_RELEASE_AREAS_NORTH"));
	FLEXPART_CHK(getParamValue(south,in,"FLEXPART_RELEASE_AREAS_SOUTH"));
	FLEXPART_CHK(getParamValue(topLevel,in,"FLEXPART_RELEASE_LEVELS_TOP"));
	FLEXPART_CHK(getParamValue(bottomLevel,in,"FLEXPART_RELEASE_LEVELS_BOTTOM"));
	FLEXPART_CHK(getParamValue(levUnit,in,"FLEXPART_RELEASE_LEVELS_UNITS"));
	FLEXPART_CHK(getParamValue(particle,in,"FLEXPART_RELEASE_PARTICLES"));
	FLEXPART_CHK(getParamValue(mass,in,"FLEXPART_RELEASE_MASS"));*/
		
	unsigned int cnt=vals["FLEXPART_RELEASE_NAMES"].size();	
	if(cnt ==0)
	{
		marslog(LOG_EROR,"No values specified for parameter FLEXPART_RELEASE_NAMES!");
	 	setError(13);
		return false; 
	}
	
	string errTxt="Incosistent number of items specified for parameter: ";
	for(map<string,vector<string> >::iterator it=vals.begin(); it != vals.end(); it++ )
	{
	  	if(it->second.size() != cnt)
		{
		  	string errTxt="Incosistent number of items specified for parameter: " + it->first + "!";
			marslog(LOG_EROR,"%s",errTxt.c_str());
			setError(13);
			return false; 
		}
	}	
	
	out  << sp.size() << endl;
	for(unsigned int i=0; i < sp.size(); i++)
	{
	  	out << sp[i] << endl;
	}
	out << "===================================================================" << endl;
	
	for(unsigned int i=0; i < cnt; i++)
	{	  
		string tStr, dStr;
		string pref="FLEXPART_RELEASE_";
	  	FLEXPART_CHK(getDate(vals[pref + "STARTING_DATES"].at(i),dStr,pref+"STARTING_DATES"));		
		FLEXPART_CHK(getTime(vals[pref + "STARTING_TIMES"].at(i),tStr,pref+"STARTING_TIMES"));
		
		out << dStr << " " << tStr << endl;		
			
		FLEXPART_CHK(getDate(vals[pref + "ENDING_DATES"].at(i),dStr,pref+"ENDING_DATES"));		
		FLEXPART_CHK(getTime(vals[pref + "ENDING_TIMES"].at(i),tStr,pref+"ENDING_TIMES"));
		
		out << dStr << " " << tStr << endl;	
		
		out << vals[pref + "AREAS_WEST"].at(i) << endl;
		out << vals[pref + "AREAS_SOUTH"].at(i) << endl;
		out << vals[pref + "AREAS_EAST"].at(i) << endl;
		out << vals[pref + "AREAS_NORTH"].at(i) << endl;
		out << vals[pref + "LEVELS_UNITS"].at(i) << endl;
		out << vals[pref + "LEVELS_BOTTOM"].at(i) << endl;
		out << vals[pref + "LEVELS_TOP"].at(i) << endl;
		out << vals[pref + "PARTICLES"].at(i) << endl;
		out << vals[pref + "MASSES"].at(i) << endl;
		out << vals[pref + "NAMES"].at(i) << endl;
		out << "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << endl;

	}

	out.close();
	
	return true;
}	


bool FlexpartRun::generateOutGridFile(const string& fGrid,MvRequest& in)
{
	ofstream out(fGrid.c_str());	
	
out << "*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\
*** HEADER ***\n\n";

	string west,south,name,nx,ny,dx,dy,dz;
	
	FLEXPART_CHK(getParamValue(west,in,"FLEXPART_GRID_WEST"));
	FLEXPART_CHK(getParamValue(south,in,"FLEXPART_GRID_SOUTH"));
	FLEXPART_CHK(getParamValue(nx,in,"FLEXPART_GRID_NX"));
	FLEXPART_CHK(getParamValue(ny,in,"FLEXPART_GRID_NY"));
	FLEXPART_CHK(getParamValue(dx,in,"FLEXPART_GRID_DX"));
	FLEXPART_CHK(getParamValue(dy,in,"FLEXPART_GRID_DY"));
	
	int cnt = in.countValues("FLEXPART_GRID_LEVELS");
	if(cnt < 1 )
	{
	  	marslog(LOG_EROR,"No paramater FLEXPART_GRID_LEVELS is specified!");
		setError(13);
		return false;	
	}  
	  
	double dval; 
	vector<double> levL;
	for(int i=0; i< cnt && i < 6; i++)
	{
		in.getValue(dval,"FLEXPART_GRID_LEVELS",i);
	 	levL.push_back(dval);
	}

	float fVal;
	int iVal;
	
	out << std::fixed;
	
	istringstream(west) >> fVal;
	out << "-------" << endl;
	out << "    " << std::setw(6) << setprecision(4) << fVal << endl;
	out << "OUTLONLEFT" << endl;
	out << endl;
	
	istringstream(south) >> fVal;
	out << "-------" << endl;
	out << "    " << std::setw(6) << setprecision(4) << fVal << endl;
	out << "OUTLATLOWER" << endl;
	out << endl;
		
	istringstream(nx) >> iVal;
	out << "-------" << endl;
	out << "    " <<  std::setw(5) << iVal << endl;
	out << "NUMXGRID" << endl;
	out << endl;
	
	istringstream(ny) >> iVal;
	out << "-------" << endl;
	out << "    " << std::setw(5) << iVal << endl;
	out << "NUMYGRID" << endl;
	out << endl;
	
	istringstream(dx) >> fVal;
	out << "-------" << endl;
	out << "    " << std::setw(6) << setprecision(3) << fVal << endl;
	out << "DXOUTLON" << endl;
	out << endl;
	
	istringstream(dy) >> fVal;
	out << "-------" << endl;
	out << "    " << std::setw(6) << setprecision(3) << fVal  << endl;
	out << "DYOUTLAT" << endl;
	out << endl;
	
	for(int i=0; i< static_cast<int>(levL.size()); i++)
	{
		out << "-------" << endl;
		out << "    " << std::setw(5) << setprecision(1) << levL[i] << endl;
		out << "LEVEL" << endl;
		out << endl;
	}
		
	out.close();
	
	return true;
}	


bool FlexpartRun::generateAgeClassesFile(const string& fAge,MvRequest& in)
{
	ofstream out(fAge.c_str());	
	
out << "*** HEADER ***\n\
*** HEADER ***\n*** HEADER ***\n\
*** HEADER ***\n*** HEADER ***\n\
*** HEADER ***\n*** HEADER ***\n\
*** HEADER ***\n*** HEADER ***\n\
*** HEADER ***\n*** HEADER ***\n\
*** HEADER ***\n*** HEADER ***\n";

	vector<string> vals;
	FLEXPART_CHK(getParamValue(vals,in,"FLEXPART_AGECLASSES"));

	int cnt = static_cast<int>(vals.size()); 
	if(cnt < 1 )
	{
	  	marslog(LOG_EROR,"No paramater FLEXPART_AGECLASSES is specified!");
		setError(13);
		return false;	
	}  
	
	out << cnt << endl;
	 	
	for(int i=0; i< cnt; i++)
	{
		string str;
	 	FLEXPART_CHK(getTimeLen(vals[i],str,"FLEXPART_AGECLASSES",true));
		out << str << endl;
	}
		
	out.close();
	
	return true;
}	

bool FlexpartRun::generateReceptorsFile(const string& fRec,MvRequest& in)
{
	ofstream out(fRec.c_str());	
	
out << "*** HEADER ***\n\
*** HEADER ***\n*** HEADER ***\n\
*** HEADER ***\n*** HEADER ***\n\
*** HEADER ***\n*** HEADER ***\n";

	out.close();
	
	return true;
}

void FlexpartRun::serve( MvRequest& in, MvRequest& out)
{
  	cout << "--------------FlexpartRun::serve()--------------" << endl;
  	in.print();

	//Find out flexpart script path
	string flexpartScript;
	char *mvbin=getenv("METVIEW_BIN");
	if (mvbin == 0)  
	{	
		marslog(LOG_EROR,"No METVIEW_BIN env variable is defined. Cannot locate script mv_flexpart_run!");
		setError(13);
		return;
	}
	else
	{
		flexpartScript=string(mvbin) +"/mv_flexpart_run";
	}
	

	//Create  tmp dir for the flexpart run
	string tmpPath;
	if(!generateTmpPath(tmpPath))
	{
		return;
	}
	
	//Genarate pathnames  file
	string fPathnames=tmpPath + "/pathnames";
	string optionsPath=tmpPath;
	string outPath=tmpPath;
	if(!generatePathnamesFile(fPathnames,in,optionsPath,outPath))
	{
	  	return;
	}	
	
	//Generate COMMAND file
	string fCmd=tmpPath + "/COMMAND";
	if(!generateCommandFile(fCmd,in))
	{
	  	return;
	}
	
	//Generate OUTGRID file
	string fGrid=tmpPath + "/OUTGRID";
	if(!generateOutGridFile(fGrid,in))
	{
	  	return;
	}
	
	//Generate RELEASES file
	string fRelease=tmpPath + "/RELEASES";
	if(!generateReleasesFile(fRelease,in))
	{
	  	return;
	}
	
	//Generate AGECLASSES file
	string fAge=tmpPath + "/AGECLASSES";
	if(!generateAgeClassesFile(fAge,in))
	{
	  	return;
	}
	
	//Generate AGECLASSES file
	string fReceptors=tmpPath + "/RECEPTORS";
	if(!generateReceptorsFile(fReceptors,in))
	{
	  	return;
	}
	
	//Flexpart exe
	string exe;	
	const char *exeC=in("FLEXPART_EXE_PATH");
	if(exeC)
	{
		exe=string(exeC);
	}
	if(!exeC || exe.empty())
	{
	  	exe="_UNDEF_";
	}	
	

	//-----------------------
	// Run FLEXPART
	//-----------------------
	
	//Find out the directory where the Flexpart Run icon is located
	/*string callerDir;
	const char* callerIcon=in("_NAME");
	if(callerIcon)
	{
	  	callerDir=string(callerIcon);
	  	
		char *mvudir=getenv("METVIEW_USER_DIRECTORY");
		if(mvudir)  
		{
	  		callerDir=string(mvudir) + "/" + callerDir;
		}	
	  	
	  	string::size_type pos=callerDir.find_last_of("/");
	 	if(pos != string::npos)
		{
		 	callerDir=callerDir.substr(0,pos);
		}	
	}
	  
	//Set the output path where the resulting files will be coupied
	string userOutPath;
	if(!getParamValue(userOutPath,in,"OUTPUT_PATH") || userOutPath.empty())
	{
	  	marslog(LOG_EROR,"No parameter OUTPUT_PATH is defined!");
		setError(13);	
		return;
	}
	
	if(userOutPath == "CURRENT_FOLDER")
	{
	  	if(callerDir.empty()) 
		{
		  	marslog(LOG_EROR,"Could not set OUTPUT_PATH properly to \"CURRENT_DIR\"!");
			setError(13);	
			return;
		}  		  
		userOutPath=callerDir;		  
	}  
	*/

	string resFileName="res.txt";
	string logFileName="log.txt";
	
	//Run the flexpart script
	string cmd = flexpartScript + " \"" + tmpPath + "\" \"" + logFileName + "\" \"" + exe + "\""; 

	//marslog(LOG_INFO,"Execute command: %s",cmd.c_str());
	cout << "Execute command: " << cmd << endl;
	
	int ret=system(cmd.c_str());	
	
	//If the script failed read log file and
	//write it into LOG_EROR
	if(ret == -1 || WEXITSTATUS(ret) != 0)
	{
		string logFile=tmpPath + "/" + logFileName;		
		ifstream in(logFile.c_str());
		string line;

		if(WEXITSTATUS(ret) == 255)
		{
		  	marslog(LOG_WARN,"Warnings generated during FLEXPART run!");
			while(getline(in,line))
			{
				marslog(LOG_WARN,"%s",line.c_str());
			}
			in.close();
			//setError(13);
		}  		
		else if(WEXITSTATUS(ret) == 1)
		{		
			marslog(LOG_EROR,"Failed to perform FLEXPART run!");
			while(getline(in,line))
			{
				marslog(LOG_EROR,"%s",line.c_str());
			}
			in.close();
			setError(13);
			return;
		}
		else if(WEXITSTATUS(ret) > 1)
		{		
			marslog(LOG_EROR,"FLEXPART run failed with exit code: %d !",WEXITSTATUS(ret));
			while(getline(in,line))
			{
				marslog(LOG_EROR,"%s",line.c_str());
			}
			in.close();
			setError(13);
			return;
		}
		
	}
	
	string resFile= tmpPath + "/" + resFileName;
		
	out=MvRequest("FLEXPART_FILE");
	out("PATH")=resFile.c_str();
	
	out.print();	
}

  	
int main( int argc, char** argv )
{
	MvApplication theApp( argc, argv,"FlexpartRun");

    	FlexpartRun flexpartRun;	
	
    	theApp.run();
}


