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

// File Decoder
// Gilberto Camara - ECMWF Jul 97
//
// .NAME:
//  Decoder
//
// .AUTHOR:
//  Gilberto Camara and Fernando Ii
//
// .SUMMARY:
//  An abstract data class for decoding different types
//  of meteorological data processed by PlotMod
//  (which uses EMOSlib and Mars' interface to Emoslib)
//
// .CLIENTS:
//  PlotModMatcher, Graphics Engine
//
//
// .RESPONSABILITIES:
//  For each data time, provide information on parameter,
//  date, time and level
//
//
// .COLLABORATORS:
//  Date, Time, Emos, PathName
//
//
// .BASE CLASS:
//  Decoder
//
// .DERIVED CLASSES:
//  GribDecoder, BufrDecoder, MatrixDecoder, GeoPointsDecoder,
//  NetCDFDecoder
//
// .REFERENCES:
//
//  The design of this class is based on the "Factory" pattern
//  ("Design Patterns", page. 107).
//
//  For additional references please see Coplien's chapter 8
//  ("Programming with Exemplars")
//
//
//  The templated factory is based on the idea of "traits"
//  described in the article "A New and Useful Template Technique: "Traits"
//  by Nathan Myers, included in the "C++ Gems" book
//  (see also Stroustrup, 3rd. edition, page 580ff).
//
#pragma once

#include <MvRequest.h>
#include <Factory.hpp>

class Decoder;
class MatchingInfo;

// Class Decoder Factory - clones a new Decoder

struct DecoderFactoryTraits
{
    using Type = Decoder;
    using Parameter = const MvRequest&;
    static Cached FactoryName(Parameter);
    static Type* DefaultObject(Parameter);
};


class DecoderFactory : public Factory<DecoderFactoryTraits>
{
public:
    DecoderFactory(const Cached& name) :
        Factory<DecoderFactoryTraits>(name) {}
};

// typedef std::vector<Cached> VariableNamesList;
// typedef std::vector<float>  DataVector;

class Decoder
{
public:
    // Contructors
    Decoder(const MvRequest&);

    // Destructor
    virtual ~Decoder();

    virtual MatchingInfo CreateMatchingInfo() = 0;

    // Methods with are overriden by derived classes. Default
    // implementations provided for convenience of derived classes,
    // as some of the functions are irrelevant to most derived classes.

    // Goes to the next data (returns false if no more data)
    virtual bool ReadNextData() { return false; }

    virtual bool GetData(std::vector<double>&, const char*) { return false; }
    virtual bool GetRequest(MvRequest&, const char*) { return false; }
    // for netcf decoder;
    virtual Cached GetView() { return {""}; }

    // Overridden by decoders that need to update their request
    virtual bool UpdateDataRequest(MvRequest&) { return false; }

    // Derived decoders are responsible for setting values correctly
    virtual void GetMinMax(double& minX, double& maxX, double& minY, double& maxY)
    {
        minX = minX_;
        maxX = maxX_;
        minY = minY_;
        maxY = maxY_;
    }

    // Returns the offset (data size)
    virtual long CurrentOffset()
    {
        return offset_;
    }

    MvRequest Request() const
    {
        return metadataRequest_;
    }

protected:
    // Utilities for derived classes
    void AddData(MvRequest& out, std::vector<double>& dataVector, const char* outName);
    void AddData(MvRequest& out, std::vector<std::string>& dataVector, const char* outName);

    void CheckMinMax(std::vector<double>& values, double& oldMax, double& oldMin);

    void SetTitle(MvRequest&);

    // Members
    MvRequest metadataRequest_;  // request which contains metadata info
    long offset_{0};
    bool nextData_{false};
    double minX_{0.}, maxX_{0.}, minY_{0.}, maxY_{0.};

private:
    // No copy allowed
    Decoder(const Decoder&);
    Decoder& operator=(const Decoder&) { return *this; }
};
