/***************************** 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 "Velstr.h"
#include "MvFortran.h"


#ifdef FORTRAN_UPPERCASE
#define velstr_ VELSTR
#endif

#ifdef FORTRAN_NO_UNDERSCORE
#define velstr_ velstr
#endif

extern "C" void velstr_(void);

#define VORTICITY	138
#define DIVERGENCE	155

void Velstr :: serve(MvRequest& in,MvRequest& out)
{
	cout << "\n---> Entering Velstr::serve..." << endl;
	in.print();
	 // Get data
	if (!GetData(in)) return;

	// Compute output field
	if (!Apply(out)) return;

	cout << "<--- Done OK! Leaving Velstr::serve.\n" << endl;
}

int Velstr :: GetField (MvRequest& grib, int param, MvFieldSet& fs)
{
	MvFilter		filter("PARAM");	// filter
	MvFieldSet		fset(grib);		// field set
	MvFieldSetIterator 	fsiter(fset);		// field set iterator
	MvField			field;			// auxiliary field
	int			nfields;		// number of fields

	// Get fields

	nfields = 0;
	fsiter.setFilter(filter == param);
	while(field=fsiter())
	{
		nfields++;
		fs += field;
	}

	return nfields;
}

bool Velstr :: GetDataGen(MvRequest& in)
{
	// Get spectral truncation, smoothng indicator and constants

	if(strcmp(in("TRUNCATION"),"AV") == 0)
	  Vtrunc = 0.;
	else
	  Vtrunc = (int)in("TRUNCATION");

	strcpy(Vsmoothing,in("SMOOTHING"));
	strcpy(Vscaling,  in("SCALING"));

	if ((const char*)in("FLTC"))
	  Vfltc = (double)in("FLTC");
	else
	  Vfltc = 19.4;

	if ((const char*)in("MFLTEXP"))
	  Vmfltexp = (double)in("MFLTEXP");
	else
	  Vmfltexp = 2.;

	return true;
}

bool Velstr :: Apply(MvRequest& out)
{
#if 0
	MvFortran	velstrf("Velstr");	// fortran subroutine

	// Call the fortran routines

	velstrf.addParameter(Vfieldset);	// setup fortran params
	velstrf.addParameter(Vtrunc);
	velstrf.addParameter(Vsmoothing);
	velstrf.addParameter( Vscaling );
	velstrf.addParameter(Vfltc);
	velstrf.addParameter(Vmfltexp);

	putenv("VELSTR_ENV=OK");
	velstr_();
	char* penv=getenv("VELSTR_ENV");
	if(strcmp(penv,"OK"))
	{
		setError(1,penv);
		return false;
	}

	// Get the result

	out = velstrf.getResult();
#endif
  for( int f=0; f < Vnfield; ++f )
  {
     MvField myField = Vfieldset[ f ];
     grib_handle* gh = myField.getGribHandle();

     if( ! isValidData_DVVALID( gh ) )
     {
        marslog(LOG_EROR,"Velstr: invalid data");
        return false;
     }

     checkOutputTruncation( gh );

//-- <aki> change param value (maybe later...)

     convert_DVTOVS( gh, Vtrunc );

     if( Vsmoothing[0] == 'Y' )
        smooth_BPPSMTH( gh );

     if( Vscaling[0] == 'Y' )
        scaleData( gh );
  }

  out = Vfieldset.getRequest();
  out.print();

  return true;
}

bool Velpot :: GetData(MvRequest& in)
{
	MvRequest 	grib;			// grib file

	 // Get data from request

	in.getValue(grib,"DATA");

	// Get divergence field

	Vnfield = GetField(grib,DIVERGENCE,Vfieldset);
	if(Vnfield == 0)
	{
		setError(1,"Field is not Divergence..");
		return false;
	}

	// get general data
	if (!GetDataGen(in)) return false;

	return true;
}

bool Streamfn :: GetData(MvRequest& in)
{
	MvRequest 	grib;			// grib file

	 // Get data from request

	in.getValue(grib,"DATA");

	// Get divergence field

	Vnfield = GetField(grib,VORTICITY,Vfieldset);
	if(Vnfield == 0)
	{
		setError(1,"Field is not Vorticity..");
		return false;
	}

	// get general data
	if (!GetDataGen(in)) return false;

	return true;
}

bool
Velstr::badRetVal( int ret, const char* gribApiFunc, const char* MvFunc )
{
  if( ret != 0 )
  {
     sendProgress( ">>> %s returned %d in %s", gribApiFunc, ret, MvFunc );
     cerr << ">>> '" << gribApiFunc << "' returned " << ret
          << " in '" << MvFunc << "'" << endl;

     return true;
  }
  else
     return false;
}


int main(int argc,char **argv)
{
	MvApplication theApp(argc,argv);
	Velpot velpot("VELPOT");
	Streamfn strfn("STREAMFN");

	theApp.run();
}
