/***************************** 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 <iostream>

#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)
{
    std::cout << "\n---> Entering Velstr::serve..." << std::endl;
    in.print();

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

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

    std::cout << "<--- Done OK! Leaving Velstr::serve.\n"
              << std::endl;
    out.print();
}

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)) {
            setError(1, "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();

    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, "Velstr-> 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, "Velstr-> 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);
        std::cerr << ">>> '" << gribApiFunc << "' returned " << ret
                  << " in '" << MvFunc << "'" << std::endl;

        return true;
    }
    else
        return false;
}


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

    theApp.run();
}
