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

//
// .NAME:
//  BufrDecoder
//
// .AUTHOR:
//  Geir Austad
//
// .SUMMARY:
//  A concrete  class for decoding BUFR files
//  (uses Vesa's C++ classes to wrap the emoslib
//  routines).
//
// .CLIENTS:
//
//
// .RESPONSIBILITIES:
//  For each file, loop thru the messages and
//  return the messages matching the given criteria.
//
// .COLLABORATORS:
//  ECMWF's BUFR classes.
//
// .BASE CLASS:
//  Decoder
//
// .DERIVED CLASSES:
//
//
// .REFERENCES:
//
//  The design of this class is based on the "Factory" pattern
//  ("Design Patterns", page. 107).
//
//
#pragma once

#include <mars.h>
#include "libMetview/MvObs.h"
#include "MvDecoder.h"

using namespace metview;

// Until something more clever, set grouping period to 6 hours.
const int GROUPINGPERIOD = 6;

// Helper class used for grouping the observations into separate
// files. The files are then matched to subpages.
class GroupInfo
{
public:
    GroupInfo() :
        out_(nullptr),
        path_("") {}

    GroupInfo(const std::string& path, bool writeData) :
        out_(nullptr),
        path_(path)
    {
        if (writeData)
            out_ = new MvObsSet(path_.c_str(), "w");
    }

    ~GroupInfo() { this->close(); }

    void write(MvObs& obs)
    {
        if (out_)
            out_->write(obs);
    }

    void close()
    {
        if (out_) {
            out_->close();
            delete out_;
            out_ = nullptr;
        }
    }

    void deleteFile()
    {
        this->close();
        unlink(path_.c_str());
    }
    const std::string& path() { return path_; }

private:
    MvObsSet* out_;
    std::string path_;
};

using GroupInfoMap = std::map<std::string, GroupInfo*, std::less<std::string>>;
using GroupInfoIterator = GroupInfoMap::iterator;

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

    // Destructor
    ~BufrDecoder() override;

    // Overridden methods from Decoder class
    bool ReadNextData() override;

    MatchingInfo CreateMatchingInfo() override;

private:
    void groupInfo(MvObsSetIterator&);
    void findTime(TDynamicTime&, std::string&);
    void generateGroupFileName(std::string&, const std::string&);
    void cleanMap();

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

    // Members
    GroupInfoMap groupInfo_;
    GroupInfoIterator groupIterator_;
    std::string path_;
};

//____________________________________________________

class ObsGroupControl
{
public:
    ObsGroupControl() = default;

    static std::string groupTimeString(const TDynamicTime& tim);
    static void printGroupingLimits(const std::string& groupTimeString);
    static int groupPeriod();
    static int groupPeriodStartMinute();
    static bool useObsTime()
    {
        return useObsTime_;
    }

    static void groupingValues();
    static void setGroupingPeriod(int hours);
    static void setGroupingPeriodStart(int minutes);
    static void setUseObsTime(bool useObsTime)
    {
        useObsTime_ = useObsTime;
    }

private:
    static int groupPeriodHours_;
    static int groupPeriodStartMinute_;
    static bool useObsTime_;
    static bool firstTime_;
};
