/***************************** 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 <MvRequestUtil.hpp>
#include <fdyntime.h>

#include "MvGribDecoder.h"
#include "MatchingInfo.h"
#include "ObjectList.h"

// =====================================================
// class GribDecoderFactory - builds  decoders
//

class GribDecoderFactory : public DecoderFactory
{
    // Virtual Constructor - Builds a new GribDecoder
    Decoder* Build(const MvRequest& inRequest) override
    {
        return new GribDecoder(inRequest);
    }

public:
    GribDecoderFactory() :
        DecoderFactory("GribDecoder") {}
};

static GribDecoderFactory gribDecoderFactoryInstance;

//=======================================================
//
// Methods for the GribDecoder class
//
GribDecoder::GribDecoder(const MvRequest& dataUnitRequest) :
    Decoder(dataUnitRequest),
    fieldSet_(dataUnitRequest),
    fieldSetIterator_(fieldSet_)
{
    // Empty
}

GribDecoder::~GribDecoder() = default;

// Read Next Data
//
// -- Goes to the next data and returns the offset (data size)
// -- Grib decoder only reads one field
bool GribDecoder::ReadNextData()
{
    currentField_ = fieldSetIterator_();  // Read next data
    if (!currentField_)
        return false;

    // Expand the field
    // MvFieldExpander expand(currentField);
    metadataRequest_ = currentField_.getRequest();

    // Get Offset
    offset_ = currentField_.getOffset();

    return true;
}

// Create MatchingInfo
// Retrieve the matching request
MatchingInfo
GribDecoder::CreateMatchingInfo()
{
    const char* ident = metadataRequest_("IDENT");
    MvRequest matchingRequest("MATCHING_INFO");

    matchingRequest("PARAM") = metadataRequest_("PARAM");
    metview::SetIfValue(matchingRequest, "LEVEL", metadataRequest_("LEVELIST"));

    // XXX this might not be necessary since we're not interested in
    // IDENT for identifying satellite images anymore.
    if (ident != nullptr)
        matchingRequest("IDENT") = ident;

    // For hindcast, data, we use HDATE, not DATE, so check this first
    long date = (long)metadataRequest_("HDATE");
    if (date == 0)
        date = (long)metadataRequest_("DATE");

    TDynamicTime matchTime(date, (long)metadataRequest_("TIME"));

    // Take the step into account when generating the matching time
    matchTime.ChangeByHours(MvField::stepRangeDecoder(metadataRequest_("STEP")));
    char buf[50];
    sprintf(buf, "%d%02d%02d", matchTime.GetYear(), matchTime.GetMonth(), matchTime.GetDay());
    matchingRequest("DATE") = buf;
    sprintf(buf, "%02d%02d", matchTime.GetHour(), matchTime.GetMin());
    matchingRequest("TIME") = buf;

    // we will later need to decide whether to apply automatic scaling or not
    // ir matchingRequest("DERIVED") = metadataRequest_("DERIVED");

    // Is it an image field?
    const char* repres = metadataRequest_("REPRES");
    if (ObjectList::IsImage(repres))
        matchingRequest("DATA_TYPE") = "IMAGE";
    else {
        // Get parameter name
        const size_t cMaxBuf = 99;
        char acc0[cMaxBuf + 1];
        size_t nsize = cMaxBuf;

        field* ff = currentField_.libmars_field();
        grib_get_string(ff->handle, "shortName", acc0, &nsize);
        matchingRequest("PARAM") = acc0;
        matchingRequest("DATA_TYPE") = "GRIB";

        // Has this parameter a companion?
        std::string pair, mode;
        bool first_companion = false;
        ObjectList::GetCompanion(std::string(acc0), pair, mode, first_companion);
        if (pair != "no_pair") {
            matchingRequest("MY_COMPANION") = pair.c_str();
            matchingRequest("FIRST_COMPANION") = first_companion;
            if (!mode.empty())
                matchingRequest("WIND_MODE") = mode.c_str();
        }
    }

    return MatchingInfo(matchingRequest);
}
