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

 Copyright 2016 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 <QDateTime>
#include <QDebug>
#include <QStringList>
#include <QVector>
#include <QXmlFormatter>
#include <QXmlQuery>
#include <QXmlResultItems>

#include "MvQWmsClient.h"
#include "MvQWmsClientEditor.h"
#include "MvQOgcRequest.h"
//#include "MvQOgcServiceManager.h"
#include "Metview.h"
#include "MvQService.h"
#include "MvQServiceApplication.h"

using namespace std;

// Globals
int          ac;
char       **av;

class MvWmsClient : public MvQService
{	
   public:
	MvWmsClient() : MvQService("WMSCLIENT") {};
	void serve(MvRequest&,MvRequest&);
	void processUiMode(MvRequest&,MvRequest&);
	void processGetMode(MvRequest&,MvRequest&,const string&);
};

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

	// Get user action mode
	const char* modeC = (const char*)in("_ACTION");
	string mode;
	if(modeC)
	  	mode=string(modeC);
	
	
	if(mode.empty())
	{
		const char* appl = (const char*)in("_APPL");
		if(appl && strcmp(appl,"macro") == 0)
		{
			processGetMode(in,out,mode);
		}
	}
	else if(mode == "edit")
	{
		processUiMode(in,out);
	}
	else if(mode == "visualise" || 
		mode == "prepare"  ||
		mode  == "execute"  ||
		mode == "update")
	{		
		processGetMode(in,out,mode);

	}

	cout << "---MvWmsClient::serve() OUT---" << endl;
	out.print();
}


void MvWmsClient::processUiMode( MvRequest& in, MvRequest& /*out*/)
{
	// Get icon filename
	//string filename(getenv("METVIEW_USER_DIRECTORY"));
	//filename += (const char*)in("_NAME");
	string filename((const char*)in("_NAME"));

	//Create the qt application
	MvQServiceApplication app(ac, av);

	//Initialise resorces from a static library (libMvQtGui)
	Q_INIT_RESOURCE(examiner);
	Q_INIT_RESOURCE(find);
	Q_INIT_RESOURCE(window);

	/*QString clientMode("EXPERT");
	if(static_cast<const char*>(in("MODE")) != 0)
	{
		clientMode=QString(in("MODE"));
	}*/

	// Initialize client
	MvQWmsUiClient *wmsClient = new MvQWmsUiClient(filename,in);
	
	//Define the ogc service manager configuration file name
	char *mvhome=getenv("METVIEW_USER_DIRECTORY");
 	if (mvhome == 0)  
	{	
			//marslog(LOG_EXIT|LOG_EROR,"%s\n",sbuff.str().c_str());
			//setError(13,"Environment variable METVIEW_USER_DIRECTORY is not defined!");	
		return;	
	}

	//QString fconf(mvhome);
	//fconf+="/Metview/Defaults/OgcClient_conf.xml";
 	
	//Create the manager
	//MvQOgcServiceManager *manager=new MvQOgcServiceManager(fconf);

	//Read the icon file and initialize the dialog
	MvQWmsClientEditor *editor=new MvQWmsClientEditor(wmsClient);
	editor->show();

	//Listen to the mars event loop!
	setupSocketNotifier();

	//Enter the app loop
 	app.exec();
}

void MvWmsClient::processGetMode( MvRequest& in, MvRequest& out,const string& mode)
{
	QApplication app(ac, av);
	
	MvQWmsGetClient *client = new MvQWmsGetClient(in);

	if(mode == "update" && client->requestChanged() == false)
	{
		return;
	}	
	
	client->runGetMap();

	//Listen to the mars event loop!
	setupSocketNotifier();

	//Enter the app loop
 	app.exec();
	
	qDebug() << "App loop exited";

	//If the getMap request failed returns
	if(client->getMapRunStatus() == false)
	{
		setError(13); //,"GetMap request failed!");
		return;
	}
	
	//Else build the output request

	MvRequest req("PRASTER");
	req("IMPORT_FILE_TYPE") = "png",
	req("IMPORT_X_POSITION") = -180;
	req("IMPORT_Y_POSITION") = -90;
	req("IMPORT_WIDTH") = 360;
	req("IMPORT_HEIGHT") = 180;
	
	MvQGetMapRequest *gmr = client->getMapRequest();

	req("CRS") = gmr->crs().toStdString().c_str();

	//In version 1.3.0 for epsg:4326 x lat and y is lon !!!!!
	//We need to swap here the coordinates because
	//magics++ interprets x as lon and y as lat!!
	if(gmr->request().contains("CRS=",Qt::CaseInsensitive) &&
	   gmr->crs() == "EPSG:4326")
	{	
		req("CRS_MINX") = gmr->minY().toStdString().c_str();
		req("CRS_MINY") = gmr->minX().toStdString().c_str();
		req("CRS_MAXX") = gmr->maxY().toStdString().c_str();
		req("CRS_MAXY") = gmr->maxX().toStdString().c_str();  
	}
	else
	{
		req("CRS_MINX") = gmr->minX().toStdString().c_str();
		req("CRS_MINY") = gmr->minY().toStdString().c_str();
		req("CRS_MAXX") = gmr->maxX().toStdString().c_str();
		req("CRS_MAXY") = gmr->maxY().toStdString().c_str();
	}  
	
	
	req("LAYERS") = gmr->layers().toStdString().c_str();
	
	req("SERVICE")="WMS";

	const char *layerTitle=static_cast<const char*>(in("LAYER_TITLE"));
	if(layerTitle) req("TITLE") = layerTitle;

	const char *description=static_cast<const char*>(in("LAYER_DESCRIPTION"));
	if(description) req("DESCRIPTION") = description;

	const char *title=static_cast<const char*>(in("SERVICE_TITLE"));
	if(title) req("SERVICE_TITLE") = title;

	//const char *legend=static_cast<const char*>(in("LAYER_LEGEND"));
	//if(legend) req("LEGEND") = legend;

	if(client->legendImagePath().isEmpty() == false)
	{
		req("LEGEND") = client->legendImagePath().toStdString().c_str();
	}

	if(client->logoImagePath().isEmpty() == false)
	{
		req("LOGO") = client->logoImagePath().toStdString().c_str();
	}


	const char *url=static_cast<const char*>(in("SERVER"));
	if(url) req("URL") = url;

	/*QMap<QString,QString> nonTimeDim;
	gmr->nonTimeDimValues(nonTimeDim);
	QStringList nonTimeDimName, nonTimeDimValue;
	QMapIterator<QString,QString> it(nonTimeDim);
	while(it.hasNext())
	{
		it.next();
		nonTimeDimName << it.key();
		nonTimeDimValue << it.value();
	}*/	

	/*QMap<QString,QString> nonTimeDimUnit;
	gmr->nonTimeDimUnits(nonTimeDimUnit);
	QStringList nonTimeDimUnit;
	QMapIterator<QString,QString> itu(nonTimeDimUnit);
	while(it.hasNext())
	{
		it.next();
		nonTimeDimUnit << it.value();
	}*/	

	//req("NON_TIME_DIM_NAME")=nonTimeDimName.join("/").toStdString().c_str();	
	//req("NON_TIME_DIM_VALUE")=nonTimeDimValue.join("/").toStdString().c_str();
	//req("NON_TIME_DIM_UNIT")=nonTimeDimUnit.join(":").toStdString().c_str();	


	//Build rasterloop if there is at least one frame in the request
	if(gmr->requestFrameNum() > 0)
	{
		MvRequest reqLoop;

		QVector<MvRequest> rFrame(gmr->requestFrameNum());	
		for(int i=0; i < rFrame.count(); i++)
		{
			MvRequest reqFrame=req;
			QString fnam=gmr->outFile(i);
			reqFrame("IMPORT_FILE_PATH") = fnam.toStdString().c_str();
			reqFrame("PATH") = fnam.toStdString().c_str();

			QMap<QString,QString> dim;
			gmr->dimValuesForFrame(dim,i);
			QStringList dimName, dimValue;
			QMapIterator<QString,QString> it(dim);
			while(it.hasNext())
			{
				it.next();
				dimName << it.key();
				if(gmr->isTimeDim(it.key()))
				{
					dimValue << MvQOgcRequest::timeToString(it.value());
				}
				else
				{
					dimValue << it.value();
				}
			}	

			reqFrame("DIM_NAME")=dimName.join("/").toStdString().c_str();	
			reqFrame("DIM_VALUE")=dimValue.join("/").toStdString().c_str();;	

			reqLoop = reqLoop + reqFrame;
		}	

		out.setVerb("PRASTERLOOP");
		out("RASTERS") = reqLoop;
	}
	else
	{
		MvRequest reqFrame=req;
		QString fnam=gmr->outFile(0);
		reqFrame("IMPORT_FILE_PATH") = fnam.toStdString().c_str();
		reqFrame("PATH")       = fnam.toStdString().c_str();

		out.setVerb("PRASTERLOOP");
		out("RASTERS") = reqFrame;	
	}

	out("IMPORT_X_POSITION") = -180;
	out("IMPORT_Y_POSITION") = -90;
	out("IMPORT_WIDTH") = 360;
	out("IMPORT_HEIGHT") = 180;


	//
	MvRequest current=in.justOneRequest();	
	while(current != NULL)
	{
		string verb = current.getVerb();
		qDebug() << "verb" << verb.c_str();
		if(verb == "WMSCLIENT")
		{
			current("REQUEST") =  gmr->request().toStdString().c_str();
			out("WMS_CLIENT_REQUEST")=current;
			qDebug() << "add to out";
		}
		break;
		current=in.advance().justOneRequest();
	}

	out.print();
}
	

int main( int argc, char **argv)
{
	ac = argc;
  	av = argv;

	// Initialize a Metview application
	MvApplication app(argc,argv,"wmsclient");

	// Instantiate the application
	MvWmsClient ogc;
	ogc.saveToPool(false);
	app.run();
}
