/**********************************************************************
zyGrib: meteorological GRIB file viewer
Copyright (C) 2008 - Jacques Zaninetti - http://www.zygrib.org

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
***********************************************************************/

/*************************
Reader for a GRIB file

*************************/

#ifndef GRIBREADER_H
#define GRIBREADER_H

#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif  // precompiled headers

#include <iostream>
#include <cmath>
#include <vector>
#include <set>
#include <map>

#include "GribRecord.h"
#include "zuFile.h"

//===============================================================
class GribReader {
public:
  GribReader();
  GribReader(const wxString fname);
  ~GribReader();

  void openFile(const wxString fname);
  bool isOk() { return ok; }
  long getFileSize() { return fileSize; }
  wxString getFileName() { return fileName; }

  int getNumberOfGribRecords(int dataType, int levelType, int levelValue);
  int getTotalNumberOfGribRecords();

  GribRecord *getGribRecord(int dataType, int levelType, int levelValue,
                            time_t date);

  GribRecord *getFirstGribRecord();
  GribRecord *getFirstGribRecord(int dataType, int levelType, int levelValue);

  std::vector<GribRecord *> *getListOfGribRecords(int dataType, int levelType,
                                                  int levelValue);

  //      double       getHoursBeetweenGribRecords()  {return
  //      hoursBetweenRecords;}
  std::set<time_t> getListDates() { return setAllDates; }
  int getNumberOfDates() { return setAllDates.size(); }
  time_t getRefDate() {
    return setAllDates.size() > 0 ? *setAllDates.begin() : 0;
  }

  // Valeur pour un point et une date quelconques
  double getTimeInterpolatedValue(int dataType, int levelType, int levelValue,
                                  double px, double py, time_t date);

  // Crée un GribRecord interpolé
  GribRecord *getTimeInterpolatedGribRecord(int dataType, int levelType,
                                            int levelValue, time_t date);

  double computeDewPoint(double lon, double lat, time_t date);

  int getDewpointDataStatus(int levelType, int levelValue);

  enum GribFileDataStatus { DATA_IN_FILE, NO_DATA_IN_FILE, COMPUTED_DATA };

  void copyFirstCumulativeRecord();
  // void  removeFirstCumulativeRecord ();
  void copyMissingWaveRecords();
  void copyFirstCumulativeRecord(int dataType, int levelType, int levelValue);
  // void  removeFirstCumulativeRecord (int dataType,int levelType,int
  // levelValue);
  void copyMissingWaveRecords(int dataType, int levelType, int levelValue);

  void computeAccumulationRecords(int dataType, int levelType, int levelValue);

  std::map<std::string, std::vector<GribRecord *> *> *getGribMap() {
    return &mapGribRecords;
  }  // dsr

private:
  bool ok;
  wxString fileName;
  ZUFILE *file;
  long fileSize;
  //        double    hoursBetweenRecords;
  int dewpointDataStatus;

  std::map<std::string, std::vector<GribRecord *> *> mapGribRecords;

  void storeRecordInMap(GribRecord *rec);

  void readGribFileContent();
  void readAllGribRecords();
  void createListDates();
  double computeHoursBeetweenGribRecords();
  std::set<time_t> setAllDates;

  void clean_vector(std::vector<GribRecord *> &ls);
  void clean_all_vectors();
  std::vector<GribRecord *> *getFirstNonEmptyList();

  // Interpolation between 2 GribRecord
  double get2GribsInterpolatedValueByDate(double px, double py, time_t date,
                                          GribRecord *before,
                                          GribRecord *after);

  // Détermine les GribRecord qui encadrent une date
  void findGribsAroundDate(int dataType, int levelType, int levelValue,
                           time_t date, GribRecord **before,
                           GribRecord **after);
};

#endif
