/***************************** LICENSE START ***********************************

 Copyright 2013 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 <iostream>
#include <stdexcept>
#include <fstream>


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

class ScmVisualiser: public Base {	
public:
	ScmVisualiser() : Base("SCM_VISUALISER") {};
	void serve(MvRequest&,MvRequest&);

private:
	bool getDataPath(MvRequest &in, const char *dataParamName, const char *dataPathParamName, string &result);
	string getList(MvRequest &in, const char *parameter, string &separator, int &numElements);
	string getString(MvRequest &in, const char *parameter, const char *defaultVal);

};


// ScmVisualiser::getDataPath
// for user parameters which have a data icon and  the alternative of
// a path icon. Returns the path of the data icon if it's there;
// otherwise thh path parameters if it's there. The path is returned
// in the 'result' string.
// Returns true if it found a path, otherwise false.

bool ScmVisualiser::getDataPath(MvRequest &in, const char *dataParamName, const char *dataPathParamName, string &result)
{
	MvRequest dataR=in(dataParamName);
	const char *dataPath=dataR("PATH");

	if(dataPath)
	{
		result=string(dataPath);
	}
	else
	{
		const char *cval=in(dataPathParamName);
		if(cval)
		{
		  	result=string(cval);
			if (result == "OFF")
				result.clear();
		}	
	}	
	
	if(result.empty())
	{
	  	marslog(LOG_EROR,"No value found for paramaters: %s and %s", dataParamName, dataPathParamName);
		setError(13);
		return false;	
	}
	
	return true;
}


// ScmVisualiser::getList
// Parses a list-type variable from a request and returns it
// as a separated string. Also returns the number of elements found.

string ScmVisualiser::getList(MvRequest &in, const char *parameter, string &separator, int &numElements)
{
	string result;

	int nrParams = in.countValues(parameter);
	numElements = nrParams;

	if (nrParams == 0)  // is this case even possible?
		result = string("dummy");
	else
		result = string(in(parameter));

	if (nrParams > 1)
	{
		for (int n=1; n<nrParams; ++n)
		{
			result += separator;
			result += string(in(parameter, n));
		}
	}

	return result;
}


// ScmVisualiser::getString
// Tries to get the given pstring arameter from the request, returning
// a user-specified default if it is not there.

string ScmVisualiser::getString(MvRequest &in, const char *parameter, const char *defaultVal)
{
	const char *val = in(parameter);

	if (!val)
		val = defaultVal;


	return string(val);
}


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

		
	string ScmVisMacro;
	char *mvbin=getenv("METVIEW_BIN");
	if (mvbin == 0)  
	{	
		marslog(LOG_EROR,"No METVIEW_BIN env variable is defined. Cannot locate mv_scm_vis.mv macro!");
		setError(13);
		return;
	}
	else
	{
		ScmVisMacro=string(mvbin) +"/mv_scm_vis.mv";
	}

	vector<string> params;
	string str;
	string listSeparator = ",";
	const char *defVal = "dummy";


    // set the MARS expand flags to avoid unwanted expansion of lists
    expand_flags(EXPAND_DATE|EXPAND_TIME|EXPAND_2ND_NAME|EXPAND_LAST_NAME);


	// plot type
	str = getString(in, "SCM_PLOT_TYPE", defVal);
	params.push_back(str);



	// Input data
	string dataPath;
	bool ok = getDataPath(in, "SCM_DATA", "SCM_DATA_FILENAME", dataPath);
	if (!ok)
		return;  // error message already generated	
	params.push_back(dataPath);



    // data title
	str = getString(in, "SCM_DATA_TITLE", defVal);
	params.push_back(str);


	// comparison data
	string compareDataBool = getString(in, "SCM_COMPARE_DATA", defVal);
	params.push_back(compareDataBool);


    string comparisonDataTitle;
	if (compareDataBool == "ON")
	{
		ok = getDataPath(in, "SCM_COMPARISON_DATA", "SCM_COMPARISON_DATA_FILENAME", dataPath);
		if (!ok)
			return;  // error message already generated	

	    comparisonDataTitle = getString(in, "SCM_COMPARISON_DATA_TITLE", defVal);
	}
	else
	{
		dataPath = "dummy";
        comparisonDataTitle = "dummy";
	}

	params.push_back(dataPath);
	params.push_back(comparisonDataTitle);



	// comparison mode
	str = getString(in, "SCM_COMPARISON_MODE", defVal);
	params.push_back(str);


	// var selection type
	str = "LIST"; //getString(in, "SCM_VARIABLE_SELECTION_TYPE", defVal);
	params.push_back(str);



    // data type (input/output from SCM)
    string dataType = getString(in, "SCM_DATA_TYPE", defVal);


	// variable lists
	int num1dVars, num2dVars, numItems;


    if (dataType == "OUTPUT")
    {
	    str = getList(in, "SCM_OUTPUT_1D_VARIABLES", listSeparator, num1dVars);
	    params.push_back(str);

	    str = getList(in, "SCM_OUTPUT_2D_VARIABLES", listSeparator, num2dVars);
	    params.push_back(str);
    }
    else
    {
	    str = getList(in, "SCM_INPUT_1D_VARIABLES", listSeparator, num1dVars);
	    params.push_back(str);

	    str = getList(in, "SCM_INPUT_2D_VARIABLES", listSeparator, num2dVars);
	    params.push_back(str);
    }

	str = getList(in, "SCM_TIMES", listSeparator, numItems);
	params.push_back(str);


	// output mode and path
	string outputMode = getString(in, "SCM_OUTPUT_MODE", defVal);
	params.push_back(outputMode);

	str = getString(in,"SCM_OUTPUT_FILE_PATH", defVal);


  	// output path - add directory if not already supplied
  	string userResPath;
	if(!str.empty())
	{
  		userResPath=string(str);
  		
		if(userResPath.find("/") == string::npos)
		{
			const char* callerIcon=in("_NAME");
			if(callerIcon)
			{
  				string callerDir(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);
				}
				
				userResPath=callerDir + "/" + userResPath;
			}	
		}
	}

	params.push_back(userResPath);



	str = getList(in, "SCM_X_MIN_LIST", listSeparator, numItems);
	params.push_back(str);

	str = getList(in, "SCM_X_MAX_LIST", listSeparator, numItems);
	params.push_back(str);

	str = getList(in, "SCM_Y_MIN_LIST", listSeparator, numItems);
	params.push_back(str);

	str = getList(in, "SCM_Y_MAX_LIST", listSeparator, numItems);
	params.push_back(str);


	str = getList(in, "SCM_VALUE_MIN_LIST", listSeparator, numItems);
	params.push_back(str);

	str = getList(in, "SCM_VALUE_MAX_LIST", listSeparator, numItems);
	params.push_back(str);


	// plot the grid
	string plotGridBool = getString(in, "SCM_GRID", defVal);
	params.push_back(plotGridBool);


	// sanity check for consistency
	if ((num1dVars > 1 || num2dVars > 1) && outputMode == "SCREEN")
	{
		marslog(LOG_EROR,"Cannot (currently) plot multiple variables to SCREEN. Please specify an output file.");
		setError(13);
		return;
	}





	//Build request to be sent to Macro
	MvRequest req("MACRO");

	string processName = MakeProcessName("ScmVisualiser");
	MvRequest macroReq("MACRO");
	req("PATH") = ScmVisMacro.c_str();
	req("_CLASS") = "MACRO";
	req("_ACTION") = "execute";
	req("_REPLY") = processName.c_str();
	
	//Define argument list for the macro!
	for(vector<string>::iterator it=params.begin(); it != params.end(); it++)
	{
		req.addValue("_ARGUMENTS",(*it).c_str());			   			     
	}
		
	//Run macro
	int error;	
	marslog(LOG_INFO,"Execute macro: %s",ScmVisMacro.c_str());
	MvRequest reply = MvApplication::waitService("macro",req,error);

	//Call myself to process the macro reply request
	if(!error && reply)
	{
		const char* myname = reply("_REPLY");
		MvApplication::callService(myname,reply,0);
	}
	else
	{
	  	marslog(LOG_EROR,"Failed to run SCM visualiser! Macro failed!");
		setError(13);
		return;
	}  
	  
	reply.print();
	
	//out=MvRequest("FLEXTRA_INPUT");
	//out("INPUT_DATA_PATH")=outPath.c_str();
	//out("AVAILABLE_FILE_PATH")=fAvailable.c_str();
	
	out.print();
}
	
	  	
int main( int argc, char** argv )
{
	MvApplication theApp( argc, argv,"ScmVisualiser");

    ScmVisualiser flextra;	
	
    theApp.run();
}


