/***************************** 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 <Metview.h>
#include <MvTimeSerie.h>
#include <Cached.h>


class Metgram : public MvService
{
protected:
    Metgram(char* a) :
        MvService(a){};
    void grib(MvRequest&, MvRequest&);
    void bufr(MvRequest&, MvRequest&);
    void do_one(MvRequest&, MvRequest&, MvTimeSerie&);

public:
    Metgram() :
        MvService("METGRAM"){};
    void serve(MvRequest&, MvRequest&);
};

static Cached GRIB("GRIB");
static Cached BUFR("BUFR");

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

    MvRequest data;

    in.getValue(data, "DATA");

    Cached type(data.getVerb());

    if (type == GRIB)
        grib(in, out);
    else if (type == BUFR)
        bufr(in, out);
    else {
        setError(1, "Metgram-> Unable to work on data of type %s", (const char*)type);
        return;
    }

    std::cout << "Metgram::serve() out" << std::endl;
    out.print();
}


void Metgram::grib(MvRequest& in, MvRequest& out)
{
    MvRequest grib = in("DATA");
    MvRequest station = in("STATION");
    MvRequest axis = in("VERTICAL_AXIS");
    MvRequest graph = in("ATTRIBUTES");

    MvTimeSerie serie(axis, graph);

    //	while (grib) {
    do_one(grib, station, serie);
    //		grib.advance();
    //	}

    out = serie.getRequest();
}

void Metgram::do_one(MvRequest& grib, MvRequest& station,
                     MvTimeSerie& serie)
{
    char ref[1024];
    char legend[1024];
    int param = -1;
    int level = -1;
    int number = -1;
    int idat = -1, dateinc = 0, fdato = 0;
    double lat, lon;
    const char *name, *icon_name;
    MvRequest last_station;


    MvFieldSet fs(grib);
    MvFieldSetIterator iter(fs);

    //	iter.sort("DATE");
    //	iter.sort("TIME");
    iter.sort("STEP");
    iter.sort("LEVELIST");
    iter.sort("NUMBER");
    iter.sort("PARAM");


    MvField field;
    while (field = iter()) {
        MvFieldExpander expand(field);
        double min = field[0];
        double max = field[0];
        MvRequest r = field.getRequest();

        int p = r("PARAM");

        int l = r("LEVELIST");
        int n = r("NUMBER");
        int idato = r("DATE");
        int itime = r("TIME");
        const char* type = r("TYPE");

        double x = r("STEP");
        printf(" %lf date %d\n", x, idato);
        if (idat == -1) {
            idat = idato;
            fdato = idato;
        }
        if (idat != idato) {
            idat = idato;
            dateinc += 10000;
        }
        itime += dateinc;
        serie.setDate(fdato, itime);

        if (p != param || l != level || n != number) {
            param = p;
            level = l;
            number = n;
            while (station) {
                icon_name = station("_CLASS");
                name = station("NAME");
                if (icon_name)
                    last_station = station;

                sprintf(ref, "%d/%s/%d/%d", param, name, level, number);
                lat = station("LATITUDE");
                lon = station("LONGITUDE");
                float abslat = lat > 0. ? lat : -lat;
                float abslon = lon > 0. ? lon : -lon;

                sprintf(legend, "%d/%s Level=%d, %4.1f%c %5.1f%c",
                        param, name, level,
                        abslat, abslat >= 0.059 ? (lat > 0. ? 'n' : 's') : ' ',
                        abslon, abslon >= 0.059 ? (lon > 0. ? 'e' : 'w') : ' ');
                serie.createNewGroup(ref, legend);
                serie.addIconInfo(ref, "DATA", grib);
                serie.addIconInfo(ref, "STATION", last_station);

                if (level)
                    serie.setTitle(ref, "Plot of %d level %d at %s",
                                   p, l, name);
                else
                    serie.setTitle(ref, "Plot of %d at %s", p, name);

                station.advance();
            }
            station.rewind();
        }

        while (station) {
            double BIGDOUBLE = 3.4E35;
            name = station("NAME");
            lat = station("LATITUDE");
            lon = station("LONGITUDE");
            sprintf(ref, "%d/%s/%d/%d", p, name, level, number);
            double y = field.interpolateAt(lon, lat);
            if (y < BIGDOUBLE)
                serie.addPoint(ref, x, y);

            station.advance();
        }
        station.rewind();
    }
}

void Metgram::bufr(MvRequest&, MvRequest&)
{
    /*****************
    MvRequest bufr;

    in.getValue(bufr,"DATA");
    MvRequest station;
    in.getValue(station,"STATION");
    double ident = station("IDENT");

    while (station) {
        char *name =  station("NAME");
        printf("station : %s\n", name);
        station.advance();
    }

    in.getValue(station,"STATION");
    MvRequest magics;

    in.getValue(magics,"VISUALISATION");
    printf("Magics parameter\n");
    magics.print();


    boolean bar     = false;
    boolean scale 	= false;
    boolean overlay = false;
    Cached  BAR("BAR");
    Cached  YES("YES");

    if (magics("GRAPH_TYPE") == BAR) bar = true;
    if (in("SCALE") == YES) scale = true;
    if (in("OVERLAY_STATIONS") == YES) overlay = true;

    MvObsSet          obsset(bufr);
    MvObsSetIterator  iter(obsset);

    MvBufrParam tempe("T");
    iter.setWmoStation(ident);

    MvObs obs;
    while(obs = iter())
    {
        obs.printParameters();
        float t = obs.value(tempe);
        printf("Tempe : %f\n", t);
    }
*****************************/
}

int main(int argc, char** argv)
{
    MvApplication theApp(argc, argv);
    Metgram metgram;

    metgram.addModeService("STATION", "STATION");
    metgram.addModeService("GRIB", "DATA");
    metgram.addModeService("PAXIS", "VERTICAL_AXIS");

    theApp.run();
}
