/***************************** 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 "Divrot.h"


void Divrot :: serve(MvRequest& in,MvRequest& out)
{
	cout << "\n---> Entering Divrot::serve..." << endl;
	in.print();

	 // Get data
	if (!GetData(in)) return;

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

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

int Divrot :: 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 Divrot :: GetDataGen(MvRequest& in)
{
	// Get spectral truncation, smoothing indicator and constants

	if(strcmp(in("TRUNCATION"),"AV") == 0)
	   DtruncOut = 0.;
	else
	   DtruncOut = (double)in("TRUNCATION");

	strcpy(Dsmoothing,in("SMOOTHING"));

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

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

	return true;
}

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

	// Call the fortran routines
	divrotf.addParameter(Dfieldset);	// setup fortran params
	divrotf.addParameter(Dtrunc);
	divrotf.addParameter(Dsmoothing);
	divrotf.addParameter(Dfltc);
	divrotf.addParameter(Dmfltexp);

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

	// Get the result

	out = divrotf.getResult();
#endif

  convert_DIVROT( out );
  out.print();

  return true;
}

bool
Divrot::appendWindComponent( grib_handle* gh )
{
    int ret = 0;
//    char *packingType = "spectral_simple";
//    size_t packtype   = strlen(packingType);

                                            //-- ensure output truncation is right
//    ret += grib_set_long  ( gh, "pentagonalResolutionParameterJ", DtruncOut );
//    ret += grib_set_long  ( gh, "pentagonalResolutionParameterK", DtruncOut );
//    ret += grib_set_long  ( gh, "pentagonalResolutionParameterM", DtruncOut );
//    ret += grib_set_string( gh, "packingType", packingType,  &packtype);
    ret += grib_set_long  ( gh, "generatingProcessIdentifier",    254 );
    badRetVal( ret, "grib_set_long/generatingProcessIdentifier", "Divrot::appendWindComponent" );
//    badRetVal( ret, "grib_set_long/truncVals", "Divrot::appendWindComponent" );

/*
    size_t len = 0;                         // data values count
    ret = grib_get_size( gh, "values", &len );
    badRetVal (ret, "grib_get_size", "appendWindComponent");

    double* values = new double[len];       // allocate array for values
    ret = grib_get_double_array( gh, "values", values, &len );  // get the values
    badRetVal (ret, "grib_get_double_array", "appendWindComponent");

                                             //-- encode wind component
    ret = grib_set_double_array( gh, "values", values, len );
    badRetVal( ret, "grib_set_double_array", "Divrot::appendWindComponent" );
*/


   if( Dsmoothing[0] == 'Y' )                //-- is smoothing requested?
      smooth_BPPSMTH( gh );

   size_t      buflen   = 0;                 //-- get the GRIB msg into 'buffer'
   const void* buffer = NULL;
   ret = grib_get_message( gh, &buffer, &buflen );
   badRetVal( ret, "grib_get_message", "Divrot::appendWindComponent" );

                                             //-- open output file in append mode
   FILE* gribFile = fopen( DfileOut.c_str(), "a" );
   if( ! gribFile )
   {
      marslog(LOG_EROR|LOG_PERR,"Cannot open %s",DfileOut.c_str());
      return false;
   }
                                             //-- append 'buffer' to output file
   if( fwrite(buffer,1,buflen,gribFile) != buflen )
   {
      marslog(LOG_EROR|LOG_PERR,"fwrite(%s) failed",DfileOut.c_str());
      return false;
   }
                                             //-- close and double check
   if( fclose(gribFile) )
   {
      marslog(LOG_EROR|LOG_PERR,"fclose(%s) failed",DfileOut.c_str());
      return false;
   }
   
   return true;
}


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

    DresultParam = eRotational;


	 // Get data from request

	in.getValue(grib,"DATA");

	// Get vorticity fields

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

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

	return true;
}

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

    DresultParam = eDivergent;


	 // Get data from request

	in.getValue(grib,"DATA");

	// Get divergence fields

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

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

	return true;
}

bool UVwind :: GetData(MvRequest& in)
{
    MvRequest grib;            // grib data

    DresultParam = eUV;


     // Get data from request

    in.getValue(grib,"DATA");


    // Get vorticity fields

    Dnfield = GetField(grib, VORTICITY, Dfieldset);
    if(Dnfield == 0)
    {
        setError(1,"No vorticity fields in data.");
        return false;
    }


    // Get divergence fields

    Dnfield2 = GetField(grib, DIVERGENCE, Dfieldset2);
    if(Dnfield2 == 0)
    {
        setError(1,"No divergence fields in data.");
        return false;
    }


    // check that we have the same number of DIV and VOR fields

    if (Dnfield != Dnfield2)
    {
        setError(1,"Should be the same number of vorticity and divergence fields - there are %d and %d.", Dnfield, Dnfield2);
        return false;
    }



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

    return true;
}


bool
Divrot::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);
	Rotwind rotw("ROTWIND");
	Divwind divw("DIVWIND");
	UVwind uvw("UVWIND");

	theApp.run();
}
