#include "wxinc.h"

#include "xvt.h"
#include "xvtwin.h"

#include <wx/artprov.h>
#include <wx/calctrl.h>
#include <wx/clipbrd.h>
#include <wx/colordlg.h>
#include <wx/fontdlg.h>
#include <wx/wxhtml.h>
#include <wx/statline.h>
#include <wx/tokenzr.h>

#ifdef __WXMSW__
#include "oswin32.h"
#endif

///////////////////////////////////////////////////////////
// TwxHtmlWindow
///////////////////////////////////////////////////////////

class TwxHtmlWindow : public wxHtmlWindow
{
protected:
  virtual void OnLinkClicked(const wxHtmlLinkInfo& link);
};

void TwxHtmlWindow::OnLinkClicked(const wxHtmlLinkInfo& link)
{
  const wxString href = link.GetHref();
  if (href.StartsWith("mailto:"))
    xvt_mail_send(href.AfterFirst(':'), NULL, NULL, _GetAppTitle(), ToText(), NULL, 1);
  else
    wxHtmlWindow::OnLinkClicked(link);
}

///////////////////////////////////////////////////////////
// TMessageBox
///////////////////////////////////////////////////////////

class TMessageBox : public wxDialog
{
  wxTimer m_timer;

protected:
  void OnButton(wxCommandEvent& evt);
  void OnTimeout(wxTimerEvent& evt);
  void AddButton(wxSizer* sz, wxWindowID id);
  DECLARE_EVENT_TABLE()

  wxString GetMessage() const;

public:
  TMessageBox(wxWindow* pParent, const wxString& msg, int nStyle, int nTimeout = 0);
};

BEGIN_EVENT_TABLE(TMessageBox, wxDialog)
  EVT_BUTTON(wxID_ANY, TMessageBox::OnButton)
  EVT_TIMER(wxID_ANY, TMessageBox::OnTimeout)
END_EVENT_TABLE()

wxString TMessageBox::GetMessage() const
{
  wxString str;
  const wxWindow* txt = FindWindowById(wxID_EDIT, this);
  if (txt != NULL)
  {
    wxHtmlWindow* html = wxDynamicCast(txt, wxHtmlWindow);
    if (html != NULL)
      str = html->ToText();
    else
      str = txt->GetLabel();
  }
  return str;
}

void TMessageBox::OnButton(wxCommandEvent& evt)
{
  int ec = wxCANCEL;
  switch (evt.GetId())
  {
  case wxID_YES: ec = wxYES; break;
  case wxID_OK : ec = wxOK; break;
  case wxID_NO : ec = wxNO; break;
  case wxID_COPY:
    wxTheClipboard->Open();
    wxTheClipboard->SetData(new wxTextDataObject(GetMessage()));
    wxTheClipboard->Close();
    return; // DO NOT EXIT
  case wxID_SAVEAS:
    xvt_mail_send("hotline@sirio-is.it", NULL, NULL, _GetAppTitle(), GetMessage(), NULL, 1);
    return; // DO NOT EXIT
  default: ec = GetEscapeId(); break;
  }
  EndModal(ec);
}

void TMessageBox::OnTimeout(wxTimerEvent& WXUNUSED(evt))
{
  wxWindowID id = GetEscapeId();
  if (id <= 0)
    id = GetAffirmativeId();
  if (id > 0)
  {
    wxCommandEvent cmd(wxEVT_COMMAND_BUTTON_CLICKED, id);
    AddPendingEvent(cmd);
  }
  else
    EndModal(wxCANCEL);
}

void TMessageBox::AddButton(wxSizer* sz, wxWindowID id)
{
  wxString strPrompt;
  switch (id)
  {
  case 0x20: strPrompt = _("Si Tutti"); break;
  case 0x40: strPrompt = _("No Tutti"); break;
  default  : break;
  }
  wxButton* btn = new wxButton(this, id, strPrompt, wxDefaultPosition, wxSize(64,-1));
  sz->Add(btn, 0, wxALL|wxALIGN_CENTER_VERTICAL, 2);
}

TMessageBox::TMessageBox(wxWindow* pParent, const wxString& msg, int nStyle, int nTimeout)
           : wxDialog(pParent, wxID_ANY, _GetAppTitle(), wxDefaultPosition, wxDefaultSize,
                      wxCAPTION | wxRAISED_BORDER | wxSTAY_ON_TOP), m_timer(this)
{
  TTaskWin* tw = wxDynamicCast(pParent ? pParent : _task_win, TTaskWin);
  if (tw != NULL)
  {
    const COLOR col = tw->GetCtlColor(XVT_COLOR_BACKGROUND);
    if (col != COLOR_INVALID)
    {
      CAST_COLOR(col, rgb);
      SetOwnBackgroundColour(rgb);
    }
  }

  wxBoxSizer* pMainSizer = new wxBoxSizer(wxVERTICAL);
  
  wxBoxSizer* pTopSizer = new wxBoxSizer(wxHORIZONTAL);
  pMainSizer->Add(pTopSizer);

  wxArtID nIco = wxART_INFORMATION;
  if (nStyle & wxICON_HAND)        nIco = wxART_ERROR;       else
  if (nStyle & wxICON_INFORMATION) nIco = wxART_INFORMATION; else
  if (nStyle & wxICON_EXCLAMATION) nIco = wxART_WARNING;     else
  if (nStyle & wxICON_QUESTION)    nIco = wxART_QUESTION;    else
  if (nStyle & 0x1000)             nIco = "220";

  const BOOLEAN bTerminalino = xvt_sys_is_pda();
  const int nBorder = bTerminalino ?  2 :  4;
  const int nIcon   = bTerminalino ? 32 : 64;
  const int nWrap   = bTerminalino ?160 :400;

  const wxBitmap img = wxArtProvider::GetBitmap(nIco, wxART_MESSAGE_BOX, wxSize(nIcon,nIcon)); 

  pTopSizer->Add(new wxStaticBitmap(this, wxID_ANY, img), 0, wxALL|wxALIGN_CENTER, nBorder);
  
  if (msg.StartsWith("<html>") && msg.EndsWith("</html>"))
  {
    TwxHtmlWindow* html = new TwxHtmlWindow;
    html->Create(this, wxID_EDIT, wxDefaultPosition, wxSize(nWrap,nWrap/1.6180339887));
    html->SetPage(msg);
    pTopSizer->Add(html, 0, wxALL|wxALIGN_CENTER|wxALIGN_CENTER_VERTICAL, nBorder);
  }
  else
  {
    wxStaticText* ss = NULL;
    if (bTerminalino)
    {
      int nLines = 0;
      wxStringTokenizer tok(msg, wxT("\n"));
      for (nLines = 0; tok.HasMoreTokens(); nLines++)
        nLines += tok.GetNextToken().Len()/32;
      ss = new wxStaticText(this, wxID_EDIT, wxEmptyString, wxDefaultPosition, 
                            wxSize(nWrap, 16*nLines), wxST_NO_AUTORESIZE);
    }
    else
      ss = new wxStaticText(this, wxID_EDIT, wxEmptyString);
  
    ss->Wrap(nWrap);
    ss->SetLabel(msg);
    pTopSizer->Add(ss, 0, wxALL|wxALIGN_CENTER|wxALIGN_CENTER_VERTICAL, nBorder);
  }
  
  pMainSizer->Add(new wxStaticLine(this), wxID_STATIC, wxALL|wxEXPAND, nBorder);

  wxFlexGridSizer* pBottomSizer = new wxFlexGridSizer(0, 2, 0, 0);
  pBottomSizer->AddGrowableCol(1);
  pMainSizer->Add(pBottomSizer, 0, wxGROW|wxALL, nBorder);

  wxBoxSizer* pSmallSizer = new wxBoxSizer(wxHORIZONTAL);
  pBottomSizer->Add(pSmallSizer, 0, wxALIGN_TOP|wxALL, 0);

  wxBoxSizer* pButtonSizer = new wxBoxSizer(wxHORIZONTAL);
  pBottomSizer->Add(pButtonSizer, 0, wxALIGN_RIGHT|wxALL, 0);

  if (nStyle & wxYES_NO)
  {
    if (nStyle & 0x60) // Yes,No,*All
    {
      if (nStyle & 0x20) // No, Yes, Yes All
      {
        SetAffirmativeId(wxID_YES);
        SetEscapeId(wxID_NO);
        AddButton(pButtonSizer, wxID_NO);
        AddButton(pButtonSizer, wxID_YES);
        AddButton(pButtonSizer, 0x20);
      }
      else // Yes, No, No All
      {
        SetAffirmativeId(wxID_NO);
        SetEscapeId(wxID_YES);
        AddButton(pButtonSizer, wxID_YES);
        AddButton(pButtonSizer, wxID_NO);
        AddButton(pButtonSizer, 0x40);
      }
    }
    else
    {
      if (nStyle & wxNO_DEFAULT)
      {
        SetAffirmativeId(wxID_NO);
        SetEscapeId(wxID_YES);
        AddButton(pButtonSizer, wxID_NO);
        AddButton(pButtonSizer, wxID_YES);
      }
      else
      {
        SetAffirmativeId(wxID_YES);
        SetEscapeId(wxID_NO);
        AddButton(pButtonSizer, wxID_YES);
        AddButton(pButtonSizer, wxID_NO);
      }
    }
  }
  if (nStyle & wxOK)
  {
    SetAffirmativeId(wxID_OK);
    AddButton(pButtonSizer, wxID_OK);
  }
  if (nStyle & wxCANCEL)
  {
    SetEscapeId(wxID_CANCEL);
    AddButton(pButtonSizer, wxID_CANCEL);
  }

  if (!bTerminalino)
  {
    const int nAssYear = xvt_vobj_get_attr(NULL_WIN, ATTR_APPL_VERSION_YEAR);
    if (nAssYear >= 2121)
    {
      const wxBitmap bmpCopy = wxArtProvider::GetBitmap(wxART_COPY, wxART_BUTTON);
      wxBitmapButton* btnCopy = new wxBitmapButton(this, wxID_COPY, bmpCopy);
      pSmallSizer->Add(btnCopy, 0, wxALIGN_TOP);
      /*
      if (xvt_mail_installed())
      {
        const wxBitmap bmpMail = wxArtProvider::GetBitmap("139", wxART_BUTTON, wxSize(bmpCopy.GetWidth(), bmpCopy.GetHeight()));
        wxBitmapButton* btnMail = new wxBitmapButton(this, wxID_SAVEAS, bmpMail);
        pSmallSizer->Add(btnMail, 0, wxALIGN_TOP);
      }
      */
    }
  }


  SetSizerAndFit(pMainSizer);
  CentreOnParent();
  
  if (nTimeout > 0)
    m_timer.Start(1000*nTimeout, true);
}

///////////////////////////////////////////////////////////
// _*Box
///////////////////////////////////////////////////////////

int _MessageBox(const wxString& msg, int nStyle, int nTimeout = 0)
{
  xvt_dm_post_speech(msg, 1, TRUE);

  xvt_sys_beep((nStyle & wxICON_ERROR) ? 2 : (nStyle & wxICON_WARNING) ? 1 : 0);

  TMessageBox dlg(NULL, msg, nStyle, nTimeout);
  const int ret = dlg.ShowModal(); 

  switch(ret)
  {
  case wxOK : xvt_dm_post_speech(_("ok"),      7, TRUE); break;
  case wxYES: xvt_dm_post_speech(_("si"),      7, TRUE); break;
  case wxNO : xvt_dm_post_speech(_("no"),      7, TRUE); break;
  default   : xvt_dm_post_speech(_("annulla"), 7, TRUE); break;
  }
  return ret;
}

///////////////////////////////////////////////////////////
// _PopUpBox
///////////////////////////////////////////////////////////

class TPopUpBox : public wxDialog
{
  DECLARE_EVENT_TABLE();
  wxTimer m_Timer;
  int m_nStep, m_nTimeout;

protected:
  void OnTimer(wxTimerEvent& evt);
  void OnChar(wxKeyEvent& evt);
  void OnClick(wxMouseEvent& evt);

public:
  TPopUpBox(wxWindow* pParent, const wxString& msg, int nStyle, int nTimeout);
};

BEGIN_EVENT_TABLE(TPopUpBox, wxDialog)
  EVT_TIMER(wxID_ANY, TPopUpBox::OnTimer)
  EVT_CHAR(TPopUpBox::OnChar)
  EVT_LEFT_DOWN(TPopUpBox::OnClick)
END_EVENT_TABLE()

void TPopUpBox::OnChar(wxKeyEvent& WXUNUSED(evt))
{
  if (IsShown())
  {
    m_Timer.Stop();
    EndModal(wxID_CANCEL);
  }
}

void TPopUpBox::OnClick(wxMouseEvent& WXUNUSED(evt))
{
  if (IsShown())
  {
    m_Timer.Stop();
    EndModal(wxID_CANCEL);
  }
}

void TPopUpBox::OnTimer(wxTimerEvent& WXUNUSED(evt))
{
  if (IsShown())
  {
    const wxRect rctMain = GetParent()->GetRect();
    const wxRect rctMine = GetRect();
    const int msec = (m_nStep++)*m_Timer.GetInterval();
    if (msec <= m_nTimeout/4)
    {
      const double perc = double(msec)/(m_nTimeout/4);
      Move(rctMain.x, rctMain.GetBottom() - rctMine.height * perc);
    }
    if (msec >= 3*m_nTimeout/4 && msec <= m_nTimeout)
    {
      const double perc = double(m_nTimeout-msec)/(m_nTimeout/4);
      Move(rctMain.x, rctMain.GetBottom() - rctMine.height * perc);
    }
    if (msec > m_nTimeout)
    {
      m_Timer.Stop();
      EndModal(wxID_CANCEL);
    }
  }
}

TPopUpBox::TPopUpBox(wxWindow* pParent, const wxString& msg, int nStyle, int nTimeout) 
         : wxDialog(pParent, wxID_ANY, wxEmptyString, wxPoint(0,2024), wxDefaultSize, wxBORDER_SIMPLE), 
           m_nTimeout(nTimeout*1000), m_Timer(this), m_nStep(0)
{
  TTaskWin* tw = wxDynamicCast(pParent ? pParent : _task_win, TTaskWin);
  if (tw != NULL)
  {
    const COLOR col = tw->GetCtlColor(XVT_COLOR_BACKGROUND);
    if (col != COLOR_INVALID)
    {
      CAST_COLOR(col, rgb);
      SetOwnBackgroundColour(rgb);
    }
  }

  wxBoxSizer* sz = new wxBoxSizer(wxHORIZONTAL);

  wxArtID nIco = wxART_ERROR;
  if (nStyle & wxICON_HAND)        nIco = wxART_ERROR;       else
  if (nStyle & wxICON_INFORMATION) nIco = wxART_INFORMATION; else
  if (nStyle & wxICON_EXCLAMATION) nIco = wxART_WARNING;     else
  if (nStyle & 0x1000)             nIco = "220";
  const wxBitmap img = wxArtProvider::GetBitmap(nIco, wxART_MESSAGE_BOX);

  wxStaticBitmap* bmp = new wxStaticBitmap(this, wxID_ANY, img);
  sz->Add(bmp, 0, wxALL, 8);
  
  wxStaticText* ss = new wxStaticText(this, wxID_ANY, wxEmptyString);
  ss->Wrap(160);
  ss->SetLabel(msg);
  sz->Add(ss, 0, wxALL | wxALIGN_CENTER | wxALIGN_CENTER_VERTICAL, 8);
  
  SetSizerAndFit(sz);
  m_Timer.Start(25);
}

static void _PopUpBox(const wxString& msg, int nStyle, int nTimeout = 4)
{
  wxWindow* pFrame = wxTheApp->GetTopWindow();
  bool bCanPopUp = pFrame != NULL && xvt_sys_get_oem_int("OEM", -1) == 0;
#ifdef __WXMSW__
  if (bCanPopUp)
    bCanPopUp = !OsWin32_IsWindowsServer(); // Animazioni non consigliabili in TS
#endif

  if (bCanPopUp)
  {
    xvt_sys_beep(nStyle & wxICON_ERROR ? 2 : 1);
    TPopUpBox dlg(pFrame, msg, nStyle, nTimeout <= 0 ? 4 : nTimeout);
    dlg.ShowModal();
  }
  else
    _MessageBox(msg, nStyle|wxOK, nTimeout);
}

WX_DECLARE_STRING_HASH_MAP(int, TMessagesMap);

void xvt_sys_sorry_box(const char* func, const char* file, int line)
{
#ifndef NDEBUG
  static TMessagesMap sorry;
	if (sorry[func]++ == 0)
	{
		wxString strMessage;
    strMessage.Printf("Function %s in file %s at line %d\nis not implemented yet: be patient...", 
                      func, file, line);
    _PopUpBox(strMessage, 0x1000); // Smiley Icon
	}
#endif
}

void xvt_sys_deprecated_box(const char* oldfunc, const char* file, const char* newfunc)
{
#ifndef NDEBUG
  static TMessagesMap deprecated;
	if (deprecated[oldfunc]++ == 0)
	{
    wxString strMessage;
    strMessage.Printf("Function %s in file %s is deprecated:\n%s is much more trendy now!\nYou can blame Guy for this, if you're bold enough!", 
                      oldfunc, file, newfunc);
    _PopUpBox(strMessage, 0x1000);
	}
#endif
}

///////////////////////////////////////////////////////////
// Speech support
///////////////////////////////////////////////////////////

// 0   Errors
// 1   Warnings
// 2   Messages
// 3   Requests
// 7   Buttons 
static int m_nSpeechMode = 0;

void xvt_dm_speech_enable(int mode)
{
#ifdef SPEECH_API
  m_nSpeechMode = mode;
  if (m_nSpeechMode != 0)
  {
    if (!OsWin32_InitializeSpeech())
      m_nSpeechMode = 0;
  }
  else
  {
    OsWin32_DeinitializeSpeech();
  }
#endif
}

int xvt_dm_speech_enabled(void)
{ return m_nSpeechMode; }

///////////////////////////////////////////////////////////
// Common dialogs
///////////////////////////////////////////////////////////

void xvt_dm_post_about_box()
{
  const char* ver = (const char*)xvt_vobj_get_attr(NULL_WIN, ATTR_APPL_VERSION_STRING);
  if (ver == NULL || !*ver) ver = "2012 11.0/200";
  wxString msg; msg << "Versione " << ver;
  xvt_dm_post_message(msg);
}

COLOR xvt_dm_post_choose_color(WINDOW win, COLOR xc)
{
  DEPRECATED_BOX("xvt_dm_post_color_sel");
  if (!xvt_dm_post_color_sel(&xc, win))
    xc = COLOR_INVALID;
  return xc;
}

BOOLEAN  xvt_dm_post_color_sel(COLOR* color, unsigned long reserved)
{
  CAST_COLOR(*color, wc);

  wxColourData cd;
  cd.SetChooseFull(true);
  cd.SetColour(wc);
  for (int i = 0; i < 16; i++)
  {
    const unsigned char val   = (i & 0x8) ? 255 : 127;
    const unsigned char red   = (i & 0x1) ? val : 0;
    const unsigned char green = (i & 0x2) ? val : 0;
    const unsigned char blue  = (i & 0x4) ? val : 0;
    wxColour col(red, green, blue);
    cd.SetCustomColour(i, col);
  }

  wxWindow* win = wxDynamicCast ((void*)reserved, wxWindow);
  wxColourDialog dialog(win, &cd);
  if (dialog.ShowModal() == wxID_OK)
  {
    *color = MAKE_XVT_COLOR(dialog.GetColourData().GetColour());
    if (*color == 0) *color = COLOR_BLACK; // 0x000000 confonde XI, mentre con 0x07000000 e' a suo agio
    return TRUE;
  }

  return FALSE;
}

class TwxCalendarDlg : public wxDialog
{
  enum { ID_CAL = 1883 };
  wxDateTime& m_date;
  wxCalendarCtrl* m_cal;

protected:
  virtual bool TransferDataFromWindow();
  void OnCalendar(wxCalendarEvent& e);

public:
  TwxCalendarDlg(wxWindow* parent, wxDateTime& date);

  DECLARE_EVENT_TABLE()
};

BEGIN_EVENT_TABLE(TwxCalendarDlg, wxDialog)
  EVT_CALENDAR(wxID_ANY, TwxCalendarDlg::OnCalendar)
END_EVENT_TABLE()

void TwxCalendarDlg::OnCalendar(wxCalendarEvent& WXUNUSED(e))
{
  wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, wxID_OK);
  AddPendingEvent(evt);
}

bool TwxCalendarDlg::TransferDataFromWindow()
{
  bool ok = wxDialog::TransferDataFromWindow();
  if (ok)
    m_date = m_cal->GetDate();
  return ok;
}

TwxCalendarDlg::TwxCalendarDlg(wxWindow* parent, wxDateTime& date) 
              : wxDialog(parent, wxID_ANY, "Data", wxDefaultPosition, wxDefaultSize, wxRAISED_BORDER), m_date(date)
{

  m_cal = new wxCalendarCtrl(this, ID_CAL, m_date, wxDefaultPosition, wxDefaultSize,
                             wxCAL_MONDAY_FIRST | wxCAL_SHOW_HOLIDAYS | wxCAL_SHOW_SURROUNDING_WEEKS);

  wxButton* button = new wxButton(this, wxID_OK, "OK");

  wxGridSizer* sizer = new  wxFlexGridSizer(2, 1, 8, 8);
  sizer->Add(m_cal, 0, wxALIGN_CENTER);
  sizer->Add(button, 0, wxALIGN_CENTER);
  SetSizer(sizer);
  sizer->SetSizeHints(this);
}

unsigned int xvt_dm_post_choose_date(WINDOW win, const RCT* rct, unsigned int ansidate)
{
  int d = ansidate%100;
  int m = (ansidate/100)%100;
  int y = ansidate / 10000;

  wxDateTime date;
  if (d >= 1 && d <= 31 && m >= 1 && m <= 12 && y > 1900)
    date.Set(d, wxDateTime::Month(m-1), y);
  else
    date = wxDateTime::Today();
  
  CAST_WIN(win, w);
  wxDialog* dlg = new TwxCalendarDlg(&w, date);

  if (rct != NULL)
  {
    const wxRect client = w.GetClientRect();
    const wxRect rect = dlg->GetRect();
    wxPoint pos(rct->right - rect.width, rct->bottom);
    if (pos.x < 0)
      pos.x = rct->left;
    if (rct->bottom + rect.height > client.GetBottom())
      pos.y = rct->top - rect.height;
    dlg->Move(w.ClientToScreen(pos));
  }

  if (dlg->ShowModal() == wxID_OK)
  {
    d = date.GetDay();
    m = date.GetMonth()+1;
    y = date.GetYear();
    ansidate = y*10000 + m*100 + d;
  }
  dlg->Destroy();
  
  return ansidate;
}

BOOLEAN xvt_dm_post_speech(const char* text, int priority, BOOLEAN async)
{
  BOOLEAN ok = FALSE;
#ifdef SPEECH_API
  if ((m_nSpeechMode & (1 << priority)) != 0)
    ok = OsWin32_Speak(text, async != 0);
#endif
  return ok;
}

ASK_RESPONSE xvt_dm_post_ask(const char* Btn1, const char* WXUNUSED(Btn2), const char* Btn3, const char* fmt)
{
  int nFlags = wxICON_QUESTION | wxYES_NO;
  if (wxStricmp(Btn1, "no") == 0)
    nFlags |= wxNO_DEFAULT;
  if (Btn3 != NULL) //il Btn3 � presente sulla maschera (es. noyesall_box, yesnocancel_box)
  {
    if (wxStricmp(Btn3, "Si Tutti") == 0)
      nFlags |= 0x20; else
    if (wxStricmp(Btn3, "No Tutti") == 0)
      nFlags |= 0x40; 
    else
      nFlags |= wxCANCEL;
  }

  const int answer = _MessageBox(fmt, nFlags);
  return answer == wxYES ? RESP_DEFAULT : (answer == wxNO ? RESP_2 : RESP_3);
}

void xvt_dm_post_error(const char *fmt)
{
  _MessageBox(fmt, wxOK | wxICON_HAND);
}

void xvt_dm_post_fatal_exit(const char *fmt)
{
  _MessageBox(fmt, wxOK | wxICON_HAND, 10);
  abort();
}

static wxString MakeFileName(const wxChar* name, const wxChar* ext)
{
  wxString f = name;
  if (ext && *ext)
  {
    if (*ext != '.')
      f += '.';
    f += ext;
  }
  return f;
}

static FL_STATUS xvt_dm_post_file_ask(FILE_SPEC *fsp, const char *msg, int flags)
{
  DIRECTORY savedir; xvt_fsys_get_dir(&savedir); // Salvo cartella corrente

	wxString path = fsp->dir.path;
	wxString name = MakeFileName(fsp->name, fsp->type);
	wxString extension = fsp->type;
  wxString wild;
  if (!extension.IsEmpty() &&  extension != "*")
     wild << _("File ") << extension << " (*." << extension << ")|*." << extension << "|";
  if (flags & wxFD_OPEN)
    wild << _("Tutti i file (*.*)|*.*|");
  wild << '|';

  wxString selectedname = wxFileSelector(msg, path, name, extension , wild, flags);
  if (selectedname.IsEmpty())
  	return FL_CANCEL;
  xvt_fsys_convert_str_to_fspec(selectedname, fsp);

  xvt_fsys_set_dir(&savedir); // Ripristino cartella corrente

  return FL_OK;
}

FL_STATUS xvt_dm_post_file_open(FILE_SPEC *fsp, const char *msg)
{
  const int flags = wxFD_OPEN | wxFD_FILE_MUST_EXIST;
  return xvt_dm_post_file_ask(fsp, msg, flags);
}

FL_STATUS xvt_dm_post_file_save(FILE_SPEC *fsp, const char *msg)
{
  const int flags = wxFD_SAVE | wxFD_OVERWRITE_PROMPT;
  return xvt_dm_post_file_ask(fsp, msg, flags);
}

FL_STATUS xvt_dm_post_dir_sel(DIRECTORY *dir)
{
  wxDirDialog dlg(_task_win);
	dlg.SetPath(dir->path);
	if (dlg.ShowModal() == wxID_OK)
	{
		xvt_fsys_convert_str_to_dir(dlg.GetPath(), dir);
		return FL_OK;
	}
	return FL_CANCEL;
}

BOOLEAN xvt_dm_post_font_sel(WINDOW win, XVT_FNTID font_id, PRINT_RCD* WXUNUSED(precp), unsigned long reserved)
{
	CAST_FONT(font_id, font);
	wxFontData data;
	data.SetInitialFont(font.Font(NULL, win));
	data.EnableEffects(reserved != 0);
  wxFontDialog dlg(_task_win, data);
	BOOLEAN ok = dlg.ShowModal() == wxID_OK;
  if (ok)
	{
    font.Copy(dlg.GetFontData().GetChosenFont());
    if (win == (WINDOW)_task_win)
    {
      EVENT e; memset(&e, 0, sizeof(EVENT));
	    e.type = E_FONT;
		  e.v.font.font_id = font_id;
	    _task_win_handler(win, &e);
    }
	}
	return ok;
}

void xvt_dm_post_message(const char *fmt)
{
  _MessageBox(fmt, wxOK | wxICON_INFORMATION);
}

void xvt_dm_post_note(const char *fmt)
{
  _PopUpBox(fmt, wxICON_INFORMATION);
}

char* xvt_dm_post_string_prompt(const char* message, char* response, int response_len)
{
	if (message && response && response_len > 0)
  {
    wxTextEntryDialog dlg(NULL, message, _GetAppTitle(), response);
    if (dlg.ShowModal() == wxID_OK)
    {
      wxStrncpy(response, dlg.GetValue(), response_len);
      response[response_len-1] = '\0';
    }
    else
	    *response = '\0';
  }
	return response;
}

void xvt_dm_post_warning(const char *fmt)
{
  _MessageBox(fmt, wxOK|wxICON_EXCLAMATION);
}

void xvt_dm_popup_error(const char *fmt)
{
  _PopUpBox(fmt, wxICON_HAND);
}

void xvt_dm_popup_message(const char *fmt)
{
  _PopUpBox(fmt, wxICON_INFORMATION);
}

void xvt_dm_popup_warning(const char *fmt)
{
  _PopUpBox(fmt, wxICON_EXCLAMATION);
}

///////////////////////////////////////////////////////////
// Help system
///////////////////////////////////////////////////////////

#ifdef __WXMSW__
#include "OsWin32.h"
#endif

struct XVAGA_HELP_INFO
{
	wxString m_strFilename;
	bool m_hlp;
} help_info;

XVT_HELP_INFO xvt_help_open_helpfile(FILE_SPEC* WXUNUSED(fs), unsigned long WXUNUSED(flags))
{
	return (XVT_HELP_INFO)&help_info;
}

void xvt_help_close_helpfile(XVT_HELP_INFO hi)
{
  if (hi == NULL_HELP_INFO)
		hi = (XVT_HELP_INFO)&help_info;
}

BOOLEAN xvt_help_process_event(XVT_HELP_INFO WXUNUSED(hi), WINDOW win, EVENT *ev)
{
  BOOLEAN bProcessed = FALSE;

#ifdef __WXMSW__
	WXHWND hwnd = (WXHWND)xvt_vobj_get_attr(win, ATTR_NATIVE_WINDOW);
	switch (ev->type)
	{
	case E_COMMAND:
		bProcessed = OsWin32_Help(hwnd, "", ev->v.cmd.tag, NULL);
		break;
	case E_HELP:
		bProcessed = OsWin32_Help(hwnd, "", M_HELP_ONCONTEXT, (const char*)ev->v.help.tid);
		break;
  default:
		break;
	}
#endif // WIN32

	return bProcessed;
}