/*

  xmunipack - config

  Copyright © 2012-5, 2019 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/>.

*/

#include "mconfig.h"
#include <wx/wx.h>
#include <wx/config.h>
#include <wx/stdpaths.h>
#include <wx/artprov.h>
#include <wx/filename.h>
#include <wx/listctrl.h>
#include <cfloat>

// config
#define MUNIBROWSE_WIDTH     "MuniBrowse_width"
#define MUNIBROWSE_HEIGHT    "MuniBrowse_height"
#define MUNIBROWSE_ICONLIST  "MuniBrowse_iconlist"
#define MUNIBROWSE_LABELTYPE "MuniBrowse_labeltype"
#define MUNIBROWSE_LABELKEY  "MuniBrowse_labelkey"
#define MUNIBROWSE_SORTTYPE  "MuniBrowse_sorttype"
#define MUNIBROWSE_SORTKEY   "MuniBrowse_sortkey"
#define MUNIBROWSE_REVERSE   "MuniBrowse_reverse"
#define MUNIBROWSE_SASH      "MuniBrowse_sash"
#define MUNIBROWSE_COLLECTOR "MuniBrowse_collector"
#define MUNIBROWSE_TBAR      "MuniBrowse_tbar"
#define MUNIVIEW_WIDTH       "MuniView_width"
#define MUNIVIEW_HEIGHT      "MuniView_height"
#define MUNIVIEW_TBAR        "MuniView_tbar"
#define MUNIDETAIL_SHOW      "MuniDetail_show"
#define MUNIDETAIL_SCALE     "MuniDetail_scale"
#define MUNIDETAIL_ZOOM      "MuniDetail_zoom"
#define MUNIMAGNIFIER_SCALE  "MuniMagnifier_scale"
#define MUNIMAGNIFIER_SHOW   "MuniMagnifier_show"
#define MUNIMAGNIFIER_WIDTH  "MuniMagnifier_width"
#define MUNIMAGNIFIER_HEIGHT "MuniMagnifier_height"
#define MUNIEXTLIST_SHOW     "MuniExtlist_show"
#define MUNICAPTION_SHOW     "MuniCaption_show"
/*
#define MUNICONSOLE_WIDTH    "MuniConsole_width"
#define MUNICONSOLE_HEIGHT   "MuniConsole_height"
#define MUNICONSOLE_WRAP     "MuniConsole_wrap"
*/
#define MUNIHELP_WIDTH       "MuniHelp_width"
#define MUNIHELP_HEIGHT      "MuniHelp_height"
#define MUNIHEADER_WIDTH     "MuniHeader_width"
#define MUNIHEADER_HEIGHT    "MuniHeader_height"
#define ASTROMETRY_FULLMATCH "Astrometry_fullmatch"
#define ASTROMETRY_MINMATCH  "Astrometry_minmatch"
#define ASTROMETRY_MAXMATCH  "Astrometry_maxmatch"
#define ASTROMETRY_UNITS     "Astrometry_units"
#define ASTROMETRY_PROJ      "Astrometry_proj"
#define ASTROMETRY_SIG       "Astrometry_sig"
#define ASTROMETRY_FSIG      "Astrometry_fsig"
#define FIND_FWHM            "Find_fwhm"
#define FIND_THRESH          "Find_thresh"
#define APHOT_NAPER          "Aphot_naper"
#define APHOT_RMIN           "Aphot_rmin"
#define APHOT_RMAX           "Aphot_rmax"
#define APHOT_ZOOM           "Aphot_zoom"
#define APHOT_SAPER          "Aphot_saper"
#define APHOT_SPIRAL         "Aphot_spiral"
#define APHOT_SNAP           "Aphot_snap"
#define APHOT_WIDTH          "Aphot_width"
#define APHOT_HEIGHT         "Aphot_height"
#define ICON_SIZE            "Icon_size"
#define ICON_SMALL           "Icon_small"
#define ICON_ZOOM            "Icon_zoom"
#define SCROLL_RATE          "Scroll_rate"
#define DISPLAY_PAL          "Display_pal"
#define DISPLAY_PALINV       "Display_palinv"
#define DISPLAY_COO          "Display_coo"
#define DISPLAY_VAL          "Display_val"
#define DISPLAY_GRID         "Display_grid"
#define DISPLAY_SOURCES      "Display_sources"
#define FITS_KEY_OBJECT      "Fits_key_object"
#define FITS_KEY_OBSERVER    "Fits_key_observer"
#define FITS_KEY_EXPTIME     "Fits_key_exptime"
#define FITS_KEY_GAIN        "Fits_key_gain"
#define FITS_KEY_AREA        "Fits_key_area"
#define FITS_KEY_FILTER      "Fits_key_filter"
#define FITS_KEY_DATEOBS     "Fits_key_dateobs"
#define COLOR_DISPLAY        "Display_colorspace"
#define CDATAFILE            "Colorspace_data"
#define PHSYSTEMFILE         "Photometric_systems"

using namespace std;


MuniConfig::MuniConfig():
  wxConfig(wxEmptyString,wxEmptyString,wxEmptyString,wxEmptyString,
	   wxCONFIG_USE_SUBDIR|wxCONFIG_USE_GLOBAL_FILE|wxCONFIG_USE_LOCAL_FILE),
  dirmask("*.fits*;*.fit*;*.fts*;*.FITS*;*.FTS*;*.FIT*"),
  rawmask("*.cr2;*.crw;*.CR2;*.CRW;*.RAW"),
  backup_suffix("~")
{
  // workaround to create config dir
  // http://article.gmane.org/gmane.comp.lib.wxwindows.general/58942/match=wxCONFIG%5fUSE%5fSUBDIR)
#if !defined(__WXMSW__) || wxUSE_CONFIG_NATIVE

  wxStandardPathsBase &stdpaths = wxStandardPathsBase::Get();
  confdir = stdpaths.GetUserDataDir() + "/";
  //  confdir.Replace("xmunipack","munipack");

  wxFileName dir(confdir);
  if( ! dir.DirExists() ) {
    if( dir.Mkdir() )
      wxLogDebug("Directory "+dir.GetFullPath()+" successfully created.");
    else
      wxLogFatalError("Failed to create of config directory '"+
		      dir.GetFullPath()+"' in your home folder.");
  }
#endif

  // backup suffix
  wxString simple_backup_suffix;
  if( wxGetEnv("SIMPLE_BACKUP_SUFFIX",&simple_backup_suffix) )
    backup_suffix = simple_backup_suffix;


  // initial browser window size
  int x,y,width,height,w,h,k;
  ::wxClientDisplayRect(&x,&y,&width,&height);


  wxString val;

  Read(MUNIBROWSE_WIDTH,&w,3*width/5);
  Read(MUNIBROWSE_HEIGHT,&h,3*height/5);
  browser_size = wxSize(w,h);
  Read(MUNIBROWSE_SASH,&browser_sash,133);
  Read(MUNIBROWSE_COLLECTOR,&browser_collector,1);
  Read(MUNIBROWSE_TBAR,&browser_tbar,1);

  Read(MUNIVIEW_WIDTH,&w,4*width/5);
  Read(MUNIVIEW_HEIGHT,&h,4*height/5);
  Read(MUNIVIEW_TBAR,&view_tbar,1);
  view_size = wxSize(w,h);

  Read(MUNICAPTION_SHOW,&caption_show,1);
  Read(MUNIDETAIL_SHOW,&detail_show,0);
  Read(MUNIDETAIL_SCALE,&detail_scale,4);
  Read(MUNIDETAIL_ZOOM,&detail_zoom,40);

  Read(MUNIMAGNIFIER_SCALE,&magnifier_scale,4);
  Read(MUNIMAGNIFIER_SHOW,&magnifier_show,0);
  Read(MUNIMAGNIFIER_WIDTH,&w,42);
  Read(MUNIMAGNIFIER_HEIGHT,&h,42);
  magnifier_size = wxSize(w,h);

  Read(MUNIEXTLIST_SHOW,&extlist_show,1);

  /*
  Read(MUNICONSOLE_WIDTH,&w,width/2);
  Read(MUNICONSOLE_HEIGHT,&h,height/2);
  console_size = wxSize(w,h);
  Read(MUNICONSOLE_WRAP,&console_wrap,0);
  */

  Read(MUNIHELP_WIDTH,&w,3*width/5);
  Read(MUNIHELP_HEIGHT,&h,4*height/5);
  help_size = wxSize(w,h);

  Read(MUNIHEADER_WIDTH,&w,width/2);
  Read(MUNIHEADER_HEIGHT,&h,4*height/5);
  header_size = wxSize(w,h);

  Read(ASTROMETRY_FULLMATCH,&astrometry_fullmatch,false);
  Read(ASTROMETRY_MINMATCH,&astrometry_minmatch,5);
  Read(ASTROMETRY_MAXMATCH,&astrometry_maxmatch,30);
  Read(ASTROMETRY_PROJ,&astrometry_proj,"GNOMONIC");
  Read(ASTROMETRY_SIG,&astrometry_sig,1.0);
  Read(ASTROMETRY_FSIG,&astrometry_fsig,5.0);
  Read(ASTROMETRY_UNITS,&astrometry_units,"arcsec");

  Read(FIND_FWHM,&find_fwhm,3.0);
  Read(FIND_THRESH,&find_thresh,7.0);

  Read(APHOT_NAPER,&aphot_naper,12);
  Read(APHOT_RMIN,&aphot_rmin,20);
  Read(APHOT_RMAX,&aphot_rmax,30);
  Read(APHOT_ZOOM,&aphot_zoom,4);
  Read(APHOT_SAPER,&aphot_saper,0);
  Read(APHOT_SPIRAL,&aphot_spiral,1);
  Read(APHOT_SNAP,&aphot_snap,1);
  Read(APHOT_WIDTH,&w,-1);
  Read(APHOT_HEIGHT,&h,-1);
  aphot_size = wxSize(w,h);

  Read(ICON_SIZE,&icon_size,150);
  Read(ICON_SMALL,&icon_small,30);
  Read(ICON_ZOOM,&icon_zoom,0);
  Read(SCROLL_RATE,&scroll_rate,10);

  Read(MUNIBROWSE_ICONLIST,&k,0);
  switch(k){
  case 0:  browser_iconlist = wxLC_ICON; break;
  case 1:  browser_iconlist = wxLC_REPORT; break;
  default: browser_iconlist = wxLC_ICON;
  }

  Read(MUNIBROWSE_LABELTYPE,&k,0);
  switch(k){
  case 0:  browser_labeltype = ID_LABEL_FILENAME; break;
  case 1:  browser_labeltype = ID_LABEL_OBJECT;   break;
  case 2:  browser_labeltype = ID_LABEL_DATEOBS;  break;
  case 3:  browser_labeltype = ID_LABEL_FILTER;   break;
  case 4:  browser_labeltype = ID_LABEL_EXPOSURE; break;
  case 5:  browser_labeltype = ID_LABEL_KEY;      break;
  case 6:  browser_labeltype = ID_LABEL_NO;       break;
  default: browser_labeltype = ID_LABEL_FILENAME;
  }


  Read(MUNIBROWSE_LABELKEY,&browser_labelkey,"");

  Read(MUNIBROWSE_SORTTYPE,&k,0);
  switch(k){
  case 0:  browser_sorttype = ID_SORT_FILENAME; break;
  case 1:  browser_sorttype = ID_SORT_OBJECT;   break;
  case 2:  browser_sorttype = ID_SORT_DATEOBS;  break;
  case 3:  browser_sorttype = ID_SORT_FILTER;   break;
  case 4:  browser_sorttype = ID_SORT_EXPOSURE; break;
  case 5:  browser_sorttype = ID_SORT_SIZE;     break;
  case 6:  browser_sorttype = ID_SORT_KEY;      break;
  default: browser_sorttype = ID_SORT_FILENAME;
  }

  Read(MUNIBROWSE_SORTKEY,&browser_sortkey,"");
  Read(MUNIBROWSE_REVERSE,&browser_reverse,0);

  Read(DISPLAY_PAL,&val,wxEmptyString);
  display_pal = PAL_GREY;
  for(int i = PAL_FIRST+1; i < PAL_LAST; i++) {
    if( val == FitsPalette::Type_str(i) )
      display_pal = i;
  }

  Read(DISPLAY_VAL,&val,wxEmptyString);
  display_val = UNIT_COUNT;
  for(int i = UNIT_FIRST+1; i < UNIT_LAST; i++) {
    if( val == FitsValue::Label_str(i) )
      display_val = i;
  }

  Read(DISPLAY_COO,&val,wxEmptyString);
  display_coo = COO_EQDEG;
  for(int i = COO_FIRST+1; i < COO_LAST; i++) {
    if( val == FitsCoo::Label_str(i) )
      display_coo = i;
  }

  Read(DISPLAY_PALINV,&display_palinv, 0);
  Read(DISPLAY_GRID, &display_grid, 0);
  Read(DISPLAY_SOURCES, &display_sources, 0);

  Read(FITS_KEY_OBJECT, &fits_key_object, "OBJECT");
  Read(FITS_KEY_OBSERVER, &fits_key_observer, "OBSERVER");
  Read(FITS_KEY_DATEOBS, &fits_key_dateobs, "DATE-OBS");
  Read(FITS_KEY_EXPTIME, &fits_key_exptime, "EXPTIME");
  Read(FITS_KEY_FILTER, &fits_key_filter, "FILTER");
  Read(FITS_KEY_GAIN, &fits_key_gain, "GAIN");
  Read(FITS_KEY_AREA, &fits_key_area, "AREA");

  Read(COLOR_DISPLAY, &display_colorspace, "sRGB");

  Read(CDATAFILE, &cdatafile, "");
  Read(PHSYSTEMFILE, &phsystemfile, "");

#ifdef MUNIPACK_DATA_DIR
  wxFileName ctab(cdatafile);
  if( ! ctab.IsFileReadable() ) {
    wxFileName cpath(MUNIPACK_DATA_DIR,"ctable.dat");
    if( cpath.FileExists() )
      cdatafile = cpath.GetFullPath();
    else
      wxPrintf("%s: Improper setup. Please, set ctable manually.\n",__FILE__);
  }
  wxFileName phtab(phsystemfile);
  if( ! phtab.IsFileReadable() ) {
    wxFileName phpath(MUNIPACK_DATA_DIR,"photosystems.fits");
    if( phpath.FileExists() )
       phsystemfile = phpath.GetFullPath();
    else
      wxPrintf("%s: Improper setup. Please, set phsystems manually.\n",__FILE__);
  }
#endif


  // validate?

  default_icon = MuniIcon::DefaultIcon(icon_size,icon_size);
  munipack_icon = LoadIcon("munipack_icon.png");
  head_icon = LoadImage("head_icon.png");
  table_icon = LoadImage("table_icon.png");
  throbber = wxAnimation(FindIconPath("throbber.gif"));

}

MuniConfig::~MuniConfig()
{
  int k;

  Write(MUNIBROWSE_WIDTH,browser_size.GetWidth());
  Write(MUNIBROWSE_HEIGHT,browser_size.GetHeight());
  Write(MUNIBROWSE_SASH,browser_sash);
  Write(MUNIBROWSE_COLLECTOR,browser_collector);
  Write(MUNIBROWSE_TBAR,browser_tbar);
  Write(MUNIVIEW_WIDTH,view_size.GetWidth());
  Write(MUNIVIEW_HEIGHT,view_size.GetHeight());
  Write(MUNIVIEW_TBAR,view_tbar);
  Write(MUNICAPTION_SHOW,caption_show);
  Write(MUNIDETAIL_SHOW,detail_show);
  Write(MUNIDETAIL_SCALE,detail_scale);
  Write(MUNIDETAIL_ZOOM,detail_zoom);
  Write(MUNIMAGNIFIER_SCALE,magnifier_scale);
  Write(MUNIMAGNIFIER_SHOW,magnifier_show);
  Write(MUNIMAGNIFIER_WIDTH,magnifier_size.GetWidth());
  Write(MUNIMAGNIFIER_HEIGHT,magnifier_size.GetHeight());
  Write(MUNIEXTLIST_SHOW,extlist_show);
  /*
  Write(MUNICONSOLE_WIDTH,console_size.GetWidth());
  Write(MUNICONSOLE_HEIGHT,console_size.GetHeight());
  Write(MUNICONSOLE_WRAP,console_wrap);
  */
  Write(MUNIHELP_WIDTH,help_size.GetWidth());
  Write(MUNIHELP_HEIGHT,help_size.GetHeight());
  Write(MUNIHEADER_WIDTH,header_size.GetWidth());
  Write(MUNIHEADER_HEIGHT,header_size.GetHeight());
  Write(ICON_SMALL,icon_small);
  Write(ICON_ZOOM,icon_zoom);

  switch(browser_iconlist){
  case wxLC_ICON:   k = 0; break;
  case wxLC_REPORT: k = 1; break;
  default: k = 0;
  }
  Write(MUNIBROWSE_ICONLIST,k);

  switch(browser_labeltype){
  case ID_LABEL_FILENAME: k = 0; break;
  case ID_LABEL_OBJECT:   k = 1; break;
  case ID_LABEL_DATEOBS:  k = 2; break;
  case ID_LABEL_FILTER:   k = 3; break;
  case ID_LABEL_EXPOSURE: k = 4; break;
  case ID_LABEL_KEY:      k = 5; break;
  case ID_LABEL_NO:       k = 6; break;
  default: k = 0;
  }
  Write(MUNIBROWSE_LABELTYPE,k);
  Write(MUNIBROWSE_LABELKEY,browser_labelkey);

  switch(browser_sorttype){
  case ID_SORT_FILENAME: k = 0; break;
  case ID_SORT_OBJECT:   k = 1; break;
  case ID_SORT_DATEOBS:  k = 2; break;
  case ID_SORT_FILTER:   k = 3; break;
  case ID_SORT_EXPOSURE: k = 4; break;
  case ID_SORT_SIZE:     k = 5; break;
  case ID_SORT_KEY:      k = 6; break;
  default: k = 0;
  }
  Write(MUNIBROWSE_SORTTYPE,k);

  Write(MUNIBROWSE_SORTKEY,browser_sortkey);
  Write(MUNIBROWSE_REVERSE,browser_reverse);
  Write(SCROLL_RATE,scroll_rate);
  Write(ASTROMETRY_FULLMATCH,astrometry_fullmatch);
  Write(ASTROMETRY_MINMATCH,astrometry_minmatch);
  Write(ASTROMETRY_MAXMATCH,astrometry_maxmatch);
  Write(ASTROMETRY_PROJ,astrometry_proj);
  Write(ASTROMETRY_SIG,astrometry_sig);
  Write(ASTROMETRY_FSIG,astrometry_fsig);
  Write(ASTROMETRY_UNITS,astrometry_units);
  Write(FIND_FWHM,find_fwhm);
  Write(FIND_THRESH,find_thresh);

  Write(APHOT_NAPER,aphot_naper);
  Write(APHOT_RMIN,aphot_rmin);
  Write(APHOT_RMAX,aphot_rmax);
  Write(APHOT_ZOOM,aphot_zoom);
  Write(APHOT_SAPER,aphot_saper);
  Write(APHOT_SPIRAL,aphot_spiral);
  Write(APHOT_SNAP,aphot_snap);
  Write(APHOT_WIDTH,aphot_size.GetWidth());
  Write(APHOT_HEIGHT,aphot_size.GetHeight());

  Write(DISPLAY_PAL,FitsPalette::Type_str(display_pal));
  Write(DISPLAY_PALINV,display_palinv);
  Write(DISPLAY_GRID,display_grid);
  Write(DISPLAY_SOURCES,display_sources);
  Write(DISPLAY_COO,FitsCoo::Label_str(display_coo));
  Write(DISPLAY_VAL,FitsValue::Label_str(display_val));
  Write(FITS_KEY_OBJECT,fits_key_object);
  Write(FITS_KEY_OBSERVER,fits_key_observer);
  Write(FITS_KEY_DATEOBS,fits_key_dateobs);
  Write(FITS_KEY_EXPTIME,fits_key_exptime);
  Write(FITS_KEY_FILTER,fits_key_filter);
  Write(FITS_KEY_GAIN,fits_key_gain);
  Write(FITS_KEY_AREA,fits_key_area);
  Write(COLOR_DISPLAY,display_colorspace);
  Write(CDATAFILE,cdatafile);
  Write(PHSYSTEMFILE,phsystemfile);

}

wxString MuniConfig::FindIconPath(const wxString& name)
{
  wxArrayString p;

#ifdef __WXDEBUG__
  p.Add("icons");
#endif

  wxPathList paths(p);

#ifdef MUNIPACK_ICON_DIR
  paths.Add(MUNIPACK_ICON_DIR);
#endif

  wxString fullpath = paths.FindValidPath(name);
  return fullpath;
}

wxIcon MuniConfig::LoadIcon(const wxString& name)
{
  wxString fullpath = FindIconPath(name);

  wxIcon icon;
  if( ! fullpath.IsEmpty() ) {

    //    wxLogDebug(fullpath);
    wxImage icona(fullpath);
    if( icona.Ok() ) {
      wxBitmap bitmap(icona);
      icon.CopyFromBitmap(bitmap);
    }
  }

  if( ! icon.IsOk() )
    icon = wxArtProvider::GetIcon(wxART_MISSING_IMAGE,wxART_OTHER,wxDefaultSize);

  return icon;
}

wxImage MuniConfig::LoadImage(const wxString& name)
{
  wxString fullpath = FindIconPath(name);

  wxImage image;
  if( ! fullpath.IsEmpty() && image.LoadFile(fullpath) ) {
    //    wxLogDebug(fullpath);
    return image;
  }
  else {
    wxBitmap b(wxArtProvider::GetBitmap(wxART_MISSING_IMAGE,wxART_OTHER,
					wxDefaultSize));
    return b.ConvertToImage();
  }
}
