/*

  XMunipack


  Copyright © 2009-2015, 2017-20 F.Hroch (hroch@physics.muni.cz)

  This file is part of Munipack.

  Munipack 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.

  Munipack 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 Munipack.  If not, see <http://www.gnu.org/licenses/>.

*/

#ifndef _XMUNIPACK_H_
#define _XMUNIPACK_H_

#include "../config.h"
#include "config.h"
#include "fits.h"
#include "enum.h"
#include "types.h"
#include "event.h"
#include "mprocess.h"
#include "mconfig.h"
#include "vocatconf.h"
#include "aphot.h"
#include "enum.h"
#include "fits.h"
#include "icon.h"
#include <wx/wx.h>
#include <wx/string.h>
#include <wx/arrstr.h>
#include <wx/imaglist.h>
#include <wx/listctrl.h>
#include <wx/srchctrl.h>
#include <wx/dataview.h>
#include <wx/listimpl.cpp>
#include <wx/propdlg.h>
#include <wx/process.h>
#include <wx/thread.h>
#include <wx/txtstrm.h>
#include <wx/timer.h>
#include <wx/filepicker.h>
#include <wx/spinctrl.h>
#include <wx/splitter.h>
#include <wx/listbook.h>
#include <wx/treectrl.h>
#include <wx/infobar.h>
#include <wx/grid.h>
#include <wx/palette.h>
#include <wx/dirctrl.h>
#include <wx/artprov.h>
#include <wx/animate.h>
#include <wx/dnd.h>
#include <wx/xml/xml.h>
#include <queue>
#include <vector>
#include <list>

#if wxUSE_FSWATCHER
#include <wx/fswatcher.h>
#endif

#ifdef __WXDEBUG__
#include <wx/debug.h>
#endif

class MuniPreferences: public wxPropertySheetDialog
{
public:
  MuniPreferences(wxWindow *, MuniConfig *);

private:

  MuniConfig *config;
  wxChoice *ocs;

  wxPanel *CreateGeneral(wxWindow *);
  wxPanel *CreateKeywords(wxWindow *);
  wxPanel *CreateColors(wxWindow *);

  void OnClose(wxCloseEvent&);
  void OnColorReset(wxCommandEvent&);
  void OnIdle(wxIdleEvent&);

};


class MuniThumbnail
{
public:
  MuniThumbnail(const FitsMeta&);
  MuniThumbnail(const wxString&);
  MuniThumbnail(wxInputStream&);

  void Load(const wxString&);
  void Load(wxInputStream&);
  void Save(const wxString&);
  void Save(wxOutputStream&);
  bool IsOk() const;


  FitsMeta GetMeta() const;
  void SetMeta(const FitsMeta&);

  wxString GetURL() const;

private:

  FitsMeta meta;

  wxString icon;
  wxArrayString icons;

  wxXmlDocument CreateXML(const FitsMeta&,const wxString&);
  FitsMeta ParseXML(const wxXmlDocument&);
  wxString CreateIconame(const wxString&,const wxString& =wxEmptyString);

};

class FitsOpen: public wxThread
{
public:
  FitsOpen(wxEvtHandler *,const wxString&, int);
  virtual ~FitsOpen();

private:

  wxEvtHandler *handler;
  wxString filename;
  int icon_size;

  ExitCode Entry();

};

class FitsExport: public wxThread
{
public:
  FitsExport(wxEvtHandler *, const FitsArray&, const wxString&, const FitsTone&,
	     const FitsItt&, const FitsPalette&, const FitsColor&);
  virtual ~FitsExport();

private:

  wxEvtHandler *handler;
  FitsArray array;
  wxString savename;
  FitsTone tone;
  FitsItt itt;
  FitsPalette pal;
  FitsColor colour;

  ExitCode Entry();
};


class MuniFileProperties: public wxDialog
{
public:
  MuniFileProperties(wxWindow *w, const FitsMeta& , const MuniConfig *);

private:

  FitsMeta meta;

};

class MuniDirProperties: public wxDialog
{
 public:
  MuniDirProperties(wxWindow*,const MuniConfig*,const std::vector<FitsMeta>&);

};



class MuniConsoleItem
{
public:
  MuniConsoleItem(const wxString& t, int i): text(t),iindex(i) {}
  wxString GetText() const { return text; }
  int GetImageIndex() const { return iindex; }

private:

  wxString text;
  int iindex;

};


class MuniConsole: public wxFrame
{
public:
  MuniConsole(wxWindow *, MuniConfig *);
  virtual ~MuniConsole();
  void AppendOutput(const wxArrayString&);
  void AppendError(const wxArrayString&);
  void AppendOutput(const wxString&);
  void AppendError(const wxString&);

private:

  MuniConfig *config;
  //  wxTextCtrl *output,*error;
  wxListCtrl *list;
  wxMenu *menuView;
  wxToolBar *tsel;
  wxSearchCtrl *search;
  wxFont fixed;
  std::vector<MuniConsoleItem> listitem;

  int logs;
  bool wrap;

  void OnClose(wxCloseEvent&);
  void OnSize(wxSizeEvent&);
  void FileClose(wxCommandEvent&);
  void SaveOutput(wxCommandEvent&);
  void ClearOutput(wxCommandEvent&);
  void SelectOutput(wxCommandEvent&);
  void AppendItems(size_t);
  void SetLogs(int);
  void SetColumnWidth();
  void Search(wxCommandEvent&);
  void SearchFinish(wxCommandEvent&);
  void OnWrap(wxCommandEvent&);

  DECLARE_EVENT_TABLE()
};


/*
class MuniLog: public wxLogWindow
{
public:
  MuniLog(wxWindow *);
  virtual ~MuniLog();

  virtual bool OnFrameClose(wxFrame *);
  bool Visibility();

private:

  wxWindow *topwin;
  bool visible;

};
*/


// class MuniGraph: public wxPanel
// {
// public:
//   MuniGraph(wxWindow *);
//   ~MuniGraph();

//   void SetItt(const FitsItt& i);
//   void SetHisto(const FitsHisto&);
//   void SetHisto(const std::vector<FitsHisto>&);
//   wxSize DoGetBestSize() const;

// private:

//   FitsItt itt;
//   std::vector<FitsHisto> hlist;
//   wxFont sf;
//   const int strip_width, big_tic, small_tic;

//   void OnPaint(wxPaintEvent&);
//   void OnSize(wxSizeEvent&);
//   void Create();

//   DECLARE_EVENT_TABLE()
// };



// class MuniStrip: public wxPanel
// {
// public:
//   MuniStrip(wxWindow *, const wxSize&, const FitsItt&, const FitsPalette&);

//   void SetItt(const FitsItt&);
//   void SetPalette(const FitsPalette&);

// private:

//   FitsItt itt;
//   FitsPalette pal;
//   wxFont sf;
//   const int strip_height, big_tic, small_tic;
//   wxBitmap strip;

//   void OnPaint(wxPaintEvent&);
//   void OnSize(wxSizeEvent&);
//   void OnIdle(wxIdleEvent&);
//   void Create();

//   DECLARE_EVENT_TABLE()
// };




class MuniThumbCanvas: public wxWindow
{
  wxBitmap icon;
  void OnPaint(wxPaintEvent& WXUNUSED(event));

public:
  MuniThumbCanvas(wxWindow *, const wxBitmap&);
  void SetIcon(const wxBitmap&);
  void SetIcon(const wxImage&);
};



// class MuniDialog: public wxDialog
// {
//   MuniConfig *config;
//   MuniProcess *mproc;
//   wxTimer timer;
//   wxAnimationCtrl *anim;
//   wxButton *execute, *stop;
//   wxStaticText *status;
//   wxString action, help;
//   long index;
//   wxArrayString out;

//   void OnHelp(wxCommandEvent&);
//   void OnExecute(wxCommandEvent&);
//   void OnStop(wxCommandEvent&);
//   void OnTimer(wxTimerEvent&);
//   void OnFinish(wxProcessEvent&);
//   void OnStdButton(wxCommandEvent&);

//  protected:

//   wxString fitsname, tmpfits;

//   void SetAction(const wxString&);
//   void SetHelp(const wxString&);
//   void SetStatus(const wxString&);
//   wxString Parser(const wxString&, const wxString&) const;
//   //  void Write(const wxString&, ...);
//   wxSizer *CreateStatusSizer(const wxString&);
//   wxSizer *CreateButtonSizer(long);
//   wxArrayString GetOutput() const;
//   wxArrayString GetLastOutput();
//   virtual void OnInput(MuniProcess *) = 0;
//   virtual void OnOutput(const wxArrayString&);
//   virtual void CleanDraw() const {}
//   //  virtual void DrawStars(const wxArrayString&) const;

//   // public:
//   MuniDialog(wxWindow *, MuniConfig *, const wxString&, const wxString&);
//   virtual ~MuniDialog();

// };


/*
class MuniPhotometry: public MuniBaseDialog
{
public:
  MuniPhotometry(wxWindow *,MuniConfig *, const wxString&);
  virtual ~MuniPhotometry();

  wxString GetBackup() const;

private:

  wxGauge *progress;
  wxButton *calbutt;
  double fwhm,thresh,saturation,readnoise,phpadu;
  wxString backupfile;
  bool erase,apply,showtooltip;
  std::list<int> ids;

  bool ParseProcessing(const wxArrayString&);
  void EraseCanvas();
  void OnTimer(wxTimerEvent&);

  void OnUpdateUI(wxUpdateUIEvent&);
  void OnIdle(wxIdleEvent&);
  void OnFwhm(wxSpinDoubleEvent&);
  void OnThresh(wxSpinDoubleEvent&);
  void OnSaturation(wxSpinDoubleEvent&);
  void OnReadNoise(wxSpinDoubleEvent&);
  void OnPhpADU(wxSpinDoubleEvent&);
  void OnApply(wxCommandEvent&);
  void OnCancel(wxCommandEvent&);
  void OnFinish(wxProcessEvent&);
  void OnPhotometry(wxCommandEvent&);

};
*/

class MuniFind: public wxDialog
{
  MuniConfig *config;
  MuniProcess *mproc;
  wxTimer timer;
  wxAnimationCtrl *anim;
  wxWindow *plot;
  wxString fitsname, tmpfits;
  const FitsArray array;
  double fwhm, thresh, satur;
  long index;
  wxButton *start, *stop;
  wxStaticText *status;

  double InitSatur() const;
  wxString Parser(const wxString&) const;
  bool StarParser(const wxString&, long *, double *, double *) const;
  void DrawStars(long, long, const wxArrayString&) const;
  void CleanDraw() const;
  long LastStar(const wxString&) const;

  void OnHelp(wxCommandEvent&);
  void OnFind(wxCommandEvent&);
  void OnStop(wxCommandEvent&);
  void OnTimer(wxTimerEvent&);
  void OnFindFinish(wxProcessEvent&);

  void OnFwhm(wxSpinDoubleEvent&);
  void OnThresh(wxSpinDoubleEvent&);
  void OnSatur(wxSpinDoubleEvent&);
  void OnStdButton(wxCommandEvent&);

 public:
  MuniFind(wxWindow *, MuniConfig *, const wxString&, const FitsHdu&);
  virtual ~MuniFind();

  void SetPoint(int,int) const;

};


class MuniCone: public wxDialog
{
public:
  MuniCone(wxWindow *,MuniConfig *,const wxString& =wxEmptyString);
  virtual ~MuniCone();
  wxString GetPath() const { return tmpfile; }

private:

  MuniConfig *config;
  MuniProcess *mproc;
  wxTimer timer;
  VOCatConf catconf;
  wxAnimationCtrl *throbber;
  wxStaticText *status, *johnson_label;
  wxTextCtrl *objentry, *alpha, *delta;
  wxButton *search, *stop;
  wxCheckBox *johnson;
  bool apply;

  wxSpinCtrlDouble *radius, *magmin, *magmax;
  wxString tmpfile, catfits, object;
  double ra,dec;
  long index;
  std::list<int> ids;

  void OnUpdateUI(wxUpdateUIEvent&);
  void OnOk(wxCommandEvent&);
  void OnClose(wxCloseEvent&);
  void OnHelp(wxCommandEvent&);
  void OnObjectName(wxCommandEvent&);
  void OnObjectEnter(wxCommandEvent&);
  void OnGetCoo(wxCommandEvent&);
  void OnRightAscension(wxCommandEvent&);
  void OnDeclination(wxCommandEvent&);
  void OnSearch(wxCommandEvent&);
  void OnFinish(wxProcessEvent&);
  void OnStop(wxCommandEvent&);
  void OnTimer(wxTimerEvent&);
  void OnService(wxCommandEvent&);
  wxString ParseOutput(const wxArrayString&);
  void Resolve();
  void ResolveFinish(wxProcessEvent&);
  double deg(const wxString&, double =1.0);

};


class MuniSelectSource: public wxDialog
{
public:
  MuniSelectSource(wxWindow *, MuniConfig *, bool =false);
  virtual ~MuniSelectSource();
  wxString GetPath() const;
  wxString GetId() const;
  int GetType() const;
  bool GetRelative() const;
  bool IsTemporary() const;
  wxString GetLabelRA() const;
  wxString GetLabelDec() const;
  wxString GetLabelPMRA() const;
  wxString GetLabelPMDec() const;
  wxString GetLabelMag() const;

private:

  MuniConfig *config;
  int page;
  wxChoice *choice_ra, *choice_dec, *choice_pmra, *choice_pmdec, *choice_mag;
  wxString reffile,catfile,tmpcatfile,idlabel,label_ra,label_dec,
    label_pmra,label_pmdec,label_mag;
  bool xframe, astrorel;

  void OnUpdateUI(wxUpdateUIEvent&);
  void CreateControls();
  void OnCheckRel(wxCommandEvent&);
  void OnRefFile(wxFileDirPickerEvent&);
  void OnCatFile(wxFileDirPickerEvent&);
  void OnCatVO(wxCommandEvent&);
  bool CheckCatalogue(const wxString&, wxArrayString&);
  void OnChoice(wxCommandEvent&);
  void OnBookChange(wxBookCtrlEvent&);
  void EraseTemp();
  void SetLabels(const wxArrayString&);

};


class MuniAstrometryOptions: public wxPanel
{
public:
  MuniAstrometryOptions(wxWindow *,MuniConfig *);
  ~MuniAstrometryOptions();

  int GetMatchType() const;
  int GetMinMatch() const;
  int GetMaxMatch() const;
  double GetSig() const;
  double GetFSig() const;
  bool GetFullMatch() const;
  wxString GetOutputUnits() const;

private:

  MuniConfig *config;

  double sig, fsig;
  int minmatch, maxmatch, matchtype;
  bool full_match;
  wxString output_units;
  std::list<int> ids;

  void OnUpdateUI(wxUpdateUIEvent&);
  void OnSpinSig(wxSpinDoubleEvent&);
  void OnSpinFSig(wxSpinDoubleEvent&);
  void OnSpinMinMatch(wxSpinEvent&);
  void OnSpinMaxMatch(wxSpinEvent&);
  void OnMatchType(wxCommandEvent&);
  void OnFullMatch(wxCommandEvent&);
  void OnChoiceUnits(wxCommandEvent&);

};

class MuniAstrometry: public wxDialog
{
public:
  MuniAstrometry(wxWindow *,MuniConfig *);
  virtual ~MuniAstrometry();
  void SetFile(const wxString&, const FitsArray&);
  void SetDetectedSources(const FitsTable&);
  wxString GetBackup() const;

private:

  MuniConfig *config;
  wxSpinCtrlDouble *wscale, *wangle, *acenter, *dcenter;
  wxButton *sunit, *calbutt, *stopbutt, *savebutt, *rembutt;
  wxGauge *progress;
  wxStaticText *overlayid, *refcatid, *info, *infolabel, *proginfo, *proglabel;
  wxBoxSizer *autosizer;
  wxCheckBox *overlay_check, *reflex_checkbox;
  FitsArray array;
  FitsTable catalogue, stars, coverlay;
  wxTimer timer;
  wxDateTime start;
  MuniPipe pipe;
  MuniAstrometryOptions *astropt;

  int nstars,nhist;
  double maglim, s0, rms;
  double xoff,yoff,alpha, delta, scale, reflex, angle, amin, dmin, fmin;
  wxString proj,label_ra,label_dec,label_mag, label_pmra, label_pmdec;
  bool init_par, init_file, init_ref, running, parsing, unsaved,
    draw_overlay, edited, relative, tmpcat,readonly,showtooltip;
  wxString file,catfile,reffile,backupfile,workingfile;
  int output_index, page;
  std::vector<int> hist;
  std::vector<double> x,y,u,v;
  std::list<int> ids;

  void OnUpdateUI(wxUpdateUIEvent&);
  void OnIdle(wxIdleEvent&);
  void OnStdButton(wxCommandEvent&);
  void OnCalibrate(wxCommandEvent&);
  void OnCalibrateStop(wxCommandEvent&);
  void OnCalibrateFinish(wxProcessEvent&);
  void OnOverlay(wxCommandEvent&);
  void OnReflex(wxCommandEvent&);
  void OnDrawOverlay(wxCommandEvent&);
  void OnReference(wxCommandEvent&);
  void OnTimer(wxTimerEvent&);
  void CreateControls();
  void RunProcessing();
  void DrawOverlay(const FitsTable&);
  void OnPopScaleUnit(wxCommandEvent&);
  void OnScaleUnit(wxCommandEvent&);
  void OnInitRef(wxCommandEvent&);
  void OnSpinDouble(wxSpinDoubleEvent&);
  void OnTextDouble(wxCommandEvent&);
  FitsTable LoadCatalogue(const wxString&);
  void InitByCatalogue(const FitsTable&);
  void ParseProcessing(const wxArrayString&);
  void Reset();
  void OnSaveWCS(wxCommandEvent&);
  void OnSaveWCSFinish(wxProcessEvent&);
  void OnChoiceProj(wxCommandEvent&);
  void RemoveWorkingFile();
  void EraseTemp();
  bool FinishClean(wxCommandEvent&);
  double Scale(double) const;
  double Period(double) const;
  void OnRemove(wxCommandEvent&);
  void OnRemoveFinish(wxProcessEvent&);
  void OnBookChange(wxBookCtrlEvent&);

};

class MuniAstrolog
{
  wxDateTime datetime;

 public:
  MuniAstrolog();
  MuniAstrolog(const wxDateTime&);

  wxString GetSign() const;
};

class MuniAstrometer: public wxDialog
{
public:
  MuniAstrometer(wxWindow *, MuniConfig *, const std::vector<FitsMeta> &);
  virtual ~MuniAstrometer();

private:

  MuniConfig *config;
  const std::vector<FitsMeta> list;
  wxDataViewListCtrl *mtable;
  wxFilePickerCtrl *fpick;
  wxStaticText *refcatid;
  wxBoxSizer *topsizer;
  wxGauge *gstat;
  wxButton *butt, *catbutt;
  wxTimer timer;
  MuniPipe pipe;
  MuniAstrometryOptions *astropt;

  int findex,lastrow;
  wxString proj, reffile,catfile,label_ra,label_dec,label_pmra,label_pmdec,
    label_mag;
  bool running,astrorel,relative,tmpcat;
  std::list<int> ids;

  void OnClose(wxCloseEvent&);
  void OnUpdateUI(wxUpdateUIEvent&);
  void CreateControls();
  void CreateProcess();
  void SetTable();
  void ParseOutput();
  void OnProcess(wxCommandEvent&);
  void OnTimer(wxTimerEvent&);
  void OnFinish(wxProcessEvent&);
  void OnReference(wxCommandEvent&);
  void OnChoiceProj(wxCommandEvent&);
  void EraseTemp();

};


class MuniCalibrate: public wxDialog
{
public:
  MuniCalibrate(wxWindow *,MuniConfig *, const wxString&);
  wxString GetResult() const;

private:

  MuniConfig *config;
  wxAnimationCtrl *throbber;
  double fwhm,thresh, alpha, delta, radius;
  wxString file, output, catalog, projection, coutput;
  MuniPipe pipe;

  void OnFwhm(wxSpinDoubleEvent&);
  void OnThresh(wxSpinDoubleEvent&);
  void OnCatalog(wxCommandEvent&);
  void OnProjection(wxCommandEvent&);
  void OnAlpha(wxCommandEvent&);
  void OnDelta(wxCommandEvent&);
  void OnRadius(wxCommandEvent&);
  void OnApply(wxCommandEvent&);
  void OnCancel(wxCommandEvent&);
  void OnFinish(wxProcessEvent&);

};

class MuniColoring: public wxDialog
{
public:
  MuniColoring(wxWindow *,MuniConfig *);
  bool SetDropMeta(int, int, const std::vector<FitsMeta>&);

private:

  const int iSize;

  MuniConfig *config;
  wxChoice *cspace;
  wxString filename,dirname,colorspace;
  wxArrayString cchoices, opt;
  std::vector<FitsMeta> metalist;
  std::vector<wxString> param_lines;
  wxListView *list;
  wxImageList *icons;
  int index;
  MuniPipe pipe;
  wxAnimationCtrl *throbber;

  void Init();
  void CreateControls();
  void InitList(const wxString&);
  void SetMeta(int, const FitsMeta&, double =0.0, double =-1.0);

  void OnBandfile(wxFileDirPickerEvent&);
  void OnFilename(wxCommandEvent&);
  void OnDirname(wxFileDirPickerEvent&);
  void OnApply(wxCommandEvent&);
  void OnCancel(wxCommandEvent&);
  void OnFinish(wxProcessEvent&);
  void OnColorspace(wxCommandEvent&);
  void OnListSelected(wxListEvent&);
  void OnUpdateBandfile(wxUpdateUIEvent&);
  void OnUpdateOk(wxUpdateUIEvent&);

};


class MuniDisplay: public wxWindow
{
public:
  MuniDisplay(wxWindow *w, MuniConfig *);

  bool SetHdu(const FitsHdu&, const wxImage&);
  void SetInitShrink(int);
  //  virtual void SetOverlay(wxInputStream&);
  virtual void SetStars(FitsTable&);
  void InvokeRendering();
  void StopRendering();
  FitsTone GetTone() const;
  FitsItt GetItt() const;
  FitsPalette GetPalette() const;
  FitsColor GetColor() const;
  wxImage GetImage();
  void ShowPanel(bool);
  void ShowCaption(bool);
  void ShowMagnifier(bool);
  void ShowTune(bool=true);
  void ShowGrid(bool =true);
  void ShowSources(bool, const FitsFile&);
  void OnFind(const wxString&, const FitsHdu&);
  void Photometry(const wxString&);
  void Astrometry(const wxString&,const FitsTable&);
  void Calibrate(const wxString&);
  bool IsTuneShown() const;
  bool IsMagnifierShown() const;
  wxSize GetCanvasSize() const;

private:

  MuniConfig *config;
  FitsArray array;
  wxImage thumb;
  wxPanel *panel, *caption;
  wxWindow *canvas;
  wxFrame *tune, *magnifier;
  MuniFind *find;
  MuniAstrometry *astrometry;

  void OnClose(wxCloseEvent&);
  void OnCloseTune(wxCloseEvent&);
  void OnCloseAstrometry(wxCommandEvent&);
  void OnCloseFind(wxCommandEvent&);
  void OnLeaveFullscreen(wxCommandEvent&);
  void OnRenderFinish(MuniRenderEvent&);
  void OnClick(MuniClickEvent&);
  void OnMouseMotion(MuniSlewEvent&);
  void OnTuneFine(MuniTuneEvent&);

};



class MuniGrid: public wxGrid
{
public:
  MuniGrid(wxWindow *w, MuniConfig *);

  bool SetHdu(const FitsHdu&);

private:

  FitsTable table;
  int rows_filled;

  void OnIdle(wxIdleEvent&);
};


class MuniHead: public wxTextCtrl
{
public:
  MuniHead(wxWindow *w, MuniConfig *);

  bool SetHdu(const FitsHdu&);

private:

  MuniConfig *config;
  FitsHdu head;

};

class MuniHeader: public wxFrame
{
public:
  MuniHeader(wxWindow *w, MuniConfig *);

  void SetHdu(const FitsHdu&);

private:

  MuniConfig *config;
  MuniHead *header;
  FitsHdu head;
  wxMenu *menuFile, *menuEdit;

  void OnClose(wxCloseEvent&);
  void FileClose(wxCommandEvent&);
  void FileExport(wxCommandEvent&);
  void EditCut(wxCommandEvent&);
  void EditCopy(wxCommandEvent&);
  void EditPaste(wxCommandEvent&);
};

class MuniSplashing: public wxWindow
{
private:

  wxBitmap logo;
  wxAnimationCtrl *anim;

public:
  MuniSplashing(wxWindow *, const MuniConfig *);
  void Play();
  void Stop();

};


class MuniExtensionList: public wxListView
{
  void OnExtChanged(wxListEvent&);
  wxBitmap DrawIcon(int, int);

public:
  MuniExtensionList(wxWindow*);
  void Set(const FitsMeta&);
  void ChangeSelection(int);

};

class MuniViewZoom: public wxChoice
{
  static const int nratios, oratio;
  static const int ratios[];

  size_t current, bestfit;
  wxArrayString zoomlist;
  wxString Label(int) const;
  void SelectItem(int);
  void OnChoiceSelect(wxCommandEvent&);

public:
  MuniViewZoom(wxWindow *, wxWindowID, int);

  int GetValue() const;
  void SelectIn();
  void SelectOut();
  void SelectNormalSize();
  void SelectBestFitSize();
  void SetBestFit(int,int,int,int);
  bool IsNormalSize() const;
  bool IsBestFitSize() const;
  bool IsIncable() const;
  bool IsOutable() const;

};


class MuniView: public wxFrame
{
public:
  MuniView(wxWindow *,MuniConfig *);
  virtual ~MuniView();
  void LoadFile(const wxString&);
  void SaveFile(const wxString&);
  void LoadMeta(const FitsMeta&);
  void LoadFileBackup(const wxString&, const wxString&);
  bool IsModified() const;
  void CreateFSWatch();

private:

  friend class FitsOpen;
  friend class FitsExport;

  MuniConfig *config;
  bool loadfile;  // trigger for LoadFile during idle
  FitsFile fits;
  FitsMeta meta;
  size_t hdusel;
  std::vector<long> viewid;
  wxArrayString backup;

  wxThread *loader;
  wxCriticalSection loaderCS;

  wxMenu *menuFile,*menuView,*menuExt;
  MuniViewZoom *zoomctrl;
  MuniExtensionList *extlist;
  MuniSplashing *splash;
  std::vector<wxWindow *> places;
  std::vector<int> zoomkeeper;
  //  MuniColoring *coloring;
  //  wxLogWindow *console;
  MuniAphot *aphot;

#if wxUSE_FSWATCHER
  wxFileSystemWatcher *fswatch;
  void OnFileSystemEvent(wxFileSystemWatcherEvent&);
#endif

  void SetupPlaces();
  int GetHduType() const;
  void InitImage();
  void InitTable();
  void InitHead();
  void UpdatePlace(int,bool);
  void ResetPlace();
  int GetHduSel() const;
  void SetupExtension();
  void UpdateZoom(const wxSize&);
  void SendScaleEvent();
  void StopLoading();
  void SetTitle();
  MuniDisplay *GetDisplay() const;

  void OnClose(wxCloseEvent& event);
  void OnIdle(wxIdleEvent& event);
  void OnSize(wxSizeEvent& event);
  void OnClick(MuniClickEvent&);
  void FileClose(wxCommandEvent& WXUNUSED(event));
  void FileOpen(wxCommandEvent& WXUNUSED(event));
  //  void NewBrowser(wxCommandEvent& WXUNUSED(event));
  void NewView(wxCommandEvent& WXUNUSED(event));
  void OnConeSearch(wxCommandEvent&);
  void OnCloseCone(wxCommandEvent&);
  void OnFullScreen(wxCommandEvent& WXUNUSED(event));
  void OnMagnifier(wxCommandEvent& WXUNUSED(event));
  void OnTune(wxCommandEvent& WXUNUSED(event));
  void OnFind(wxCommandEvent& WXUNUSED(event));
  void OnAphot(wxCommandEvent& WXUNUSED(event));
  void OnAphotFinish(wxCommandEvent&);
  void OnAstrometry(wxCommandEvent& WXUNUSED(event));
  void OnShowGrid(wxCommandEvent&);
  void OnShowSources(wxCommandEvent&);
  void OnHeader(wxCommandEvent& WXUNUSED(event));
  void HelpAbout(wxCommandEvent& WXUNUSED(event));
  //  void ViewLog(wxCommandEvent&);
  void FileProperties(wxCommandEvent& WXUNUSED(event));
  void OnPreferences(wxCommandEvent& WXUNUSED(event));
  void ShowToolbar(wxCommandEvent&);
  void ShowExtlist(wxCommandEvent&);
  void ShowCaption(wxCommandEvent&);
  void OnMenuExt(wxCommandEvent&);
  void OnMenuZoom(wxCommandEvent&);
  void OnToolZoom(wxCommandEvent&);
  void OnDetailPanel(wxCommandEvent&);
  //  void SaveAsText(wxString);
  void FileSave(wxCommandEvent& WXUNUSED(event));
  void FileExport(wxCommandEvent& WXUNUSED(event));
  void OnLoadFinish(FitsOpenEvent&);
  void OnExtChanged(wxListEvent&);
  void OnUpdateBackward(wxUpdateUIEvent&);
  void OnUpdateForward(wxUpdateUIEvent&);
  void OnUpdateShowGrid(wxUpdateUIEvent&);
  void OnUpdateShowSources(wxUpdateUIEvent&);
  void OnUpdateShowTune(wxUpdateUIEvent&);
  void OnUpdateShowMagnifier(wxUpdateUIEvent&);
  void OnUpdateZoomFit(wxUpdateUIEvent&);
  void OnUpdateZoom100(wxUpdateUIEvent&);
  void OnUpdateZoomIn(wxUpdateUIEvent&);
  void OnUpdateZoomOut(wxUpdateUIEvent&);
  void OnUpdateFullScreen(wxUpdateUIEvent&);
  /*
  void Coloring(wxCommandEvent& WXUNUSED(event));
  void OnColoringFinish(wxCommandEvent&);
  */

  void OnDraw(MuniDrawEvent&);

  void LoadStart(const wxString&);
  void ExportStart(const wxString&);

  int Unsaved(const wxString&);
  void RemoveBackup();

  // File monitor
  void MonitorFile(const wxString&);
  double MonitorDelay(const wxString&) const;

};

class MuniAnim
{
  // ve stylu totemu nebo vlc pod mac: dole ovladaci prvky,
  // info o obrazku (text) do statusbaru

};




class MuniArchive: public wxEvtHandler
{
public:
  MuniArchive(wxEvtHandler *, const wxString&);

  bool IsReadOnly() const;

  void ChangeDir(const wxString&);
  void MakeDir(const wxString&);
  void DeleteDir(const wxString&);
  void RenameDir(const wxString&,const wxString&);
  wxArrayString GetDirs(const wxString& =wxEmptyString) const;
  wxArrayString GetFiles(const wxString& =wxEmptyString) const;
  wxString GetRoot() const;
  wxString GetAbsPath() const;

  void LoadMeta();
  void StopLoadMeta();
  void FlushMeta(const std::vector<FitsMeta>&, const std::vector<FitsMeta>&);
  std::vector<FitsMeta> GetMeta() const;
  void AppendMeta(const FitsMeta&, long);
  void AppendMeta(const FitsMeta&);
  void AppendMeta(const std::vector<FitsMeta>&);
  void DeleteMeta(const FitsMeta&);
  void DeleteMeta(const std::vector<FitsMeta>&);

  void SetEventHandler(wxEvtHandler *);


private:

  friend class xArchiveThread;

  wxString GetFullPath(const wxString& =wxEmptyString) const;
  wxString DissolveRoot(const wxString&) const;
  long NextAvailableIndex() const;
  wxArrayString GetItems(const wxString&, int,
			 const wxString& =wxEmptyString) const;
  bool IsAbsPath(const wxString&) const;
  void OnMetaOpen(MetaOpenEvent&);
  void OnMetaFinish(MetaOpenEvent&);

  const wxString root;
  wxString cpath;
  const wxString sep;

  wxEvtHandler *handler;
  wxThread *loader;
  wxCriticalSection loaderCS;
};



class MuniCollector: public wxTreeCtrl
{
public:
  MuniCollector(wxWindow *);
  void SetArchive(MuniArchive *);
  void SelectLastItem();
  bool IsOk() const;

private:

  wxEvtHandler *handevt;
  MuniArchive *archive;
  wxTreeItemId workplace, current, last, arch;
  wxString origlabel, tmpdir;

  void CreateTree(const wxTreeItemId&);
  virtual void OnSelChanged(wxTreeEvent&);
  virtual void OnItemMenu(wxTreeEvent&);
  virtual void OnEditBegin(wxTreeEvent&);
  virtual void OnEditEnd(wxTreeEvent&);
  virtual void OnEdit(wxCommandEvent&);
  virtual void OnNewArchive(wxCommandEvent&);
  virtual void OnExcludeArchive(wxCommandEvent&);

  DECLARE_EVENT_TABLE()
};


class MetaRender: public wxThread
{
public:
  MetaRender(wxEvtHandler *, MuniConfig*);
  virtual ~MetaRender();

protected:

  wxEvtHandler *handler;
  MuniConfig *config;

  ExitCode Entry();
};

class MuniListCtrl: public wxListCtrl
{
public:
  MuniListCtrl(wxWindow *, long = 0, MuniConfig * = 0);
  virtual ~MuniListCtrl();

  virtual void AddFits(const wxArrayString&);
  virtual void AddMeta(const FitsMeta&);
  virtual void AddMeta(const std::vector<FitsMeta>&);
  virtual void SetMeta(const std::vector<FitsMeta>&);
  virtual void SelectAll();
  virtual void DeSelectAll();
  virtual std::vector<FitsMeta> GetAllMeta() const;
  virtual std::vector<FitsMeta> GetSelectedMeta() const;
  virtual std::vector<FitsMeta> GetAddedMeta() const;
  virtual std::vector<FitsMeta> GetDeletedMeta() const;
  virtual void DeleteMeta(const std::vector<FitsMeta>&);
  virtual bool DeleteAllMeta();
  virtual void Update();

  virtual void PasteMeta(const FitsMeta&);
  virtual void PasteMeta(const std::vector<FitsMeta>&);

  std::vector<FitsMeta> GetClipboard() const;
  void SetClipboard(const std::vector<FitsMeta>&);

  std::vector<unsigned int> GetSelectedIndex() const;
  void SelectItemLast();
  void SelectItem(long);
  void SelectItemRelative(long);

  virtual void Cut();
  virtual void Copy();
  virtual void Paste();
  virtual void Label(int);
  virtual void Sort(int);
  virtual void Reverse(bool);

  void AddItem(const FitsMeta&);

protected:

  friend class MetaRender;

  MuniConfig *config;
  wxImageList *thumbs;
  std::vector<FitsMeta> flist,addlist,dellist;
  std::queue<FitsMeta> metas;
  wxThread *metarender;
  wxCriticalSection metarenderCS;


  void OnRightClick(wxListEvent&);
  void OnView(wxCommandEvent& WXUNUSED(event));
  void OnProperties(wxCommandEvent& WXUNUSED(event));
  void OnLabel(wxCommandEvent&);
  void OnSort(wxCommandEvent&);
  void OnReverse(wxCommandEvent&);
  void Sorter();
  void OnMouse(wxMouseEvent&);
  void OnCut(wxCommandEvent&);
  void OnCopy(wxCommandEvent&);
  void OnPaste(wxCommandEvent&);
  void OnSelall(wxCommandEvent&);
  void OnFitsOpen(FitsOpenEvent&);
  void OnMetaLoad(MetaOpenEvent&);
  void OnMetaLoadFinish(MetaOpenEvent&);
  void OnMetaOpenFinish(wxCommandEvent&);
  void StopMetaRender();
  void OnMetaRenderFinish(wxThreadEvent&);

};

class MuniListIcon: public MuniListCtrl
{
public:

  MuniListIcon(wxWindow *, MuniConfig * =0);
  virtual void Update();

private:

  long hitem;
  wxImage himage;

  wxString LabelFits(const FitsMeta&, int);
  virtual void HightLightItem(long,bool);
  int iSize() const;
  double iRatio() const;

  void OnMouse(wxMouseEvent&);
  void OnIdle(wxIdleEvent&);

};

class MuniListList: public MuniListCtrl
{
public:
  MuniListList(wxWindow *, MuniConfig * =0);
  virtual void Update();

private:

  void OnIdle(wxIdleEvent&);

};





class MuniDataObjectMeta: public wxDataObjectSimple
{
public:
  MuniDataObjectMeta();
  MuniDataObjectMeta(const std::vector<FitsMeta>& mlist);
  virtual ~MuniDataObjectMeta();

  size_t GetDataSize() const;
  bool GetDataHere(void *) const;
  bool SetData(size_t, const void *);
  std::vector<FitsMeta> GetMetafitses() const;

private:

  size_t len;
  char *data;
};


class MuniListWindow: public wxWindow
{
public:
  MuniListWindow(wxWindow *, wxWindowID, long = 0, MuniConfig * = 0);

  void AddWindow(wxWindow *);
  void SetStyle(long);

  virtual void AddFits(const wxArrayString&);
  virtual void AddMeta(const FitsMeta&);
  virtual void AddMeta(const std::vector<FitsMeta>&);
  virtual void SetMeta(const std::vector<FitsMeta>&);
  virtual void SelectAll();
  virtual void DeSelectAll();
  virtual std::vector<FitsMeta> GetAllMeta() const;
  virtual std::vector<FitsMeta> GetSelectedMeta() const;
  virtual std::vector<FitsMeta> GetAddedMeta() const;
  virtual std::vector<FitsMeta> GetDeletedMeta() const;
  virtual void DeleteMeta(const std::vector<FitsMeta>&);
  virtual bool DeleteAllMeta();
  virtual void Update();

  std::vector<FitsMeta> GetClipboard() const;
  void SetClipboard(const std::vector<FitsMeta>&);

  std::vector<unsigned int> GetSelectedIndex() const;
  void SelectItemLast();
  void SelectItem(long);
  void SelectItemRelative(long);

  virtual int GetSelectedItemCount() const;
  virtual int GetItemCount() const;

  virtual void Cut();
  virtual void Copy();
  virtual void Paste();
  virtual void Label(int);
  virtual void Sort(int);
  virtual void Reverse(bool);

private:

  MuniConfig *config;
  wxBoxSizer *topsizer;
  MuniListCtrl *list;

  void OnProcess(wxProcessEvent&);
  void OnMetaOpen(FitsOpenEvent&);
  void OnMetaLoad(MetaOpenEvent&);

};

class MuniAverage: public MuniListWindow
{
public:
  MuniAverage(wxWindow *,wxWindowID, long =0, MuniConfig * = 0);

private:

  MuniConfig *config;
  MuniPipe pipe;
  wxTimer timer;

  wxTextCtrl *flabel;
  wxDirPickerCtrl *dirpic;
  wxRadioButton *btype[3];
  wxGauge *gauge;
  wxStaticText *label;

  wxString dirname,bitpix,level,filename[3];
  bool robust;
  int xtype;

  void OnDirname(wxFileDirPickerEvent&);
  void OnOptions(wxCommandEvent&);
  void OnCreate(wxCommandEvent&);
  void OnFlabel(wxCommandEvent&);
  void OnBtype(wxCommandEvent&);
  void OnUpdateButt(wxUpdateUIEvent&);
  void OnFinish(wxProcessEvent&);
  void OnUpdate(wxTimerEvent&);

};

class MuniDarkbat: public MuniListWindow
{
public:
  MuniDarkbat(wxWindow *,wxWindowID, long =0, MuniConfig * = 0);

private:

  MuniConfig *config;
  wxFilePickerCtrl *fpic,*dpic,*bpic;
  wxDirPickerCtrl *dirpic;
  wxRadioButton *r0, *r1, *r2;
  wxButton *bcre;
  wxGauge *gauge;
  wxStaticText *label;
  wxString ffilename,dfilename,bfilename,dirname,bitpix,suffix;
  wxArrayString results;
  int mode;
  MuniPipe pipe;
  wxTimer timer;

  void OnFlatname(wxFileDirPickerEvent&);
  void OnDarkname(wxFileDirPickerEvent&);
  void OnBiasname(wxFileDirPickerEvent&);
  void OnDirname(wxFileDirPickerEvent&);
  void OnResult(wxCommandEvent&);
  void OnOptions(wxCommandEvent&);
  void OnCreate(wxCommandEvent&);
  void OnUpdateDirpic(wxUpdateUIEvent&);
  void OnUpdateButt(wxUpdateUIEvent&);
  void OnClearBias(wxCommandEvent&);
  void OnClearDark(wxCommandEvent&);
  void OnClearFlat(wxCommandEvent&);
  wxString CreateResult(const wxString&) const;
  void OnFinish(wxProcessEvent&);
  void OnUpdate(wxTimerEvent&);

};





class MuniImportRawOptions: public wxDialog
{
public:
  MuniImportRawOptions(wxWindow *, MuniConfig *);

  wxString GetType() const;
  wxString GetBand() const;
  wxString GetBitpix() const;
  wxString GetOverWrite() const;
  wxString GetInterpol() const;
  wxString GetDarkframe() const;
  wxString GetDcoptions() const;
  wxString GetDirs() const;

private:

  MuniConfig *config;
  wxChoice *filters,*interpols;
  wxCheckBox *overs;
  wxRadioButton *type0, *type1, *bitpix0, *bitpix1;
  wxFilePickerCtrl *darks;
  wxDirPickerCtrl *dirs;
  wxTextCtrl *dcopts;

  bool over,type_colour,type_grey,bitpix_16bit,bitpix_float;
  int filter,interpol;
  wxString dark,dcopt,dir;
  wxArrayString fchoices,fopt,ichoices,iopt;

  void Init();
  void CreateControls();
  void OnUpdateUI(wxUpdateUIEvent&);
  void OnDarks(wxFileDirPickerEvent&);
  void OnDirs(wxFileDirPickerEvent&);

};


class MuniBrowserSearch: public wxSearchCtrl
{
public:
  MuniBrowserSearch(wxWindow *, wxWindowID, const wxString& =wxEmptyString,
		    const wxPoint& =wxDefaultPosition,
		    const wxSize& =wxDefaultSize, long =0);

  std::vector<long> Find(const std::vector<FitsMeta>&) const;

private:

  int type;
  wxString muster;

  std::vector<long> FindByName(const std::vector<FitsMeta>&) const;
  std::vector<long> FindByKey(const std::vector<FitsMeta>&) const;
  std::vector<long> FindByAdv(const std::vector<FitsMeta>&) const;

  void OnSearchEnter(wxCommandEvent&);
  void OnSearchButton(wxCommandEvent&);
  void OnSearchFinish(wxCommandEvent&);
  void OnSearchMenu(wxCommandEvent&);
  void OnSearchUpdate(wxCommandEvent&);
  void OnUpdateUI(wxUpdateUIEvent&);

};

class MuniImportRaw: public wxDialog
{
private:

  int fcount;
  wxStaticText *label;
  wxGauge *gauge;
  MuniPipe pipe;
  wxString dcdark;

  void OnFinish(wxProcessEvent&);
  void OnClose(wxCloseEvent&);
  void OnCancel(wxCommandEvent&);
  void CreateControls();
  void CreatePipe(const MuniImportRawOptions&, const wxArrayString&);

public:

  MuniImportRaw(wxWindow *, const MuniImportRawOptions&, const wxArrayString&);
  virtual ~MuniImportRaw();

  void Update(int);
  void LoadFile(const wxString&);

};


class MuniBrowser: public wxFrame
{
public:
  MuniBrowser(wxWindow *, MuniConfig *);
  virtual ~MuniBrowser();

  void FileLoad(const wxString&);
  void FilesLoad(const wxArrayString&);

private:

  MuniConfig *config;
  MuniArchive *archive;
  wxMenu *menuFile, *menuView, *menuAct, *menuArrange, *menuLabels, *menuHelp;
  MuniListWindow *list;
  MuniView *view;
  wxSplitterWindow *splitter;
  MuniCollector *collector;
  wxToolBar *tbar,*tbot;
  wxToolBarToolBase *tstop,*twarn;
  wxBoxSizer *topsizer;
  wxStaticText *archiveprop;
  wxArrayString errmsg;

  wxStaticText *padding;
  MuniBrowserSearch *search;
  bool metaload;

  void OnClose(wxCloseEvent&);
  void OnSize(wxSizeEvent&);
  void OnIdle(wxIdleEvent&);
  void FileOpen(wxCommandEvent& WXUNUSED(event));
  void FileSave(wxCommandEvent& WXUNUSED(event));
  void OnPreferences(wxCommandEvent& WXUNUSED(event));
  void OnProperties(wxCommandEvent& WXUNUSED(event));
  void FileClose(wxCommandEvent&);
  void OnSall(wxCommandEvent& WXUNUSED(event));
  void OnCut(wxCommandEvent&);
  void OnCopy(wxCommandEvent&);
  void OnPaste(wxCommandEvent&);
  void SelectItem(wxCommandEvent&);
  void OnIconList(wxCommandEvent&);
  void OnZoomMax(wxCommandEvent&);
  void OnZoom(wxCommandEvent&);
  void NewBrowser(wxCommandEvent& WXUNUSED(event));
  void NewView(wxCommandEvent& WXUNUSED(event));
  void OnView(wxCommandEvent& WXUNUSED(event));
  void OnActivated(wxListEvent&);
  void OnShowToolbar(wxCommandEvent&);
  void OnShowCollector(wxCommandEvent&);
  void FindStars(wxCommandEvent& WXUNUSED(event));
  void AperturePhot(wxCommandEvent& WXUNUSED(event));
  void ProfilePhot(wxCommandEvent& WXUNUSED(event));
  void Matching(wxCommandEvent& WXUNUSED(event));
  void Astrometry(wxCommandEvent& WXUNUSED(event));
  void Stacking(wxCommandEvent& WXUNUSED(event));
  void Deconvolution(wxCommandEvent& WXUNUSED(event));
  void OnAverage(wxCommandEvent& WXUNUSED(event));
  void OnDarkbat(wxCommandEvent& WXUNUSED(event));
  void OnList(wxCommandEvent&);
  //  void HelpHelp(wxCommandEvent& WXUNUSED(event));
  void HelpAbout(wxCommandEvent& WXUNUSED(event));
  //  void HelpBug(wxCommandEvent& WXUNUSED(event));
  void OnNewArchive(wxCommandEvent&);
  void OnExcludeArchive(wxCommandEvent&);
  void OnSelChanged(wxTreeEvent&);
  void OnMetaLoad(MetaOpenEvent&);
  void SetArchiveSize();
  void OnLabel(wxCommandEvent&);
  void OnSort(wxCommandEvent&);
  void OnReverse(wxCommandEvent&);
  void OnCancelAction(wxCommandEvent&);
  void ShowInspect(bool);
  void OnConfigUpdated(wxCommandEvent&);

  void OnSearch(wxCommandEvent&);
  void OnSearchFinish(wxCommandEvent&);

  //  void ImportRaw(const MuniImportRawOptions&,const wxArrayString&);

  void SwitchList(int);
  void LoadMeta();

  void OnUpdateArchive(wxUpdateUIEvent&);
  void OnUpdateActmenu(wxUpdateUIEvent&);
  void OnUpdateFilemenu(wxUpdateUIEvent&);
  void OnUpdateTbot(wxUpdateUIEvent&);
  void OnUpdateCut(wxUpdateUIEvent&);
  void OnUpdatePaste(wxUpdateUIEvent&);

};


class XMunipack: public wxApp
{
  bool OnInit();
  int OnExit();
  void OnFatalException();
  void OnEventLoopEnter(wxEventLoopBase*);

  MuniConfig *config;
  MuniView *view;
  MuniBrowser *browser;

};

#endif
