/*

  xmunipack - config

  Copyright © 2012-5 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_SCALE     "MuniDetail_scale"
#define MUNIDETAIL_ZOOM      "MuniDetail_zoom"
#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 PHOTOMETRY_FWHM      "Astrometry_fwhm"
#define PHOTOMETRY_THRESH    "Astrometry_thresh"
#define PHOTOMETRY_SATUR     "Astrometry_satur"
#define PHOTOMETRY_READNS    "Astrometry_readns"
#define PHOTOMETRY_PHPADU    "Astrometry_phpadu"
#define ICON_SIZE            "Icon_size"
#define ICON_SMALL           "Icon_small"
#define ICON_ZOOM            "Icon_zoom"
#define SCROLL_RATE          "Scroll_rate"
#define DISPLAY_ITT          "Display_itt" 
#define DISPLAY_PAL          "Display_pal" 
#define DISPLAY_ZOOM         "Display_zoom" 
#define DISPLAY_NVISION      "Display_nvision"
#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 COLOR_TEMPERATURE    "Color_temperature"
#define COLOR_WHITEPOINT_U   "Color_whitepoint_u"
#define COLOR_WHITEPOINT_V   "Color_whitepoint_v"
#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(MUNIDETAIL_SCALE,&detail_scale,4);
  Read(MUNIDETAIL_ZOOM,&detail_zoom,40);

  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(PHOTOMETRY_FWHM,&photo_fwhm,2.0);
  Read(PHOTOMETRY_THRESH,&photo_thresh,5.0);
  Read(PHOTOMETRY_SATUR,&photo_satur,DBL_MAX);
  Read(PHOTOMETRY_READNS,&photo_readns,0.0);
  Read(PHOTOMETRY_PHPADU,&photo_phpadu,1.0);

  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_ITT,&val,wxEmptyString);
  display_itt = ITT_LINE;
  for(int i = ITT_FIRST+1; i < ITT_LAST; i++) {
    if( val == FitsItt::Type_str(i) )
      display_itt = i;
  }
  // bad horible, solution, needs to be implemented via iterators, strings

  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;
  }
  // bad horible, solution, needs to be implemented via iterators, strings

  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;
  }
  // bad horible, solution, needs to be implemented via iterators, strings

  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;
  }
  // bad horible, solution, needs to be implemented via iterators, strings

  Read(DISPLAY_ZOOM, &display_zoom, -1.0);
  Read(DISPLAY_NVISION, &display_nvision, 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(COLOR_TEMPERATURE, &color_temperature, 6504.0);
  Read(COLOR_WHITEPOINT_U, &color_uwhitepoint, 0.19784);
  Read(COLOR_WHITEPOINT_V, &color_vwhitepoint, 0.46831);

  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(MUNIDETAIL_SCALE,detail_scale);
  Write(MUNIDETAIL_ZOOM,detail_zoom);
  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(PHOTOMETRY_FWHM,photo_fwhm);
  Write(PHOTOMETRY_THRESH,photo_thresh);
  Write(PHOTOMETRY_SATUR,photo_satur);
  Write(PHOTOMETRY_READNS,photo_readns);
  Write(PHOTOMETRY_PHPADU,photo_phpadu);
  Write(DISPLAY_ITT,FitsItt::Type_str(display_itt));
  Write(DISPLAY_PAL,FitsPalette::Type_str(display_pal));
  Write(DISPLAY_ZOOM,display_zoom);
  Write(DISPLAY_NVISION,display_nvision);
  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(COLOR_TEMPERATURE,color_temperature);
  Write(COLOR_WHITEPOINT_U,color_uwhitepoint);
  Write(COLOR_WHITEPOINT_V,color_vwhitepoint);
  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();
  }
}


MuniArtIcons::MuniArtIcons(const wxArtClient& c, const wxSize& s):
  client(c), size(s) 
{}

wxBitmap MuniArtIcons::Icon(const wxArtID& id) const
{
#ifdef __WXMAC__
  wxString name;
  if( id == "zoom-fit-best" )
    name = "stock_zoom_fit_width");
  else if( id == "zoom-original" )
    name = "stock_zoom_one_to_one";
  else if( id == "preferences-desktop" )
    name = "stock_preferences";
  else if( id == "wxART_GO_UP" )
    name = "stock_up";
  else if( id == "wxART_GO_HOME" )
    name = "stock_home";
  else if( id == "wxART_GO_BACK" )
    name = "stock_back";
  else if( id == "wxART_GO_FORWARD" )
    name = "stock_forward";
  else if( id == "wxART_FOLDER" )
    name = "stock_folder";
  else if( id == "stop" )
    name = "stock_cancel";
  else if( id == "view-refresh" )
    name = "stock_refresh";

  wxString a(id);
  //  wxLogDebug(wxT("MuniArtIcons::Icon ") +a);
  wxString fullpath = MuniConfig::FindIconPath(name+".png");
  if( ! fullpath.IsEmpty() ) {

    //    wxLogDebug(wxT("MuniArtIcons::Icon %s"),fullpath.c_str());
    wxImage icona(fullpath);
    if( icona.Ok() ) {
      return wxBitmap(icona);
    }
  }
  return wxArtProvider::GetBitmap(wxART_MISSING_IMAGE,client,size);

#else

  wxBitmap b = wxArtProvider::GetBitmap(id,client,size);
  if( ! b.IsOk() ) 
    b = wxArtProvider::GetBitmap(wxART_MISSING_IMAGE,client,size);
  return b;
#endif
}
