/***************************** 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 <Metview.h>
#include <MvPath.hpp>
#include <MvScanFileType.h>

MvRequest::MvRequest(const char *verb)
{
	_overwrite = 1;
	CurrentRequest = FirstRequest = empty_request(verb);
}

MvRequest::MvRequest(request* r,boolean clone)
{
	_overwrite = 1;
	CurrentRequest = FirstRequest = clone?clone_all_requests(r):r;
}

MvRequest::MvRequest(const MvRequest &r)

{
	_overwrite = 1;
	CurrentRequest = FirstRequest = clone_all_requests(r.FirstRequest);

	// Make sure currents match
	request *s = r.FirstRequest;
	while(s && s != r.CurrentRequest)
	{
		s = s->next;
		CurrentRequest = CurrentRequest->next;
	}
}

MvRequest::~MvRequest()
{
	free_all_requests(FirstRequest);
}

void MvRequest::clean()
{
	free_all_requests(FirstRequest);
	FirstRequest = CurrentRequest = 0;
	CurrentValue = 0;
}

MvRequest& MvRequest::operator=(const MvRequest& r)
{
	free_all_requests(FirstRequest);
	CurrentRequest = FirstRequest = clone_all_requests(r.FirstRequest);

	// Make sure currents match
	request *s = r.FirstRequest;
	while(s && s != r.CurrentRequest)
	{
		s = s->next;
		CurrentRequest = CurrentRequest->next;
	}
	return *this;
}

//MvRequest& MvRequest::operator=(const request *r)
//{
//	free_all_requests(FirstRequest);
//	CurrentRequest = FirstRequest = clone_all_requests(r);
//	return *this;
//}

MvRequest MvRequest::operator+(const MvRequest& r) const
{
	if(CurrentRequest == NULL) return r;

	request *a = clone_all_requests(CurrentRequest);
	request *b = clone_all_requests(r.CurrentRequest);

	request *q = NULL, *p = a;

	while(p)
	{
		q = p;
		p = p->next;
	}

	q->next = b;
	return MvRequest(a,false);
}

void MvRequest::operator+=(const MvRequest& r)
{
	request *a = NULL;
	request *b = NULL;
	
	if (CurrentRequest)
	{
		a = CurrentRequest;
	}

	if (r.CurrentRequest)
	{
		b = clone_all_requests(r.CurrentRequest);
	}

	request *q = NULL, *p = a;

	if (a)
	{
		while(p)  // find the end of request a
		{
			q = p;
			p = p->next;
		}

		q->next = b;

	}
	else
	{
		CurrentRequest = FirstRequest = b;
	}
}


void MvRequest::copyFromCurrent(const MvRequest &r)
{
    _overwrite = 1;
    CurrentRequest = FirstRequest = clone_all_requests(r.CurrentRequest);
}

void MvRequest::copyFromCurrentTo(const MvRequest &r, const char *verb)
{
    _overwrite = 1;
    CurrentRequest = FirstRequest = copyFromCurrentTo_Recursive(r.CurrentRequest, verb);
}

request *MvRequest::copyFromCurrentTo_Recursive(const request *r, const char *verb)
{
    if (r)
    {
        request *q = clone_one_request(r);
        if (strcmp(request_verb(r), verb))  // if not the verb we're looking for
        {
            q->next = copyFromCurrentTo_Recursive(r->next, verb);
        }
        return q;
    }
    return 0;
}



void MvRequest::setVerb(const char* v)
{
	if(FirstRequest)
	{
		strfree(CurrentRequest->name);
		CurrentRequest->name = strcache(v);
	}
	else FirstRequest = CurrentRequest = empty_request(v);
}

int MvRequest::countValues(const char* p) const
{
	return count_values(CurrentRequest, p);

}

void MvRequest::print() const
{
  if( mvDebugPrint() )  //-- to control prints that go to log files
    {
	print_all_requests(CurrentRequest);
	fflush(stdout);  //-- may be mixed with C++ io
    }
}

const char *MvRequest::getVerb() const
{
	return CurrentRequest?CurrentRequest->name:NULL;
}

void MvRequest::unsetParam(const char* pname)
{
	unset_value(CurrentRequest, pname);
}

void MvRequest::read(const char* fileNamePath, bool expand)
{
   // Read request using MARS library
   // The problem here is that this function does not expand any
   // subrequests. This expansion will be done manually, if second
   // parameter is true.
   free_all_requests(FirstRequest);
   CurrentRequest = FirstRequest = read_request_file(fileNamePath);

   if ( !expand )
      return;

   // Get object request. This will help to find out if a parameter
   // is a subrequest, which in this case will need to be expanded.
   request* obj = this->findRequestObject();
   if ( obj == NULL )
      return;

   // Expand subrequests
   string path = mdirname(fileNamePath);
   this->importSubObjects(path,obj);

   return;
}

void MvRequest::save(const char* file) const
{
	FILE* fp = fopen(file, "w");
	if (fp)
	{
		save(fp);
		fclose(fp);
	}
}

void MvRequest::save(FILE* file) const
{
	save_all_requests(file, FirstRequest);
}


void MvAccess::operator=(const MvAccess& a)
{
	if(this == &a)
		marslog(LOG_WARN,"MvAccess::operator= cannot work on the same"
			" object (%s/%d)",LastGet,LastIndex);

	set_value(
		Request->CurrentRequest,LastGet,"%s",
		get_value(a.Request->CurrentRequest,a.LastGet,a.LastIndex)
	);
	LastGet = NULL;
	LastIndex = 0;
}

MvAccess::operator const char*() const
{
	return get_value(Request->CurrentRequest, LastGet, LastIndex);
}

MvConstAccess::operator const char*() const
{
	return get_value(Request->CurrentRequest, LastGet, LastIndex);
}

MvAccess::operator double() const
{
	const char *p = get_value(Request->CurrentRequest, LastGet, LastIndex);
	return p?atof(p):0;
}

MvConstAccess::operator double() const
{
	const char *p = get_value(Request->CurrentRequest, LastGet, LastIndex);
	return p?atof(p):0;
}

MvAccess::operator int() const
{
	const char *p = get_value(Request->CurrentRequest, LastGet, LastIndex);
	return p?atoi(p):0;
}

MvConstAccess::operator int() const
{
	const char *p = get_value(Request->CurrentRequest, LastGet, LastIndex);
	return p?atoi(p):0;
}

MvAccess::operator MvDate() const
{
	long save = expand_flags(0); // So it is working OK
	const char *p = get_value(Request->CurrentRequest, LastGet, LastIndex);
	expand_flags(save);
	return MvDate(p);
}

MvConstAccess::operator MvDate() const
{
	long save = expand_flags(0); // So it is working OK
	const char *p = get_value(Request->CurrentRequest, LastGet, LastIndex);
	expand_flags(save);
	return MvDate(p);
}

MvAccess::operator long() const
{
	const char *p = get_value(Request->CurrentRequest, LastGet, LastIndex);

	/* backward compatiblity */
	long julian,second;
	boolean dum;
	if(p && parsedate(p,&julian,&second,&dum))
		return julian_to_date(julian,false);

	return p?atol(p):0;
}
MvConstAccess::operator long() const
{
	const char *p = get_value(Request->CurrentRequest, LastGet, LastIndex);

	/* backward compatiblity */
	long julian,second;
	boolean dum;
	if(p && parsedate(p,&julian,&second,&dum))
		return julian_to_date(julian,false);

	return p?atol(p):0;
}


MvAccess::operator request*() const
{
	return get_subrequest(Request->CurrentRequest, LastGet, LastIndex);
}

void MvAccess::operator= (const char* val)
{
	if (LastGet) set_value(Request->CurrentRequest, LastGet, "%s", val);
	LastGet = NULL;
	LastIndex = 0;
}
void MvAccess::operator= (double val)
{
	if (LastGet) set_value(Request->CurrentRequest, LastGet, "%.12g", val);
	LastGet = NULL;
	LastIndex = 0;
}
void MvAccess::operator= (int val)
{
	if (LastGet) set_value(Request->CurrentRequest, LastGet, "%d", val);
	LastGet = NULL;
	LastIndex = 0;
}
void MvAccess::operator= (const request* val)
{
	if (LastGet) set_subrequest(Request->CurrentRequest, LastGet, val);
	LastGet = NULL;
	LastIndex = 0;
}
void MvAccess::operator= (long val)
{
	if (LastGet) set_value(Request->CurrentRequest, LastGet, "%ld", val);
	LastGet = NULL;
	LastIndex = 0;
}

void MvAccess::operator= (const MvDate& val)
{
	char buf[80];
	val.Format("yyyy-mm-dd HH:MM:SS",buf);
	if (LastGet) set_value(Request->CurrentRequest,
		LastGet, "%s", buf);
	LastGet = NULL;
	LastIndex = 0;
}

void MvAccess::operator+= (const request* val)
{
	add_subrequest(Request->CurrentRequest, LastGet,val);
}

void MvAccess::operator+= (const MvDate& val)
{
	char buf[80];
	val.Format("yyyy-mm-dd HH:MM:SS",buf);
	if (LastGet) add_value(Request->CurrentRequest,
		LastGet, "%s", buf);
	LastGet = NULL;
	LastIndex = 0;
}

void MvAccess::operator+= (const char* val)
{
	if (LastGet) add_value(Request->CurrentRequest, LastGet, "%s", val);
	LastGet = NULL;
	LastIndex = 0;
}

void MvAccess::operator+= (const MvAccess& a)
{
	if(this == &a)
		marslog(LOG_WARN,"MvAccess::operator+= cannot work on the same"
			" object (%s/%d)",LastGet,LastIndex);

	add_value(
		Request->CurrentRequest,LastGet,"%s",
		get_value(a.Request->CurrentRequest,a.LastGet,a.LastIndex)
	);
	LastGet = NULL;
	LastIndex = 0;
}

void MvRequest::getValue(int& v, const char* p, int i) const
{
	const char *t = get_value(CurrentRequest, p, i);
	v = (t) ? atoi(get_value(CurrentRequest, p, i)) : 0;
}

void MvRequest::getValue(double& v, const char* p, int i) const
{
	const char *t = get_value(CurrentRequest, p, i);
	v = (t) ? atof(get_value(CurrentRequest, p, i)) : 0;
}

void MvRequest::getValue(const char*& v, const char* p, int i) const
{
	v = get_value(CurrentRequest, p, i);
}

void MvRequest::getValue(Cached& v, const char* p, int i) const
{
	v = get_value(CurrentRequest, p, i);
}

void MvRequest::getValue(void*& v, const char* p, int i) const
{
	sscanf(get_value(CurrentRequest, p, i), "%p", &v);
}

void MvRequest::getValue(MvRequest& v, const char* name,int i) const
{
	v = get_subrequest(CurrentRequest, name, i );
}

MvRequest  MvRequest::getSubrequest(const char* name,int i) const
{
	return MvRequest(get_subrequest(CurrentRequest, name, i),false);
}


int MvRequest::iterInit( const char* param )
{
  parameter *p = find_parameter( CurrentRequest, param );
  if( p == 0 )
    {
      CurrentCount = 0;
      CurrentValue = 0;
    }
  else
    {
      CurrentCount = count_values( CurrentRequest, param );
      CurrentValue = p->values;
    }

  return CurrentCount;    //-- 'iterInit' returns parameter count
}

bool MvRequest::iterGetNextValue(const char*& val)
{
  bool myStat = false;
  if( CurrentValue && CurrentValue->name )
    {
      val    = CurrentValue->name;
      myStat = true;
    }
  else
      val = 0;

  if( CurrentValue )
    CurrentValue = CurrentValue->next;

  return myStat;
}

bool MvRequest::iterGetNextValue(double& val)
{
  bool myStat = false;
  if( CurrentValue && CurrentValue->name )
    {
      val    = atof(CurrentValue->name);
      myStat = true;
    }
  else
      val = 0;

  if( CurrentValue )
    CurrentValue = CurrentValue->next;

  return myStat;
}

void MvRequest::setValue(const char* p, double v)
{
	set_value(CurrentRequest, p, "%.12g", v);
}

void MvRequest::setValue(const char* p, const void* v)
{
	set_value(CurrentRequest, p, "%p", v);
}

void MvRequest::setValue(const char* p, int v)
{
	set_value(CurrentRequest, p, "%d", v);
}

void MvRequest::setValue(const char* p, const char* v)
{
	set_value(CurrentRequest, p, "%s", v);
}

void MvRequest::setValue(const char* p, long v)
{
	set_value(CurrentRequest, p, "%ld", v);
}

void MvRequest::setValue(const char* p,const request *r)
{
	set_subrequest(CurrentRequest, p, r);
}

void MvRequest::setValue(const char* p, const MvRequest& v)
{
	set_subrequest(CurrentRequest, p, v);
}

void MvRequest::addValue(const char* p, double v)
{
	add_value(CurrentRequest, p, "%.12g", v);
}

void MvRequest::addValue(const char* p, const void* v)
{
	add_value(CurrentRequest, p, "%p", v);
}

void MvRequest::addValue(const char* p, int v)
{
	add_value(CurrentRequest, p, "%d", v);
}

void MvRequest::addValue(const char* p, const char* v)
{
	if( v )
	  add_value(CurrentRequest, p, "%s", v);
}

void MvRequest::addValue(const char* p, long v)
{
	add_value(CurrentRequest, p, "%ld", v);
}

void MvRequest::addValue(const char* p, const MvRequest& v)
{
	MvRequest sub;
	getValue(sub,p,0);
	setValue(p,sub+v);
}

MvRequest& MvRequest::rewind()
{
	CurrentRequest = FirstRequest;
	return *this;
}

MvRequest& MvRequest::advance()
{
	if(CurrentRequest) CurrentRequest = CurrentRequest->next;
	return *this;
}

void MvRequest::advanceToEnd ()
{
     while(CurrentRequest)
          advance();
}

MvRequest& MvRequest::advanceTo ( string& verb )
{
     while(CurrentRequest)
     {
          if ( getVerb() == verb )
               break;

          advance();
     }
     return *this;
}

MvRequest& MvRequest::advanceAfter ( string& verb )
{
     while(CurrentRequest)
     {
          if ( getVerb() == verb )
          {
               advance();
               break;
          }

          advance();
     }
     return *this;
}

MvRequest MvRequest::justOneRequest() const
{
	return MvRequest(clone_one_request(CurrentRequest),false);
}

#if 0
//-- following commented-out functions are now (May 2008) obsolete
//
// Set value to list of requests, if request name matches
//

void set_value_to_requests(int overwrite, request* first_reqst, const char* reqname, const char* parname, const char* parformat, ...)
{
	char parvalue[1024];
	va_list ap;
	va_start(ap,parformat);
	vsprintf(parvalue, parformat, ap);

	request* reqst;
	for (reqst = first_reqst; reqst; reqst = reqst->next)
	{
		if (!strcmp(reqst->name, reqname))
		{
			if (overwrite || !get_value(reqst, parname, 0))
				set_value(reqst, parname, parvalue);
		}
	}
}

void add_value_to_requests(request* first_reqst, const char* reqname, const char* parname, const char* parformat, ...)
{
	char parvalue[1024];
	va_list ap;
	va_start(ap,parformat);
	vsprintf(parvalue, parformat, ap);

	request* reqst;
	for (reqst = first_reqst; reqst; reqst = reqst->next)
	{
		if (!strcmp(reqst->name, reqname))
			add_value(reqst, parname, parvalue);
	}
}

void MvRequest :: setValueToAll(const char* reqname, const char* parname, const char* value)
{
	set_value_to_requests(_overwrite, FirstRequest, reqname, parname, value);
}


void MvRequest :: setValueToAll(const char* reqname, const char* parname, int ivalue)
{
	char value[20];
	sprintf(value, "%d", ivalue);
	set_value_to_requests(_overwrite, FirstRequest, reqname, parname, value);
}

void MvRequest :: setValueToAll(const char* reqname, const char* parname, double fvalue)
{
	char value[20];
	sprintf(value, "%.12g", fvalue);
	set_value_to_requests(_overwrite, FirstRequest, reqname, parname, value);
}

void MvRequest :: addValueToAll(const char* reqname, const char* parname, const char* value)
{
	add_value_to_requests(FirstRequest, reqname, parname, value);
}

void MvRequest :: addValueToAll(const char* reqname, const char* parname, int ivalue)
{
	char value[20];
	sprintf(value, "%d", ivalue);
	add_value_to_requests(FirstRequest, reqname, parname, value);
}

void MvRequest :: addValueToAll(const char* reqname, const char* parname, double fvalue)
{
	char value[20];
	sprintf(value, "%.12g", fvalue);
	add_value_to_requests(FirstRequest, reqname, parname, value);
}
#endif

int MvRequest::countParameters() const
{
	if(!CurrentRequest) return 0;
	int n = 0;
	parameter *p = CurrentRequest->params;
	while(p)
	{
		n++;
		p = p->next;
	}
	return n;
}

const char *MvRequest::getParameter(int i) const
{
	if(!CurrentRequest) return NULL;

	int n = 0;
	parameter *p = CurrentRequest->params;
	while(p)
	{
		if(n++ == i) return p->name;
		p = p->next;
	}
	return NULL;
}

bool MvRequest::iterInitParam( )
{
	CurrentParam = CurrentRequest->params;

	return (CurrentParam ? true : false);
}

bool MvRequest::iterGetNextParamInterface(MvRequest& req)
{
	if( !CurrentParam )  //end of request
		return false;

	// clone the Interface request
	request *r = CurrentParam->interface;
	if ( r )
	{
		req = clone_all_requests(CurrentParam->interface);
	}
	else  	// if there is no Interface, creates a default one
	{
		req.clean();
		req.setVerb("Interface");
		req("interface") = "any";
	}

	CurrentParam = CurrentParam->next;
	return true;
}

#if 0
//-- following commented-out function is now (May 2008) obsolete
const char* MvRequest :: enquire(const char* name, const char* classe, const char* keyw)
{
	const char* classe_value;
	const char* cmd = NULL;
	request* reqst = FirstRequest;

	while (reqst)
	{
		if (!strcmp(name, reqst->name))
		{
			classe_value = get_value(reqst,"class",0);
			if (classe_value && !strcmp(classe_value, classe))
				cmd = get_value(reqst,keyw,0);
		}
		reqst = reqst->next;
	}

	return cmd;
}
#endif

const char* MvRequest :: enquire(const char* name, const char* keyw, int posit)
{
	const char* value = NULL;
	request* reqst = FirstRequest;

	while (reqst && !value)
	{
		if (!strcmp(name, reqst->name))
			value = get_value(reqst,keyw,posit);
		reqst = reqst->next;
	}
	return value;
}

// Apply the application override parameters to the current request

void MvRequest :: appOverrides(MvRequest& r)
{
	int i = -1;
	const char *parname, *parvalue;

	while( (parname = r("_APPLICATION_OVERRIDES",++i)) ) //-- xtra pranthesis to avoid warning
	{
		// reset parameter "parname"
		unset_value(CurrentRequest, parname);

		// copy parameter values from "r";
		int j = -1;
		while( (parvalue = r(parname,++j)) ) //-- xtra pranthesis to avoid warning
			add_value(CurrentRequest, parname, parvalue);

		// copy overrides
		add_value(CurrentRequest, "_APPLICATION_OVERRIDES", parname);
	}
}

void MvRequest :: merge(const MvRequest& r)
{
	update(r);                               //-- calls a member function (below)
}

void MvRequest :: mars_merge(const MvRequest& r)
{
	reqcpy(CurrentRequest,r.CurrentRequest); //-- calls a Mars function
}

void  MvRequest::update(const MvRequest& r)
{
	request *a = CurrentRequest;
	const request *b = r.CurrentRequest;

	if(!a || !b)
		return;

	parameter *p = b->params;
	while(p)
	{
		// Parameter not found in the target request
		if( find_parameter(a,p->name) == NULL )
		{
			p = p->next;
			continue;
		}

		boolean b = false;
		value *v = p->values;
		while(v)
		{
			update_value(a,p->name,v->name,b);
			b = true;
			v = v->next;
		}

		if(p->subrequest)
			set_subrequest(a,p->name,p->subrequest);

		/* For marsgen */
		{
			parameter* q = find_parameter(a, p->name);
			if(q) {
				free_all_values(q->default_values);
				q->default_values = clone_all_values(p->default_values);
			}
		}

		p = p->next;
	}
}

void MvRequest :: update_value(request *r,const char *parname,const char *valname,boolean append)
{
	parameter *p;
	value     *v;

	if(!r) return;


	if( (p = find_parameter(r,parname)) == NULL )
		return;

	if(append)
	{
		value *a = p->values,*b= NULL;
		while(a)
		{
			b = a;
//			c = b;
			a = a->next;
		}
		v = new_value(strcache(valname));
		if(b) b->next = v;
		else p->values = v;

		p->count = 0;
	}
	else
	{
		if(p->values)
		{
			free_all_values(p->values->next);
			p->values->next = NULL;
			p->count = 0;
			if(EQ(p->values->name,valname))
				return;
			else
			{
				strfree(p->values->name);
				p->values->name = strcache(valname);
			}
		}
		else
		{
			v = new_value(strcache(valname));
			p->values = v;
			p->count = 0;
		}
	}
}

MvRequest MvRequest::ExpandRequest ( const char* defName, const char* rulesName, long expandFlag )
{
	// Create the full path
	string sdef   = MakeSystemEtcPath(defName);
	string srules = MakeSystemEtcPath(rulesName);

	MvLanguage langMetview ( sdef.c_str(),srules.c_str(),expandFlag );

	return langMetview.expandOne ( CurrentRequest );
}


bool MvRequest::getPath(const char* par,string &resPath,bool canBeEmpty,string &errTxt)
{		
	errTxt.clear();
	
	const char *inPath=(*this)(par);
	
  	if(inPath && strlen(inPath) > 0)
	{
	  	resPath=string(inPath);
	  		
	  	if(resPath.at(0) == ' ')
		{
			errTxt="Leading whitespace in parameter: " + string(par) + "!";
			return false;
		}
		
		else if(resPath.at(0) != '/')
		{
			const char* callerIcon=(*this)("_NAME");
			if(callerIcon)
			{
	  			string callerDir(callerIcon);	  	

				// special case: if callerDir is a path with "Process@" in it, then it
				// very probably means that this was run from a macro - in this case, we can't
				// use the returned path (because it's invalid) and instead a relative path should be
				// considred relative to where the macro is run from; so in this case we would simply
				// remove the path.

				if(callerDir.find("Process@") != string::npos)
				{
					// yes, it's called from Macro - files are relative to current dir
					callerDir = ".";
				}
				else
				{
					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);
					}
				}
					
				resPath=callerDir + "/" + resPath;
			}	
		}					
	}
	
	if(!inPath || (resPath.empty() && canBeEmpty == false))
	{
		errTxt="No value is defined for parameter: " + string(par) + "!";
		return false;
	}
	
	return true;
}
	

bool MvRequest::getPath(const char* iconPar,const char* textPar,string &resPath,bool canBeEmpty,string &errTxt)
{			
  	errTxt.clear();
	
	MvRequest dataR=(*this)(iconPar);
	const char *dataPath=dataR("PATH");
	
	//First try to get the path from the icon object
	if(dataPath)
	{
	  	resPath=string(dataPath);
	}
	//If there is no icon we use the text parameter to get the path
	else
	{
	  	if(!getPath(textPar,resPath,true,errTxt))
		{ 
			return false;
		}
	}
	
	if(!canBeEmpty && resPath.empty())
	{
	  	errTxt="No value found for paramaters: " + string(iconPar) + " " +  string(textPar); 
		return false;
	}	
	
	return true;
}	



// MvRequest::getBaseDate()
// returns zero if neither HDATE nor DATE are present in the request
int MvRequest::getBaseDate()
{
    int date = (*this)("HDATE");  // try HDATE first (will return 0 if not there)

    if (date == 0)
        date = (*this)("DATE");   // no HDATE? try DATE (will return 0 if not there)

    return date;
}



bool MvRequest::getValueId(const char* par,string& value,const std::map<string,string>& idMap,bool canBeEmpty,string &errTxt)
{	
        value.clear();
	errTxt.clear();
	
	const char *cval=(*this)(par);
	
	if(cval)
  	{
		value=string(cval);		
		
		if(idMap.empty() == false)
		{
		  	std::map<string,string>::const_iterator it=idMap.find(value); 
		  	if(it != idMap.end())
				value=it->second;
			else
			  	value.clear();
		}			
	}	
	else if(!canBeEmpty)
	{
	  	errTxt="Parameter not found: " + string(par);
		return false;	
	}
	
	if(!canBeEmpty && value.empty())
	{
		errTxt="No value found for paramater: " + string(par);
		return false;
	}
	
	return true;	
}


bool MvRequest::getValue(const char* par,string& value,bool canBeEmpty,string &errTxt)
{
	value.clear();
	errTxt.clear();
	
	const char *cval=(*this)(par);
	
	if(cval)
  	{
		value=string(cval);		
	}
	else if(!canBeEmpty)
	{  	
	  	errTxt="Parameter not found: " + string(par);
		return false;
	}
	
	if(!canBeEmpty && value.empty())
	{
		errTxt="No value found for parameter: " + string(par);
		return false;
	}
	
	return true;	
}

bool MvRequest::getValue(const char* par,std::vector<string>& value,bool canBeEmpty,string &errTxt)
{
	value.clear();
	errTxt.clear();
	
	int cnt = countValues(par);
	
	if(cnt==0)
	{
	  	if(!canBeEmpty)
		  	return false;
	}
	else if(cnt == 1)
	{
	  	const char *cval=(*this)(par);
		if(cval)
  		{		
			value.push_back(string(cval)); 
		}
	}
	else
	{  
		string val;
		for( int i=0; i<cnt; i++)
	     	{
	      		const char *cval = (*this)(par,i );
			if(cval)
			{					
				value.push_back(string(cval));
			}						
		}
	}
	
	return true;
}

//===================================================================
// MvAccess

void MvAccess::operator+= (double val)
{
	if (LastGet) add_value(Request->CurrentRequest, LastGet, "%.12g", val);
	LastGet = NULL;
	LastIndex = 0;
}

MvAccess::operator Cached() const
{
	const char *p = *this;
	return Cached(p);
}

MvAccess::operator MvRequest() const
{
	return MvRequest(get_subrequest(Request->CurrentRequest, LastGet, LastIndex),false);
}
MvConstAccess::operator Cached() const
{
	const char *p = *this;
	return Cached(p);
}

MvConstAccess::operator MvRequest() const
{
	return MvRequest(get_subrequest(Request->CurrentRequest, LastGet, LastIndex),false);
}


MvValue::MvValue(double d)
{
	CurrentRequest = FirstRequest = empty_request("NUMBER");
	set_value(CurrentRequest,"VALUE","%.12g",d);
}

MvValue::MvValue(const char *s)
{
	CurrentRequest = FirstRequest = empty_request("STRING");
	set_value(CurrentRequest,"VALUE","%s",s);
}

MvGrib::MvGrib(const char *s)
{
	CurrentRequest = FirstRequest = empty_request("GRIB");
	set_value(CurrentRequest,"PATH","%s",s);
}

//----------------------------------------------


void MvRequest::importSubObjects(string& path, request* obj)
{
   // Get the definition filename
   const char* defFile = get_value(obj,"definition_file",0);
   if ( !defFile )
      return;

   // Read the definition file
   request* rdef = read_language_file(defFile);
   if ( !rdef )
      return;

   // This request may be structured as a set of requests.
   // Loop each request and expand all parameters that are subrequests.
   this->rewind();
   while (CurrentRequest)
   {
      // Find the correspondent definition request
      request* rl = rdef;
      while(rl && (rl->name != this->getVerb()))
         rl = rl->next;

      // Skip this request if there is no related definition request
      if ( !rl )
         continue;

      // Check each parameter to find out if it needs to be expanded
      parameter* p = rl->params;
      MvRequest reqAux;
      while (p)
      {
         // Search for parameters that have an icon interface
         const char *cicon = get_value(p->interface,"interface",0);
         if (cicon && (strcmp(cicon,"icon") == 0))
         {
            // Build all subrequests and add to this parameter
            const char* cclass = get_value(p->interface,"class",0);
            const char *q;
            for ( int i = 0; i < this->countValues(p->name); i++ )
            {            
               // Build subrequest
               this->getValue(q,p->name,i);
               string fullPath = (path[path.size()-1] == '/') ? path + q : path + "/" + q;
               if ( !IsBinaryOrMissingFile(fullPath.c_str()) )
               {
                  // Read request from file and add parameter _CLASS.
                  // Do not add parameter _NAME because this request
                  // will be built by loading the contents of a file.
                  // Adding parameter _NAME will make further routines to
                  // read the file again.
                  reqAux.read(fullPath.c_str(),true);
                  reqAux("_CLASS") = reqAux.getVerb();
               }
               else
               {
                  // Build request manually
                  reqAux.setVerb(cclass);

                  // Add hidden parameters
                  reqAux("_CLASS") = cclass;

                  // Name without the Metview user directory path
                  string user_dir = GetUserDirectory();
                  std::size_t found = fullPath.find(user_dir);
                  if (found != std::string::npos)
                     reqAux("_NAME") = fullPath.substr(found+user_dir.size()).c_str();
                  else
                     reqAux("_NAME") = fullPath.c_str();
               }

               // Add subrequest to this parameter
               if ( i == 0 )  // clean parameter values once
                  this->unsetParam(p->name);

               this->addValue(p->name,reqAux);
            }
         }

         p = p->next;
      }

      CurrentRequest = CurrentRequest->next;
   }

   this->rewind();
}

request* MvRequest::findRequestObject()
{
   const char* className = this->getVerb();
   if (!className)
      return NULL;

   const char *c;
   request *u = mars.setup;
   while (u)
   {
      if (strcmp(u->name,"object") == 0 && 
          (c = get_value(u,"class",0))  &&
           c == className )
         return u;

      u = u->next;
   }

   return NULL;
}

bool MvRequest::checkParameters( MvRequest& req, vector<string>& params )
{
   const char *par, *v1, *v2;
   int i,j,cnt1,cnt2;

   for (i = 0; i < (signed)params.size(); i++ )
   {
      par = params[i].c_str();
      cnt1 = this->iterInit(par);
      cnt2 = req.iterInit(par);
      if ( cnt1 && (cnt1 == cnt2) )
      {
         for (j = 0; j < cnt1; j++)
         {
            this->iterGetNextValue( v1 );
            req.iterGetNextValue( v2 );
            if ( v1 != v2 )
               return false;
         }
      }
      
   }

   return true;
}
