/***************************** 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).
//
//
#ifndef BufrDecoder_H
#define BufrDecoder_H

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

// 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_(0),
        path_("") {}

    GroupInfo(const string& path, bool writeData) :
        out_(0),
        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_ = 0;
        }
    }

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

private:
    MvObsSet* out_;
    string path_;
};

typedef map<string, GroupInfo*, less<string> > GroupInfoMap;
typedef GroupInfoMap::iterator GroupInfoIterator;

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

    // Destructor
    virtual ~BufrDecoder();

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

    virtual MatchingInfo CreateMatchingInfo();

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

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

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

//____________________________________________________

class ObsGroupControl
{
public:
    ObsGroupControl() {}

    static string groupTimeString(const TDynamicTime& tim);
    static void printGroupingLimits(const 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_;
};
#endif
