/*

  xmunipack - file browser window


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

*/


#include "xmunipack.h"
#include "help.h"
#include <algorithm>
#include <vector>
#include <typeinfo>
#include <wx/wx.h>
#include <wx/dirdlg.h>
#include <wx/list.h>
#include <wx/listctrl.h>
#include <wx/imaglist.h>
#include <wx/filename.h>
#include <wx/aboutdlg.h>
#include <wx/dirctrl.h>
#include <wx/tooltip.h>
#include <wx/srchctrl.h>
#include <wx/wupdlock.h>
#include <wx/utils.h>
#include <wx/busyinfo.h>

using namespace std;


MuniBrowser::MuniBrowser(wxWindow *w, MuniConfig *c):
  wxFrame(w, wxID_ANY,wxEmptyString,wxDefaultPosition,
	  c->browser_size, wxDEFAULT_FRAME_STYLE),
  config(c),
  archive(new MuniArchive(GetEventHandler(),config->confdir)),
  menuView(new wxMenu), menuAct(new wxMenu),
  menuArrange(new wxMenu), menuLabels(new wxMenu), list(0),
  view(0),
  splitter(0), collector(0), tbar(0), tbot(0), tstop(0), twarn(0),
  topsizer(0),  archiveprop(0),
  metaload(false)
{
  SetIcon(config->munipack_icon);

#ifdef __WXMAC__
  // all main windows?
  SetExitOnFrameDelete(true);
  wxMenuBar *menubar = new wxMenuBar;
  wxMenuBar::MacSetCommonMenuBar(menubar);
#endif

  // toolbars
  tbar = new wxToolBar(this,wxID_ANY,wxDefaultPosition,wxDefaultSize,
		       wxTB_TOP | wxTB_HORIZONTAL | wxTB_TEXT);
  tbar->SetFont(*wxSMALL_FONT);
  MuniArtIcons icons(wxART_TOOLBAR,wxSize(22,22));
  tbar->AddTool(wxID_OPEN,"Open",icons.Icon(wxART_FILE_OPEN),
		"Load files to the current archive");
  tbar->AddSeparator();
  tbar->AddTool(wxID_CUT,"Cut",icons.Icon(wxART_CUT),
		"Remove selected files");
  tbar->AddTool(wxID_COPY,"Copy",icons.Icon(wxART_COPY),
		"Copy selected files to clipboard");
  tbar->AddTool(wxID_PASTE,"Paste",icons.Icon(wxART_PASTE),
		"Paste selected files from clipboard");
  tbar->AddSeparator();
  padding = new wxStaticText(tbar,wxID_ANY,wxEmptyString,wxDefaultPosition,wxSize(1,-1));
  tbar->AddControl(padding);
  tbar->AddStretchableSpace();
  wxSize s = GetSize();
  search = new MuniBrowserSearch(tbar,wxID_FIND,wxEmptyString,wxDefaultPosition,
				 wxSize((20*s.GetWidth())/100,wxDefaultCoord),
				 wxTE_PROCESS_ENTER);
  tbar->AddControl(search);
  tbar->Realize();
  tbar->Show(config->browser_tbar);

  tbot = new wxToolBar(this,wxID_ANY,wxDefaultPosition,wxDefaultSize,
		       wxTB_BOTTOM | wxTB_HORIZONTAL);
  tbot->AddTool(wxID_ADD,wxEmptyString,icons.Icon(wxART_ADD_BOOKMARK),
		"Add a new archive.");
  tbot->AddTool(wxID_REMOVE,wxEmptyString,icons.Icon(wxART_DEL_BOOKMARK),
		"Remove the selected archive.");
  tbot->AddTool(wxID_STOP,wxEmptyString,icons.Icon(wxART_CROSS_MARK),
		"STOP");
  tbot->AddTool(ID_WARNING,wxEmptyString,icons.Icon(wxART_WARNING),
	"Some errors occurred. For details, check menu Tools->Logs.");
  archiveprop = new wxStaticText(tbot,wxID_ANY,wxEmptyString,wxDefaultPosition,
			 wxDefaultSize,wxALIGN_CENTRE|wxST_NO_AUTORESIZE);
  archiveprop->SetFont(*wxSMALL_FONT);
  tbot->AddControl(archiveprop);
  tstop = tbot->RemoveTool(wxID_STOP);
  twarn = tbot->RemoveTool(ID_WARNING);
  tbot->Realize();

  // menus
  wxMenu *menuWizards = new wxMenu;
  menuWizards->Append(ID_LC,"Light curve");
  menuWizards->Append(ID_CMD,"Color diagram");

  menuFile = new wxMenu;
  menuFile->Append(wxID_NEW);
  //  menuFile->Append(ID_NEW_BROWSER,wxT("New"));
  //menuFile->Append(ID_NEW_VIEW, wxT("New &View..."));
  menuFile->Append(wxID_OPEN);
  menuFile->Append(ID_NEW_VIEW,"View...");

  //  menuFile->Append(wxID_SAVEAS);
  //  menuFile->AppendSubMenu(menuExport,wxT("Export"));
  menuFile->Append(ID_EXPORT,"Export As...");
  //  menuFile->Append(wxID_SAVEAS,wxT("Export Files"));
  //  menuFile->AppendSeparator();
  //  menuFile->Append(wxID_ADD,wxT("New Archive..."));
  //  menuFile->Append(wxID_REMOVE,wxT("Exclude Archive"));
#ifdef __WXMAC__
  menuFile->Append(wxID_CLOSE);
#endif
  menuFile->AppendSeparator();
  menuFile->Append(wxID_PROPERTIES);
#ifndef __WXMAC__
  menuFile->AppendSeparator();
  menuFile->Append(wxID_CLOSE,wxEmptyString,
		 "Close this window (or finish xmunipack).");
#endif
#ifdef __WXMAC__
  menuFile->AppendSeparator();
  menuFile->Append(wxID_EXIT);
#endif

  wxMenu *menuEdit = new wxMenu;
  menuEdit->Append(wxID_CUT);
  menuEdit->Append(wxID_COPY);
  menuEdit->Append(wxID_PASTE);
  menuEdit->AppendSeparator();
  menuEdit->Append(wxID_SELECTALL);
  menuEdit->AppendSeparator();
  menuEdit->Append(wxID_PREFERENCES);
  // edit header?

  menuArrange->AppendRadioItem(ID_SORT_FILENAME,"By Filename");
  menuArrange->AppendRadioItem(ID_SORT_OBJECT,"By Object");
  // menuArrange->AppendRadioItem(wxID_ANY,wxT("By Type"));
  //  menuArrange->AppendRadioItem(wxID_ANY,wxT("By Dimensions"));
  menuArrange->AppendRadioItem(ID_SORT_DATEOBS,"By Start of Observation");
  menuArrange->AppendRadioItem(ID_SORT_FILTER,"By Filter");
  menuArrange->AppendRadioItem(ID_SORT_EXPOSURE,"By Exposure Time");
  menuArrange->AppendRadioItem(ID_SORT_SIZE,"By Filesize");
  menuArrange->AppendRadioItem(ID_SORT_KEY,"By Predefined Keyword");
  menuArrange->AppendSeparator();
  menuArrange->AppendCheckItem(ID_SORT_REVERSE,"Reverse");

  menuLabels->AppendRadioItem(ID_LABEL_FILENAME,"Filename");
  menuLabels->AppendRadioItem(ID_LABEL_OBJECT,"Object");
  menuLabels->AppendRadioItem(ID_LABEL_DATEOBS,"Date of Observation");
  menuLabels->AppendRadioItem(ID_LABEL_FILTER,"Filter");
  menuLabels->AppendRadioItem(ID_LABEL_EXPOSURE,"Exposure Time");
  menuLabels->AppendRadioItem(ID_LABEL_KEY,"Predefined Keyword");
  menuLabels->AppendRadioItem(ID_LABEL_NO,"No Labels");

  menuView->AppendSubMenu(menuArrange,"Arrange Images");
  menuView->AppendSubMenu(menuLabels,"Show Labels as");
  menuView->AppendRadioItem(wxID_VIEW_LARGEICONS,"View as Icons");
  menuView->AppendRadioItem(wxID_VIEW_LIST,"View as List");
  menuView->AppendCheckItem(ID_VIEW_MARK,"Mark by Type",
		   "Mark scientific, flats, dark, .. exposures.");
  menuView->AppendSeparator();
  menuView->Append(wxID_ZOOM_100);
  menuView->Append(wxID_ZOOM_IN);
  menuView->Append(wxID_ZOOM_OUT);
  menuView->AppendSeparator();
  menuView->AppendCheckItem(ID_TOOLBAR,"Show Toolbar",
    "Change visibility of toolbar (shorthand buttons with icons on top)");
  menuView->Check(ID_TOOLBAR,config->browser_tbar);
  menuView->AppendCheckItem(ID_COLLECTOR,"Archive Tree",
    "Change visibility of archive tree (directory structure on left)");
  menuView->Check(ID_COLLECTOR,config->browser_collector);
  menuView->AppendSeparator();
  menuView->Append(wxID_STOP);

  menuAct->Append(ID_LIST,"Workplace");
  menuAct->Append(wxID_ADD,"New Archive...");
  menuAct->Append(wxID_REMOVE,"Exclude Archive");
  menuAct->AppendSeparator();
  //  menuAct->Append(ID_COLORING,wxT("Coloring..."));
  //  menuAct->Append(ID_FIND,wxT("Find Stars..."),
  //		  wxT("Detection of stars on images."));
  //  menuAct->Append(ID_PHOT,"Photometry...","Aperture photometry.");
  //  menuAct->Append(ID_PROFILE,wxT("Profile Photometry..."),
  //		  wxT("Profile photometry."));
  //  menuAct->Append(ID_MATCH,wxT("Matching of Images..."),
  //		  wxT("By genetic algorithm or Fourier transformation."));
  menuAct->Append(ID_ASTROMET,"Astrometry...","Astrometry calibration");
  menuAct->Append(ID_KOMBINE,"Compose Images...","Composition of images.");
  menuAct->Append(ID_DEKON,"Deconvolution...","Deconvolution of images.");
  menuAct->Append(ID_DARKBAT,"Correction");
  menuAct->Append(ID_AVERAGE,"Average");
  menuAct->Append(ID_ARITH,"Arithmetic...","Basic arithmetical operations with images.");
  //  menuAct->AppendSeparator();
  //  menuAct->AppendCheckItem(ID_LOG, wxT("&Log..."));

  wxMenu *menuGo = new wxMenu;
  menuGo->Append(wxID_UP);
  menuGo->Append(wxID_HOME);

  menuHelp = new wxMenu;
  //  menuHelp->AppendCheckItem(ID_LOG,"&Log...");
  //  menuHelp->Append(ID_LOG,"Log");
  menuHelp->Append(wxID_ABOUT);

  wxMenuBar *menuBar = new wxMenuBar;
  menuBar->Append(menuFile,"&File");
  menuBar->Append(menuEdit,"&Edit");
  menuBar->Append(menuView,"&View");
  // operations?
  menuBar->Append(menuAct,"&Tools");
  menuBar->Append(menuWizards,"&Assistants");
  menuBar->Append(menuHelp,"&Help");

  // gray temporary unaccesible tools
  //  menuFile->Enable(wxID_SAVEAS,false);
  menuFile->Enable(ID_EXPORT,false);

  //  menuEdit->Enable(wxID_PREFERENCES,false);

  menuView->Enable(wxID_ZOOM_IN,config->icon_zoom != 0);
  menuView->Enable(wxID_ZOOM_OUT,config->icon_zoom != 5);
  menuArrange->Enable(ID_SORT_KEY,false);
  menuLabels->Enable(ID_LABEL_KEY,false);
  menuView->Enable(ID_VIEW_MARK,false);
  menuView->Enable(wxID_STOP,false);

  //  menuAct->Enable(ID_PHOT,false);
  //  menuAct->Enable(ID_PROFILE,false);
  //  menuAct->Enable(ID_MATCH,false);
  //  menuAct->Enable(ID_ASTROMET,false);
  menuAct->Enable(ID_KOMBINE,false);
  menuAct->Enable(ID_DEKON,false);
  menuAct->Enable(ID_ARITH,false);
  menuWizards->Enable(ID_LC,false);
  menuWizards->Enable(ID_CMD,false);
  //  menuBar->Enable(menuBar->FindMenu(wxT("Assistants")),false);

  SetMenuBar(menuBar);

  topsizer = new wxBoxSizer(wxVERTICAL);

  topsizer->Add(tbar,wxSizerFlags().Expand());

  splitter = new wxSplitterWindow(this);
  splitter->SetSashGravity(0.0);

  collector = new MuniCollector(splitter);

  // icon space
  list = new MuniListWindow(splitter,ID_LIST,config->browser_iconlist,config);

  if( config->browser_collector )
    splitter->SplitVertically(collector,list,config->browser_sash);
  else
    splitter->Initialize(list);

  topsizer->Add(splitter,wxSizerFlags(1).Expand());
  topsizer->Add(tbot,wxSizerFlags().Expand());

  SetSizer(topsizer);

  menuLabels->Check(config->browser_labeltype,true);
  menuArrange->Check(config->browser_sorttype,true);
  menuArrange->Check(ID_SORT_REVERSE,config->browser_reverse);
  switch (config->browser_iconlist) {
  case wxLC_ICON:   menuView->Check(wxID_VIEW_LARGEICONS,true); break;
  case wxLC_REPORT: menuView->Check(wxID_VIEW_LIST,true); break;
  }
  menuView->Enable(menuView->FindItem("Show Labels as"),
		   config->browser_iconlist==wxLC_ICON);


  Bind(wxEVT_CLOSE_WINDOW,&MuniBrowser::OnClose,this);
  //  Bind(wxEVT_SIZE,&MuniBrowser::OnSize,this);
  //  Bind(wxEVT_IDLE,&MuniBrowser::OnIdle,this);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::NewBrowser,this,wxID_NEW);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::NewView,this,ID_NEW_VIEW);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnView,this,ID_VIEW);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::FileOpen,this,wxID_OPEN);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::FileSave,this,wxID_SAVE);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::FileClose,this,wxID_CLOSE);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnNewArchive,this,wxID_ADD);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnExcludeArchive,this,wxID_REMOVE);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnPreferences,this,wxID_PREFERENCES);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnProperties,this,wxID_PROPERTIES);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnSall,this,wxID_SELECTALL);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnCut,this,wxID_CUT);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnCopy,this,wxID_COPY);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnPaste,this,wxID_PASTE);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::SelectItem,this,wxID_BACKWARD);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::SelectItem,this,wxID_FORWARD);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnLabel,this,ID_LABEL_FILENAME,ID_LABEL_NO);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnSort,this,ID_SORT_FILENAME,ID_SORT_KEY);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnReverse,this,ID_SORT_REVERSE);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnIconList,this,wxID_VIEW_LARGEICONS);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnIconList,this,wxID_VIEW_LIST);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnZoomMax,this,wxID_ZOOM_100);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnZoom,this,wxID_ZOOM_IN);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnZoom,this,wxID_ZOOM_OUT);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnShowToolbar,this,ID_TOOLBAR);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnShowCollector,this,ID_COLLECTOR);
  //  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::ViewLog,this,ID_LOG);
  //  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::ShowLog,this,ID_WARNING);
  //  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::FindStars,this,ID_FIND);
  //  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::AperturePhot,this,ID_PHOT);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::ProfilePhot,this,ID_PROFILE);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::Matching,this,ID_MATCH);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::Astrometry,this,ID_ASTROMET);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::Stacking,this,ID_KOMBINE);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::Deconvolution,this,ID_DEKON);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnAverage,this,ID_AVERAGE);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnDarkbat,this,ID_DARKBAT);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::OnList,this,ID_LIST);
  Bind(wxEVT_COMMAND_MENU_SELECTED,&MuniBrowser::HelpAbout,this,wxID_ABOUT);
  Bind(wxEVT_COMMAND_SEARCHCTRL_CANCEL_BTN,&MuniBrowser::OnSearch,this,wxID_FIND);
  Bind(wxEVT_COMMAND_SEARCHCTRL_CANCEL_BTN,&MuniBrowser::OnSearchFinish,this,wxID_FIND);
  Bind(wxEVT_COMMAND_TREE_SEL_CHANGED,&MuniBrowser::OnSelChanged,this);
  Bind(wxEVT_COMMAND_LIST_ITEM_ACTIVATED,&MuniBrowser::OnActivated,this);
  Bind(wxEVT_COMMAND_BUTTON_CLICKED,&MuniBrowser::OnCancelAction,this,wxID_CANCEL);
  Bind(EVT_CONFIG_UPDATED,&MuniBrowser::OnConfigUpdated,this);
  Bind(EVT_META_OPEN,&MuniBrowser::OnMetaLoad,this);

  Bind(wxEVT_UPDATE_UI,&MuniBrowser::OnUpdateArchive,this,archiveprop->GetId());
  Bind(wxEVT_UPDATE_UI,&MuniBrowser::OnUpdateTbot,this,wxID_ADD);
  Bind(wxEVT_UPDATE_UI,&MuniBrowser::OnUpdateCut,this,wxID_CUT);
  Bind(wxEVT_UPDATE_UI,&MuniBrowser::OnUpdateTbot,this,wxID_REMOVE);
  Bind(wxEVT_UPDATE_UI,&MuniBrowser::OnUpdatePaste,this,wxID_PASTE);

  if( ! collector->IsOk() ) {
    collector->SetArchive(archive);
  }

}

MuniBrowser::~MuniBrowser()
{
  // remove temporary files
  config->browser_size = GetSize();
  if( splitter->IsSplit() )
    config->browser_sash = splitter->GetSashPosition();
  config->browser_tbar = tbar->IsShown();
  config->browser_collector = collector->IsShown();
  config->browser_reverse = menuArrange->IsChecked(ID_SORT_REVERSE);
  delete archive;
}


void MuniBrowser::OnClose(wxCloseEvent& event)
{
  // view
  if( view && view->GetId() == event.GetId() ) {
    //    wxLogDebug(_("View shutdown"));
    view = 0;
    return;
  }

  // save archive
  if( list->GetId() == ID_LIST &&
      (list->GetAddedMeta().size() > 0 || list->GetDeletedMeta().size() > 0) ) {
    wxWindowDisabler disableAll;
    wxBusyInfo info("Saving changed thumbnails, please wait...", this);
    // whithout this workaround the busybox is showed after the run
    for(int i = 0; i < 3; i++) {
      wxSafeYield();
      wxMicroSleep(100000);
    }
    archive->FlushMeta(list->GetAddedMeta(),list->GetDeletedMeta());
  }



//   // darkbat
//   if( event.GetId() == ID_DARKBAT ) {
//     // enable all controls
//     wxMenuBar *menu = GetMenuBar();
//     menu->Enable(true);
//     tbar->Enable(true);
//     collector->Enable(true);
//     //    if( darkbat->GetReturnCode() == wxID_OK ) {

//     //    }
//   }



  if( metaload ) {
    archive->StopLoadMeta();
    // wxMilliSleep(333);
    // The thread needs some time to be stoped gracefully.
  }

  // add removed tools to prevent leaks
  tbot->AddTool(tstop);
  tbot->AddTool(twarn);
  tbot->Realize();


  Destroy();
}

void MuniBrowser::OnSize(wxSizeEvent& event)
{
  SetArchiveSize();

  wxSize size(GetClientSize());
  wxSize margins(tbar->GetMargins());
  wxSize tool(tbar->GetToolSize());
  wxSize ss(search->GetSize());

  int n(tbar->GetToolsCount());
  int x = size.GetWidth() - 2*n*margins.GetWidth() -n*tool.GetWidth() -
    ss.GetWidth();
  x = size.GetWidth() - ss.GetWidth() - 3*tool.GetWidth() - (tbar->GetToolsCount()-2)*tool.GetWidth() - 2*n*margins.GetWidth();
  //  wxLogDebug(wxT("%d %d %d %d %d"),x,size.GetWidth(),ss.GetWidth(),tool.GetWidth(),tbar->GetToolsCount());
  padding->SetSize(x,wxDefaultCoord);

  //  Layout();
  event.Skip();
}

void MuniBrowser::OnIdle(wxIdleEvent& event)
{
  /*
  if( ! collector->IsOk() ) {
    collector->SetArchive(archive);
  }
  */
}

void MuniBrowser::OnUpdateFilemenu(wxUpdateUIEvent& event)
{
  bool enable = ! archive->IsReadOnly();
  event.Enable(enable);
}

void MuniBrowser::OnUpdateTbot(wxUpdateUIEvent& event)
{
  bool enable = ! archive->IsReadOnly();
  event.Enable(enable);
}

void MuniBrowser::OnUpdateCut(wxUpdateUIEvent& event)
{
  event.Enable(list->GetSelectedMeta().size() > 0);
}

void MuniBrowser::OnUpdatePaste(wxUpdateUIEvent& event)
{
  event.Enable(list->GetClipboard().size() > 0);
}

void MuniBrowser::OnUpdateActmenu(wxUpdateUIEvent& event)
{
  wxString cname = wxString(typeid(*list).name(),wxConvUTF8);

  event.Enable(true);

  //  wxLogDebug(cname+_(" %d %d"),event.GetId(),ID_MDARK);

  if( event.GetId()==ID_AVERAGE && cname.Find("MuniAverage")!=wxNOT_FOUND )
    event.Enable(false);

  else if( event.GetId() == ID_DARKBAT && cname.Find("MuniDarkbat") != wxNOT_FOUND )
    event.Enable(false);
}


void MuniBrowser::OnUpdateArchive(wxUpdateUIEvent& event)
{
  /*
  if( metarender ) {

    wxString t;
    t.Printf("Remaining %d files",(int) s_namelist.size());
    event.SetText(t);

  }
  */
  //  else if ( shell ) {
    // ??
  //    event.SetText("Files are being processed.");
  //  }
  /*
  else {

    size_t n = list->GetSelectedItemCount();
    wxString a;
    if( n > 0 )
      a.Printf("%d of %d selected",(int)n,(int)list->GetItemCount());
    else
      a.Printf("%d items",(int) list->GetItemCount());
    event.SetText(a);
  }
  */

  //  SetArchiveSize();
}

void MuniBrowser::SetArchiveSize()
{
  wxSize size(GetSize());
  wxSize margins(tbot->GetMargins());
  wxSize tool(tbot->GetToolSize());
  int n(tbot->GetToolsCount());

  int w = size.GetWidth() - 2*n*margins.GetWidth() -n*tool.GetWidth();
  archiveprop->SetSize(w,-1);
}



void MuniBrowser::FileOpen(wxCommandEvent& WXUNUSED(event))
{
  wxFileDialog select(this,"Choose a file",wxEmptyString,wxEmptyString,
		      "FITS files ("+config->dirmask+")|"+config->dirmask+
		      "|RAW files ("+config->rawmask+")|"+config->rawmask+
		      "|All files (*)|*",
		      wxFD_FILE_MUST_EXIST|wxFD_CHANGE_DIR|wxFD_MULTIPLE);

  if (select.ShowModal() == wxID_OK ) {

    wxArrayString files;
    select.GetPaths(files);

    if( select.GetFilterIndex() == 1 ) {
      // RAW files

      MuniImportRawOptions opt(this,config);
      if( opt.ShowModal() == wxID_OK ) {
	MuniImportRaw *iraw = new MuniImportRaw(this,opt,files);
	iraw->Show();
	//	ImportRaw(opt,files);
      }
    }
    else
      FilesLoad(files);
  }
}

// void MuniBrowser::ImportRaw(const MuniImportRawOptions& opt, const wxArrayString& files)
// {
//   MuniImportRaw *iraw = new MuniImportRaw(this,opt,files);
//   iraw->Show();
// }


void MuniBrowser::LoadMeta()
{
  archive->LoadMeta();
  archiveprop->SetLabel("Loading metafiles.... ");
  archiveprop->SetSize(100,-1);
  tbot->Realize();
  metaload = true;
}

void MuniBrowser::OnMetaLoad(MetaOpenEvent& event)
{
  //  wxLogDebug("MuniBrowser::OnMetaLoad %d: "+event.meta.GetName(),event.GetId()==ID_ARCHIVE_FINISH);

  archiveprop->SetLabel("Loaded: "+event.meta.GetName());

  /*
  if( event.GetId() != ID_ARCHIVE_FINISH ) {
    if( ! wxIsBusy() )
      wxBeginBusyCursor();
  }
  */
  if( event.GetId() == ID_ARCHIVE_FINISH ) {
    metaload = false;
    //    wxEndBusyCursor();
  }

  wxASSERT(list);
  list->AddMeta(event.meta);
}

void MuniBrowser::FileSave(wxCommandEvent& WXUNUSED(event))
{
  //  SetStatusText(_T("Save file is not implemenetd yet."));
}


void MuniBrowser::OnProperties(wxCommandEvent& event)
{
  MuniDirProperties *w = new MuniDirProperties(this,config,archive->GetMeta());
  w->Show();
}


void MuniBrowser::OnPreferences(wxCommandEvent& WXUNUSED(event))
{
  MuniPreferences *w = new MuniPreferences(this,config);
  w->Show();
}



void MuniBrowser::FileClose(wxCommandEvent& event)
{
  Close();
}

void MuniBrowser::OnSall(wxCommandEvent& WXUNUSED(event))
{
  list->SelectAll();
}

void MuniBrowser::OnCut(wxCommandEvent& event)
{
  list->Cut();
}

void MuniBrowser::OnCopy(wxCommandEvent& event)
{
  list->Copy();
}

void MuniBrowser::OnPaste(wxCommandEvent& event)
{
  list->Paste();
}

void MuniBrowser::OnZoomMax(wxCommandEvent& event)
{
  config->icon_zoom = 0;
  menuView->Enable(wxID_ZOOM_IN,false);
  menuView->Enable(wxID_ZOOM_OUT,true);
  list->Update();
}

void MuniBrowser::OnZoom(wxCommandEvent& event)
{
  if( event.GetId() == wxID_ZOOM_OUT && config->icon_zoom < 5 )
    config->icon_zoom++;

  if( event.GetId() == wxID_ZOOM_IN && config->icon_zoom > 0 )
    config->icon_zoom--;

  menuView->Enable(wxID_ZOOM_IN,config->icon_zoom != 0);
  menuView->Enable(wxID_ZOOM_OUT,config->icon_zoom != 5);

  list->Update();
}

void MuniBrowser::SelectItem(wxCommandEvent& event)
{
  int dir = 0;
  switch(event.GetId()){
  case wxID_BACKWARD: dir = -1; break;
  case wxID_FORWARD: dir = 1;   break;
  }

  list->SelectItemRelative(dir);
}

void MuniBrowser::NewBrowser(wxCommandEvent& WXUNUSED(event))
{
  MuniBrowser *newb = new MuniBrowser(this,config);
  newb->Show(true);
}

// void MuniBrowser::NewBrowser(wxCommandEvent& WXUNUSED(event))
// {
//   MuniBrowser *newb = new MuniBrowser(config,archive);
//   newb->Show(true);

// //   long selected_item = -1;
// //   while( (selected_item = list->GetNextSelectedItem(selected_item)) != -1 ) {
// //     //    FitsMeta *f;
// //     //    if( (f = GetFitsMeta(selected_item)) )
// //     //    newb->FileLoad(f->GetFullPath());
// //     wxASSERT(0 <= selected_item && selected_item < (long)flist.size());
// //     FitsMeta f(flist[selected_item]);
// //     newb->FileLoad(f.GetFullPath());
// //   }
// }


void MuniBrowser::NewView(wxCommandEvent& WXUNUSED(event))
{
  if( ! view ) {
    view = new MuniView(this,config);
    view->Show();
  }
}

void MuniBrowser::OnView(wxCommandEvent& WXUNUSED(event))
{

  wxListEvent e;
  OnActivated(e);
  //  wxPostEvent(this,e);

  /*
  if( ! view ) {
    view = new MuniView(this,config);
    view->Show();
  }
  vector<FitsMeta> fl = list->GetSelectedMeta();
  wxASSERT(! fl.empty());
  view->LoadMeta(fl[0]);
  */
}


// void MuniBrowser::NewView(wxCommandEvent& WXUNUSED(event))
// {
//   MuniView *w = new MuniView(config);
//   w->Show();

//   //  vector<MuniListItem> ls = list->GetSelectedItems();
//   vector<FitsMeta> ls = list->GetSelectedMeta();

//   //  for(vector<MuniListItem>::iterator i=ls.begin();i!=ls.end();++i){
//   for(vector<FitsMeta>::iterator i=ls.begin();i!=ls.end();++i){
//     w->LoadMeta(*i);
//   }
// }


void MuniBrowser::FindStars(wxCommandEvent& WXUNUSED(event))
{
  //  SetStatusText(wxT("FindStars is not implemenetd yet."));
}

void MuniBrowser::AperturePhot(wxCommandEvent& WXUNUSED(event))
{
  //  SetStatusText(wxT("AperturePhot is not implemenetd yet."));
}

void MuniBrowser::ProfilePhot(wxCommandEvent& WXUNUSED(event))
{
  //  SetStatusText(wxT("ProfilePhot is not implemenetd yet."));
}

void MuniBrowser::Matching(wxCommandEvent& WXUNUSED(event))
{
  //  SetStatusText(wxT("Matching is not implemenetd yet."));
}

void MuniBrowser::Astrometry(wxCommandEvent& WXUNUSED(event))
{
  //  SetStatusText(wxT("Astrometry is not implemenetd yet."));
  //  wxLogDebug("Selected files count: %d.",(int)list->GetSelectedMeta().size());
  MuniAstrometer ameter(this,config,list->GetSelectedMeta());
  ameter.ShowModal();
}

void MuniBrowser::Stacking(wxCommandEvent& WXUNUSED(event))
{
  //  SetStatusText(wxT("Stacking is not implemenetd yet."));
}

void MuniBrowser::Deconvolution(wxCommandEvent& WXUNUSED(event))
{
  //  SetStatusText(wxT("Deconvolution is not implemenetd yet."));
}

void MuniBrowser::OnDarkbat(wxCommandEvent& WXUNUSED(event))
{
  //  wxLogDebug("Running darkbat...");
  SwitchList(ID_DARKBAT);
}

void MuniBrowser::OnCancelAction(wxCommandEvent& event)
{
  ShowInspect(true);
}


void MuniBrowser::ShowInspect(bool enable)
{
  // enable or disable selected controls for inspecting control mode
  GetMenuBar()->Enable(enable);
  tbar->Enable(enable);
  collector->Enable(enable);
}

void MuniBrowser::OnList(wxCommandEvent& event)
{
  SwitchList(event.GetId());
  LoadMeta();
}

void MuniBrowser::OnAverage(wxCommandEvent& WXUNUSED(event))
{
  //  wxLogDebug("Preparing darks...");
  SwitchList(ID_AVERAGE);
}

void MuniBrowser::HelpAbout(wxCommandEvent& WXUNUSED(event))
{
  MuniAbout(config->munipack_icon);
}

void MuniBrowser::OnLabel(wxCommandEvent& event)
{
  list->Label(event.GetId());
}

void MuniBrowser::OnSort(wxCommandEvent& event)
{
  list->Sort(event.GetId());
}

void MuniBrowser::OnReverse(wxCommandEvent& event)
{
  list->Reverse(event.IsChecked());
}

void MuniBrowser::OnActivated(wxListEvent& event)
{
  if( ! view ) {
    view = new MuniView(this,config);
    view->Show();
  }
  vector<FitsMeta> fl = list->GetSelectedMeta();
  wxASSERT(! fl.empty());
  view->LoadMeta(fl[0]);
}

void MuniBrowser::OnIconList(wxCommandEvent& event)
{
  if( event.GetId() == wxID_VIEW_LARGEICONS ) {
    list->SetStyle(wxLC_ICON);
    config->browser_iconlist = wxLC_ICON;
    menuView->Enable(menuView->FindItem("Show Labels as"),true);
  }
  else if( event.GetId() == wxID_VIEW_LIST ) {
    list->SetStyle(wxLC_REPORT);
    config->browser_iconlist = wxLC_REPORT;
    menuView->Enable(menuView->FindItem("Show Labels as"),false);
  }
}

void MuniBrowser::OnSelChanged(wxTreeEvent& event)
{
  //  wxBusyCursor wait;

  // flush archive
  if( list->GetId() == ID_LIST )
    //?
    archive->FlushMeta(list->GetAddedMeta(),list->GetDeletedMeta());

  if( event.GetString() == "Average" ) {
    //? menu ?
    wxQueueEvent(this,new wxCommandEvent(wxEVT_COMMAND_MENU_SELECTED,ID_AVERAGE));
  }
  else if( event.GetString() == "Correction" ) {
    // ? menu ?
    wxQueueEvent(this,new wxCommandEvent(wxEVT_COMMAND_MENU_SELECTED,ID_DARKBAT));
  }
  else {
    SwitchList(0);
    LoadMeta();
  }

  SetTitle(event.GetString());
}


void MuniBrowser::FilesLoad(const wxArrayString& files)
{
  list->AddFits(files);
}


void MuniBrowser::OnShowToolbar(wxCommandEvent& event)
{
  tbar->Show(event.IsChecked());
  Layout();
}


void MuniBrowser::OnShowCollector(wxCommandEvent& event)
{
  menuView->Check(ID_COLLECTOR,event.IsChecked());

  if( event.IsChecked() )
    splitter->SplitVertically(collector,list,config->browser_sash);
  else {
    config->browser_sash = splitter->GetSashPosition();
    splitter->Unsplit(collector);
  }
}

void MuniBrowser::OnNewArchive(wxCommandEvent& event)
{
  wxQueueEvent(collector,event.Clone());
}

void MuniBrowser::OnExcludeArchive(wxCommandEvent& event)
{
  wxQueueEvent(collector,event.Clone());
}


void MuniBrowser::OnConfigUpdated(wxCommandEvent& event)
{
  if( view )
    wxQueueEvent(view,event.Clone());
}


void MuniBrowser::OnSearch(wxCommandEvent& event)
{
  // do search
  vector<long> l = search->Find(list->GetAllMeta());
  for(size_t i = 0; i < l.size(); i++)
    list->SelectItem(l[i]);
}


void MuniBrowser::OnSearchFinish(wxCommandEvent& event)
{
  // deslect all
  list->DeSelectAll();
}



void MuniBrowser::SwitchList(int type)
{
  wxWindowUpdateLocker noUpdates(splitter);

  wxWindow *w = splitter->IsSplit() ? splitter->GetWindow2() : splitter->GetWindow1();
  wxASSERT(w);

  long style = config->browser_iconlist;

  wxWindow *wlist = list;
  switch(type) {

  case ID_AVERAGE:
    list = new MuniAverage(splitter,ID_AVERAGE,style,config);
    //list->SetMeta(wlist->GetSelectedMeta());
    break;

  case ID_DARKBAT:
    list = new MuniDarkbat(splitter,ID_DARKBAT,style,config);
    //    list->SetMeta(wlist->GetSelectedMeta());
    break;

  default:
    list = new MuniListWindow(splitter,ID_LIST,style,config);
    break;
  }

  splitter->ReplaceWindow(wlist,list);
  wlist->Destroy();

  Layout();
}
