/******************************************************************************
 *
 * Project:  OpenCPN
 * Purpose:  GRIB Plugin Friends
 * Author:   David Register
 *
 ***************************************************************************
 *   Copyright (C) 2010 by David S. Register   *
 *                                                                         *
 *   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 2 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, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,  USA.         *
 ***************************************************************************
 */

#ifndef __GRIBUICTRLBAR_H__
#define __GRIBUICTRLBAR_H__

#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif  // precompiled headers
#include <wx/fileconf.h>
#include <wx/glcanvas.h>

#include "GribUIDialogBase.h"
#include "CursorData.h"
#include "GribSettingsDialog.h"
#include "GribRequestDialog.h"
#include "GribReader.h"
#include "GribRecordSet.h"
#include "IsoLine.h"
#include "GrabberWin.h"

#ifndef PI
#define PI 3.1415926535897931160E0 /* pi */
#endif

class GRIBUICtrlBar;
class GRIBUICData;
class GRIBFile;
class GRIBRecord;
class GribRecordTree;
class GRIBOverlayFactory;
class GribRecordSet;
class GribRequestSetting;
class GribGrabberWin;
class GribSpacerWin;

class wxFileConfig;
class grib_pi;
class wxGraphicsContext;

WX_DECLARE_OBJARRAY(GribRecordSet, ArrayOfGribRecordSets);

enum ZoneSelection {
  AUTO_SELECTION,
  SAVED_SELECTION,
  START_SELECTION,
  DRAW_SELECTION,
  COMPLETE_SELECTION
};

class GribTimelineRecordSet : public GribRecordSet {
public:
  GribTimelineRecordSet(unsigned int cnt);
  //    GribTimelineRecordSet(GribRecordSet &GRS1, GribRecordSet &GRS2, double
  //    interp_const);
  ~GribTimelineRecordSet();

  void ClearCachedData();

  /* cache isobars here to speed up rendering */
  wxArrayPtrVoid *m_IsobarArray[Idx_COUNT];
};

//----------------------------------------------------------------------------------------------------------
//    GRIB CtrlBar Specification
//----------------------------------------------------------------------------------------------------------
class GRIBUICtrlBar : public GRIBUICtrlBarBase {
public:
  GRIBUICtrlBar(wxWindow *parent, wxWindowID id, const wxString &title,
                const wxPoint &pos, const wxSize &size, long style,
                grib_pi *ppi);
  ~GRIBUICtrlBar();

  void OpenFile(bool newestFile = false);

  void ContextMenuItemCallback(int id);
  void SetFactoryOptions();

  wxDateTime TimelineTime();
  GribTimelineRecordSet *GetTimeLineRecordSet(wxDateTime time);
  void StopPlayBack();
  void TimelineChanged();
  void CreateActiveFileFromNames(const wxArrayString &filenames);
  void PopulateComboDataList();
  void ComputeBestForecastForNow();
  void SetViewPort(PlugIn_ViewPort *vp);
  void SetDataBackGroundColor();
  void SetTimeLineMax(bool SetValue);
  void SetCursorLatLon(double lat, double lon);
  void UpdateTrackingControl();
  void SetDialogsStyleSizePosition(bool force_recompute = false);
  void SetRequestBitmap(int type);
  void OnMouseEvent(wxMouseEvent &event);
  GRIBUICData *GetCDataDialog() { return m_gGRIBUICData; }
  bool InDataPlot(int id) {
    return id > wxID_ANY && id < (int)GribOverlaySettings::GEO_ALTITUDE;
  }
  void SetScaledBitmap(double factor);
  wxBitmap GetScaledBitmap(wxBitmap bitmap, const wxString svgFileName,
                           double scale_factor);
  void OpenFileFromJSON(wxString json);

  //
  double getTimeInterpolatedValue(int idx, double lon, double lat,
                                  wxDateTime t);
  bool getTimeInterpolatedValues(double &M, double &A, int idx1, int idx2,
                                 double lon, double lat, wxDateTime t);

  wxWindow *pParent;
  GribOverlaySettings m_OverlaySettings;

  GribTimelineRecordSet *m_pTimelineSet;

  wxTimer m_tPlayStop;
  grib_pi *pPlugIn;
  GribRequestSetting *pReq_Dialog;
  GRIBFile *m_bGRIBActiveFile;
  bool m_bDataPlot[GribOverlaySettings::GEO_ALTITUDE];  // only for no altitude
                                                        // parameters
  bool m_CDataIsShown;
  int m_ZoneSelAllowed;
  int m_old_DialogStyle;
  double m_ScaledFactor;
  void DoZoomToCenter();

private:
  void OnClose(wxCloseEvent &event);
  void OnSize(wxSizeEvent &event);
  void OnPaint(wxPaintEvent &event);
  void OnSettings(wxCommandEvent &event);
  void OnPlayStop(wxCommandEvent &event);
  void OnPlayStopTimer(wxTimerEvent &event);
  void OnMove(wxMoveEvent &event);
  void OnMenuEvent(wxMenuEvent &event);
  void MenuAppend(wxMenu *menu, int id, wxString label, wxItemKind kind,
                  wxBitmap bitmap = wxNullBitmap, wxMenu *submenu = NULL);
  void OnZoomToCenterClick(wxCommandEvent &event);
  void OnPrev(wxCommandEvent &event);
  void OnRecordForecast(wxCommandEvent &event) {
    StopPlayBack();
    m_InterpolateMode = false;
    m_pNowMode = false;
    TimelineChanged();
  }
  void OnNext(wxCommandEvent &event);
  void OnNow(wxCommandEvent &event) {
    StopPlayBack();
    ComputeBestForecastForNow();
  }
  void OnAltitude(wxCommandEvent &event);
  void OnOpenFile(wxCommandEvent &event);
  void OnRequest(wxCommandEvent &event);
  void OnCompositeDialog(wxCommandEvent &event);

  void OnTimeline(wxScrollEvent &event);
  void OnShowCursorData(wxCommandEvent &event);

  wxDateTime MinTime();
  wxArrayString GetFilesInDirectory();
  void SetGribTimelineRecordSet(GribTimelineRecordSet *pTimelineSet);
  int GetNearestIndex(wxDateTime time, int model);
  int GetNearestValue(wxDateTime time, int model);
  bool GetGribZoneLimits(GribTimelineRecordSet *timelineSet, double *latmin,
                         double *latmax, double *lonmin, double *lonmax);
  wxDateTime GetNow();
  void RestaureSelectionString();
  void SaveSelectionString() {
    m_SelectionIsSaved = true;
    m_Selection_index = m_cRecordForecast->GetSelection();
    m_Selection_label = m_cRecordForecast->GetString(m_Selection_index);
  }

  //    Data
  CursorData *m_gCursorData;
  GribGrabberWin *m_gGrabber;
  GRIBUICData *m_gGRIBUICData;

  PlugIn_ViewPort *m_vp;
  int m_lastdatatype;

  int m_TimeLineHours;
  int m_FileIntervalIndex;
  bool m_InterpolateMode;
  bool m_pNowMode;
  bool m_HasAltitude;

  bool m_SelectionIsSaved;
  int m_Selection_index;
  wxString m_Selection_label;
  wxArrayString m_file_names; /* selected files */
  wxString m_grib_dir;
  wxSize m_DialogsOffset;
};

//----------------------------------------------------------------------------------------------------------
//    GRIBFile Object Specification
//----------------------------------------------------------------------------------------------------------
class GRIBFile {
public:
  GRIBFile(const wxArrayString &file_names, bool CumRec, bool WaveRec,
           bool newestFile = false);
  ~GRIBFile();

  bool IsOK(void) { return m_bOK; }
  wxArrayString &GetFileNames(void) { return m_FileNames; }
  wxString GetLastMessage(void) { return m_last_message; }
  ArrayOfGribRecordSets *GetRecordSetArrayPtr(void) {
    return &m_GribRecordSetArray;
  }
  time_t GetRefDateTime(void) { return m_pRefDateTime; }

  const unsigned int GetCounter() { return m_counter; }

  WX_DEFINE_ARRAY_INT(int, GribIdxArray);
  GribIdxArray m_GribIdxArray;

private:
  static unsigned int ID;

  const unsigned int m_counter;
  bool m_bOK;
  wxString m_last_message;
  wxArrayString m_FileNames;
  GribReader *m_pGribReader;
  time_t m_pRefDateTime;

  //    An array of GribRecordSets found in this GRIB file
  ArrayOfGribRecordSets m_GribRecordSetArray;

  int m_nGribRecords;
};

//----------------------------------------------------------------------------------------------------------
//    GRIB CursorData Dialog Specification
//----------------------------------------------------------------------------------------------------------
class GRIBUICData : public GRIBUICDataBase {
public:
  GRIBUICData(GRIBUICtrlBar &parent);
  ~GRIBUICData() {}

  // GribGrabberWin      *m_gGrabber;
  GRIBUICtrlBar &m_gpparent;
  CursorData *m_gCursorData;

private:
  void OnMove(wxMoveEvent &event);
};

#endif
