#include "wxinc.h"
#include "gtArt.h"
#include "gtDialog.h"

#include <wx/aui/aui.h>
#include <wx/datectrl.h>
#include <wx/dateevt.h>
#include <wx/dir.h>
#include <wx/filename.h>
#include <wx/taskbar.h>

///////////////////////////////////////////////////////////
// gt*Box
///////////////////////////////////////////////////////////

#define APPFULLNAME wxAppConsole::GetInstance()->GetAppName()

bool gtMessage(const wxString str)
{
  wxMessageBox(str, APPFULLNAME, wxOK | wxCENTRE | wxICON_INFORMATION);
  return false;
}

bool gtWarning(const wxString str)
{
  wxMessageBox(str, APPFULLNAME, wxOK | wxCENTRE | wxICON_EXCLAMATION);
  return false;
}

bool gtError(const wxString str)
{
  wxMessageBox(str, APPFULLNAME, wxOK | wxCENTRE | wxICON_ERROR);
  return false;
}

bool gtAsk(const wxString str)
{
  const int a = wxMessageBox(str, APPFULLNAME, wxYES_NO | wxCENTRE | wxICON_QUESTION);
  return a == wxYES;
}

bool TryToUpdateFile(const wxString& strFile)
{
  while (wxFileName::FileExists(strFile) && !wxFileName::IsFileWritable(strFile))
  {
    wxLogWarning("Can't update %s", (const char*)strFile);
    wxString msg = "Impossibile aggiornare il file " + strFile; 
    msg += "\nProbabilmente il file � in uso esclusivo da parte di ";
    if (strFile.Find(".xls") > 0 || strFile.Find(".doc") > 0)
      msg += "Office"; else
    if (strFile.Find(".dwg") > 0 || strFile.Find(".dxf") > 0)
      msg += "Autocad";
    else
      msg += "un'altra applicazione";
    msg += ".\nSi desidera ritentare dopo averlo chiuso?";
    if (!gtAsk(msg))
      return false;
  }
  return true;
}

bool TryToRemoveFile(wxString& strFile)
{
  wxFileName fn(strFile);
  bool ok = true;
  while (fn.FileExists())
  {
    ok = TryToUpdateFile(strFile);
    if (ok)
      ::wxRemoveFile(strFile);
    else
    {
      strFile = wxFileSelector("Selezionare un nome alternativo", fn.GetPath(), fn.GetName()+"SAV."+fn.GetExt(), fn.GetExt(), 
                               wxFileSelectorDefaultWildcardStr, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
      ok = !strFile.IsEmpty(); 
      if (!ok)
        break;
      fn = strFile;
    }
  }
  return ok;
}


///////////////////////////////////////////////////////////
// gtNumberCtrl
///////////////////////////////////////////////////////////

class gtRealValidator : public wxTextValidator
{
protected:
  virtual wxValidator* Clone() const { return new gtRealValidator; }
public:
  gtRealValidator();
};

gtRealValidator::gtRealValidator()
               : wxTextValidator(wxFILTER_INCLUDE_CHAR_LIST)
{ 
  const wxChar* inc = wxT("0123456789e+-.,");
  wxArrayString a;
  for (const wxChar* i = inc; *i; i++)
    a.Add(wxString(*i));
  SetIncludes(a); 
}

class gtNumberCtrl : public wxTextCtrl
{
protected:
  gtNumberCtrl(wxWindow* parent, const wxString& id, wxSize sz, long flags, const wxTextValidator& val);

public:
  virtual wxString GetValue() const;
  gtNumberCtrl(wxWindow* parent, const wxString& id, wxSize sz = wxSize(64, -1), long flags = wxTE_RIGHT);
};

wxString gtNumberCtrl::GetValue() const
{
  wxString str = wxTextCtrl::GetValue();
  str.Replace(wxT(","), wxT("."));
  return str;
}

gtNumberCtrl::gtNumberCtrl(wxWindow* parent, const wxString& id, wxSize sz, long flags, const wxTextValidator& val) 
            : wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, sz, flags | wxTE_RIGHT, val, id)
{ }

gtNumberCtrl::gtNumberCtrl(wxWindow* parent, const wxString& id, wxSize sz, long flags) 
            : wxTextCtrl(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, sz, flags | wxTE_RIGHT,
              gtRealValidator(), id)
{ }

///////////////////////////////////////////////////////////
// gtNaturalCtrl
///////////////////////////////////////////////////////////

class gtNaturalCtrl : public gtNumberCtrl
{
public:
  gtNaturalCtrl(wxWindow* parent, const wxString& id, wxSize sz = wxSize(64, -1), long flags = wxTE_RIGHT);
};


gtNaturalCtrl::gtNaturalCtrl(wxWindow* parent, const wxString& id, wxSize sz, long flags)
             : gtNumberCtrl(parent, id, sz, flags, wxTextValidator(wxFILTER_NUMERIC, NULL)) 
{ }

///////////////////////////////////////////////////////////
// gtFloatCtrl
///////////////////////////////////////////////////////////

class gtFloatValidator : public wxTextValidator
{
protected:
  virtual wxValidator* Clone() const { return new gtFloatValidator; }
public:
  gtFloatValidator();
};

gtFloatValidator::gtFloatValidator()
               : wxTextValidator(wxFILTER_INCLUDE_CHAR_LIST)
{ 
  const wxChar* inc = wxT("0123456789-.,");
  wxArrayString a;
  for (const wxChar* i = inc; *i; i++)
    a.Add(wxString(*i));
  SetIncludes(a); 
}

class gtFloatCtrl : public gtNumberCtrl
{
public:
  gtFloatCtrl(wxWindow* parent, const wxString& id, int nFlags = wxTE_RIGHT);
};

gtFloatCtrl::gtFloatCtrl(wxWindow* parent, const wxString& id, int nFlags)
           : gtNumberCtrl(parent, id, wxSize(64,-1), nFlags, gtFloatValidator())
{ }

///////////////////////////////////////////////////////////
// gt01Ctrl
///////////////////////////////////////////////////////////

class gt01Validator : public wxTextValidator
{
protected:
  virtual wxValidator* Clone() const { return new gt01Validator; }
public:
  gt01Validator();
};

gt01Validator::gt01Validator()
               : wxTextValidator(wxFILTER_INCLUDE_CHAR_LIST)
{ 
  const wxChar* inc = wxT("0123456789.,");
  wxArrayString a;
  for (const wxChar* i = inc; *i; i++)
    a.Add(wxString(*i));
  SetIncludes(a); 
}

class gt01Ctrl : public gtNumberCtrl
{
public:
  virtual wxString GetValue() const;
  gt01Ctrl(wxWindow* parent, const wxString& id);
};

wxString gt01Ctrl::GetValue() const
{
  wxString str = gtNumberCtrl::GetValue();
  double d; str.ToDouble(&d);
  if (d < 0) str = wxEmptyString; else
  if (d > 1) str = wxT("1");
  return str;
}

gt01Ctrl::gt01Ctrl(wxWindow* parent, const wxString& id)
        : gtNumberCtrl(parent, id, wxSize(40,-1), wxTE_RIGHT, gt01Validator())
{ }

///////////////////////////////////////////////////////////
// gtCoordCtrl
///////////////////////////////////////////////////////////

class gtCoordCtrl : public gtNumberCtrl
{
public:
  static wxColour Axis2Color(int a);
  static wxString Axis2Label(int a);
  gtCoordCtrl(wxWindow* parent, const wxString& id, int axis);
};

wxColour gtCoordCtrl::Axis2Color(int a)
{
  static const wxColour col[4] = { *wxRED, *wxGREEN, *wxBLUE, *wxWHITE };
  wxASSERT(a >= 0 && a <= 3);
  return ModulatedColor(col[a], 190);
}

wxString gtCoordCtrl::Axis2Label(int a)
{
  static const wxChar* lab[4] = { wxT("x"), wxT("y"), wxT("z"), wxT("t") };
  wxASSERT(a >= 0 && a <= 3);
  return wxString(lab[a]);
}

gtCoordCtrl::gtCoordCtrl(wxWindow* parent, const wxString& id, int a)
           : gtNumberCtrl(parent, id, wxSize(80,-1)) 
{ SetBackgroundColour(Axis2Color(a)); }

///////////////////////////////////////////////////////////
// gtComboBox
///////////////////////////////////////////////////////////

class gtComboBox : public wxComboBox
{
  DECLARE_DYNAMIC_CLASS(gtComboBox);

public:
  virtual wxString GetValue() const;
  virtual void SetValue(const wxString& value);

  gtComboBox() {}
  gtComboBox(wxWindow *parent,
               wxWindowID id,
               const wxString& value,
               const wxPoint& pos,
               const wxSize& size,
               const wxArrayString& choices,
               long style = 0,
               const wxValidator& validator = wxDefaultValidator,
               const wxString& name = wxComboBoxNameStr) 
               : wxComboBox(parent, id, value, pos, size, choices, style, validator, name) {}
};

IMPLEMENT_DYNAMIC_CLASS(gtComboBox, wxComboBox);

wxString gtComboBox::GetValue() const
{
  const wxString str = GetStringSelection();
  return str.BeforeFirst('-').Trim();
}

void gtComboBox::SetValue(const wxString& value)
{
  const size_t n = GetCount();
  int i = 0;
  if (n > 1)
  {
    for (i = n-1; i > 0; i--)
    {
      if (GetString(i).StartsWith(value))
        break;
    }
  }
  SetSelection(i);
}

///////////////////////////////////////////////////////////
// gtBaseDlg
///////////////////////////////////////////////////////////

IMPLEMENT_DYNAMIC_CLASS(gtBaseDlg, wxDialog);

BEGIN_EVENT_TABLE(gtBaseDlg, wxDialog)
  EVT_IDLE(gtBaseDlg::OnIdle)
END_EVENT_TABLE()

bool gtBaseDlg::Init()
{
  if (GetSizer() == NULL)
  {
    const int nSize = 128*3;
    wxSizer* pMainSizer = new wxBoxSizer(wxVERTICAL);

    wxBoxSizer* pSplitBox = new wxBoxSizer(wxHORIZONTAL);
    pMainSizer->Add(pSplitBox, 1, wxGROW);
  
    m_rgbTheme = *wxLIGHT_GREY;
    const wxString strLogo = wxT("fd0logo.png"); 
    if (wxFileName::FileExists(strLogo))
    {
      wxImage img(strLogo, wxBITMAP_TYPE_PNG); 
      if (img.GetWidth() > img.GetHeight())
        img = img.Rotate90(false);
      const int nHeight = img.GetHeight();
      const int nWidth  = img.GetWidth();
      if (nHeight > nSize)
        img.Rescale(nWidth * nSize / nHeight, nSize, wxIMAGE_QUALITY_HIGH);
      const wxBitmap bmp(img);
      pSplitBox->Add(new wxStaticBitmap(this, wxID_ANY, bmp), 0, wxALL, 2);
      m_rgbTheme = wxColour(img.GetRed(0,0), img.GetGreen(0,0), img.GetBlue(0,0));
    }
  
    wxSizer* pButtons = CreateButtonSizer(wxOK | wxCANCEL);
    pMainSizer->Add(pButtons, 0, wxALIGN_RIGHT|wxALIGN_BOTTOM);

    wxSizer* pRightSizer = new wxBoxSizer(wxVERTICAL);
    pRightSizer->SetMinSize(nSize, nSize);
    pSplitBox->Add(pRightSizer, 1, wxGROW);
    
    /*

    for (int i = pButtons->GetChildren().GetCount()-1; i >= 0; i--)
    {
      const wxSizerItem* si = pButtons->GetItem(i);
      wxButton* pButton = wxDynamicCast(si->GetWindow(), wxButton);
      if (pButton != NULL) 
      {
        wxArtID id;
        switch (pButton->GetId())
        {
        case wxID_OK    : id = wxART_GO_FORWARD; break;
        case wxID_CANCEL: id = wxART_ERROR; break;
        default: break;
        }
        if (!id.IsEmpty())
        {
          const wxBitmap bmp = wxArtProvider::GetBitmap(id, wxART_BUTTON);
          if (bmp.IsOk())
            pButton->SetBitmap(bmp);
        }
      }
    }

    */

    SetSizerAndFit(pMainSizer); // Useful inside the following call
    CreateControls(*pRightSizer);
  }
  return true; 
}

bool gtBaseDlg::gtError(const wxString msg)
{
  m_msg = msg;
  return false;
}

void gtBaseDlg::OnIdle(wxIdleEvent& evt)
{
  if (!m_msg.IsEmpty())
  {
    ::gtError(m_msg);
    m_msg.Empty();
  }
  else
    evt.Skip();
}

wxButton* gtBaseDlg::PrependButton(wxWindowID id, wxString strLabel, wxArtID art)
{
  if (GetSizer() == NULL)
    Init();

  wxSizer* pMainSizer = GetSizer();
  wxSizerItemList& list = pMainSizer->GetChildren();
  wxSizerItem* pButtonsItem = list.GetLast()->GetData();
  wxSizer* pButtons = pButtonsItem->GetSizer();

  wxButton* pButt = new wxButton(this, id, strLabel); 
  // if (!art.IsEmpty())  pButt->SetBitmap(wxArtProvider::GetBitmap(art, wxART_BUTTON));
  pButtons->Insert(0, pButt);

  return pButt;
}

gtBaseDlg::gtBaseDlg(const wxString& strTitle, int nFlags) 
         : wxDialog(NULL, wxID_ANY, strTitle, 
                    wxDefaultPosition, wxDefaultSize, 
                    (nFlags ? nFlags : wxDEFAULT_DIALOG_STYLE) | wxCENTRE)
{
  wxFrame* pFrame = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame);
  if (pFrame != NULL)
  {
    const wxIcon ico = pFrame->GetIcon();
    if (ico.Ok())
      SetIcon(ico);
  }
}

///////////////////////////////////////////////////////////
// gtPropertyDlg
///////////////////////////////////////////////////////////

IMPLEMENT_DYNAMIC_CLASS(gtPropertyDlg, gtBaseDlg)

void gtPropertyDlg::OnTextChanged(wxFocusEvent& evt)
{
  wxTextCtrl* pText = wxDynamicCast(evt.GetEventObject(), wxTextCtrl);
  if (pText != NULL && pText->IsModified())
  {
    wxVariant var(pText->GetValue(), pText->GetName());
    if (!OnValidateProperty(var) || !OnPropertyChanged(var))
    {
      // veto!
    }
  }
  evt.Skip(true);
}

void gtPropertyDlg::OnComboChanged(wxCommandEvent& evt)
{
  const wxObject* pObj = evt.GetEventObject();
  wxVariant var;
  
  gtComboBox* pStrCombo = wxDynamicCast(pObj, gtComboBox);
  if (pStrCombo != NULL)
    var = wxVariant(pStrCombo->GetValue(), pStrCombo->GetName());
  else
  {
    const wxComboBox* pCombo = wxStaticCast(pObj, wxComboBox);
    var = wxVariant(pCombo->GetCurrentSelection(), pCombo->GetName());
  }
  if (!var.IsNull() && OnValidateProperty(var))
    OnPropertyChanged(var);
}

void gtPropertyDlg::OnRadioBoxChanged(wxCommandEvent& evt)
{
  const wxObject* pObj = evt.GetEventObject();
  wxRadioBox* pRadio = wxDynamicCast(pObj, wxRadioBox);
  wxVariant var = wxVariant(pRadio->GetSelection(), pRadio->GetName());
  if (!var.IsNull() && OnValidateProperty(var))
    OnPropertyChanged(var);
}

void gtPropertyDlg::OnCheckChanged(wxCommandEvent& evt)
{
  const wxCheckBox* pCheck = wxStaticCast(evt.GetEventObject(), wxCheckBox);
  wxVariant var(pCheck->GetValue(), pCheck->GetName());
  if (OnValidateProperty(var))
    OnPropertyChanged(var);
}

void gtPropertyDlg::OnDateChanged(wxCalendarEvent& evt)
{
  /*
  const wxCalendarCtrl* pDate = wxStaticCast(evt.GetEventObject(), wxCalendarCtrl);
  wxVariant var(evt.GetDate(), pDate->GetName());
  if (OnValidateProperty(var))
    OnPropertyChanged(var);
    */
}

void gtPropertyDlg::OnDatePickChanged(wxDateEvent& evt)
{
  const wxDatePickerCtrl* pDate = wxStaticCast(evt.GetEventObject(), wxDatePickerCtrl);
  wxVariant var(evt.GetDate(), pDate->GetName());
  if (OnValidateProperty(var))
    OnPropertyChanged(var);
}


struct GTTableInfo : public wxObject
{
  wxString m_strTable;
};

void gtPropertyDlg::OnSqlPressed(wxCommandEvent& evt)
{
  wxWindow* pButton = wxStaticCast(evt.GetEventObject(), wxWindow);
  const wxString strProp = pButton->GetName().Mid(4); // Btn_TABLENAME
  const GTTableInfo* info = (const GTTableInfo*)evt.m_callbackUserData;
  if (info && info->m_strTable.StartsWith("*."))
  {
    const wxString ext = info->m_strTable.Mid(2);
    wxString str;
    if (!ext.IsEmpty())
    {
      wxString filter;
      filter << info->m_strTable << "|(File " << ext << ")|"; 
      str << wxT("Selezionare il file di tipo ") << ext;
      str = wxFileSelector(str, NULL, NULL, ext, NULL, 0, this);
    }
    else
    {
      str = wxT("Selezionare una cartella");
      str = wxDirSelector(str, GetString(strProp), wxDD_DEFAULT_STYLE, wxDefaultPosition, this);
    }

    if (!str.IsEmpty())
      SetProperty(strProp, str);
  }
}

void gtPropertyDlg::CreateControls(wxSizer& sizer)
{
  const int dx = 320;
  const int dy = dx * ((1 + sqrt(5.0))/2.0);
  m_pNoteBook = new wxAuiNotebook(this, wxID_ANY, wxDefaultPosition, wxSize(dx,dy),
                                  wxAUI_NB_TAB_FIXED_WIDTH | wxAUI_NB_SCROLL_BUTTONS);
  sizer.Add(m_pNoteBook, 1, wxGROW);
  AddPage(_("Propriet�"));
}

bool gtPropertyDlg::TransferDataToWindow()
{
  bool ok = gtBaseDlg::TransferDataToWindow();

  if (ok && m_pNoteBook == NULL)
    ok = Init();

  return ok;
}

bool gtPropertyDlg::TransferDataFromWindow()
{
  const bool ok = m_pNoteBook != NULL && gtBaseDlg::TransferDataFromWindow();
  return ok;
}

void gtPropertyDlg::AddPage(const wxString& strLabel)
{
  wxASSERT(m_pNoteBook != NULL);
  wxPanel* pPanel = new wxPanel(m_pNoteBook);
  m_pNoteBook->AddPage(pPanel, strLabel);

  wxFlexGridSizer* pGrid = new wxFlexGridSizer(2);
  pGrid->AddGrowableCol(1, 1);
  pPanel->SetSizer(pGrid);
  pGrid->SetSizeHints(pPanel);
}

wxPanel* gtPropertyDlg::GetCurrPanel()
{
  wxASSERT(m_pNoteBook != NULL);
  wxWindow* pWindow = m_pNoteBook->GetPage(m_pNoteBook->GetPageCount()-1);
  return wxStaticCast(pWindow, wxPanel);
}

void gtPropertyDlg::AddCategory(const wxString& strLabel)
{
  wxPanel* pPanel = GetCurrPanel();
  wxGridSizer* pSizer = wxStaticCast(pPanel->GetSizer(), wxGridSizer);
  wxStaticText* pText = new wxStaticText(pPanel, wxID_ANY, "  " + strLabel + "  ", 
                                         wxDefaultPosition, wxDefaultSize, 0);
  const wxColour& rgb = ThemeColour();
  pText->SetForegroundColour(gtContrastingColor(rgb));
  pText->SetBackgroundColour(rgb);
  pSizer->Add(pText, 1, wxGROW|wxALIGN_CENTER_VERTICAL);

  for (int i = pSizer->GetCols(); i > 1; i--)
  {
    // pSizer->AddSpacer(4);
    wxStaticText* pSpacer = new wxStaticText(pPanel, wxID_ANY, "");
    pSpacer->SetBackgroundColour(rgb);
    pSizer->Add(pSpacer, 1, wxGROW|wxALIGN_CENTER_VERTICAL);
  }
}

static void SetPropertyHint(wxWindow& p, const wxString& strHint)
{
  if (!strHint.IsEmpty())
  {
    p.SetToolTip(strHint);
  }
}

void gtPropertyDlg::AddLabel(const wxString& strLabel)
{
  if (!strLabel.IsEmpty())
  {
    wxPanel* pPanel = GetCurrPanel();
    wxSizer* pSizer = pPanel->GetSizer();
    wxStaticText* pText = new wxStaticText(pPanel, wxID_ANY, strLabel);
    pSizer->Add(pText, 0, wxALL | wxALIGN_CENTER_VERTICAL, 1);
  }
}

void gtPropertyDlg::AddProperty(const char* strName, const wxString& strValue, const wxString& strLabel, 
                                long flags, const wxString& strHint)
{
  wxPanel* pPanel = GetCurrPanel();
  wxSizer* pSizer = pPanel->GetSizer();

  AddLabel(strLabel);

  const wxString strHandle = strName;
  const wxSize sz((flags & wxTE_READONLY) ? -1 : 128, -1);
  wxTextCtrl* pText = new wxTextCtrl(pPanel, wxID_ANY, strValue, 
                                     wxDefaultPosition, sz,
                                     flags, wxDefaultValidator, strHandle); 
  pText->Connect(wxEVT_KILL_FOCUS, 
                 wxFocusEventHandler(gtPropertyDlg::OnTextChanged), 
                 NULL, this);

  //SetPropertyColor(*pText);
  SetPropertyHint(*pText, strHint);
  if (flags & wxTE_READONLY)
  {
    pText->Disable();
    pSizer->Add(pText, 0, wxALL, 1);  // Evita resizing campi fissi
  }
  else
    pSizer->Add(pText, 1, wxGROW|wxALL, 1);

  m_hControls[strName] = pText;
}

void gtPropertyDlg::AddProperty(const char* strName, const wxArrayString& aLabels, int nValue, 
                                  const wxString& strLabel, long flags)
{
  const wxString strHandle = strName;
  wxPanel* pPanel = GetCurrPanel();
  wxSizer* pSizer = pPanel->GetSizer();

  if ((flags & wxTE_MULTILINE) || aLabels.GetCount() == 2)
  {
    wxRadioBox* pBox = new wxRadioBox(pPanel, wxID_ANY, strLabel, wxDefaultPosition, wxDefaultSize,
                                      aLabels, 0, wxRA_SPECIFY_ROWS, wxDefaultValidator, strHandle);
    pBox->Connect(wxEVT_COMMAND_RADIOBOX_SELECTED, 
                  wxCommandEventHandler(gtPropertyDlg::OnRadioBoxChanged), NULL, this);
    pSizer->Add(pBox, 1, wxALL | wxGROW, 1);
    pSizer->AddSpacer(8);
  }
  else
  {
    AddLabel(strLabel);
    wxComboBox* pBox = new wxComboBox(pPanel, wxID_ANY, aLabels[nValue], wxDefaultPosition, wxDefaultSize,
                                      aLabels, flags | wxCB_READONLY, wxDefaultValidator, strHandle);
    pSizer->Add(pBox, 1, wxGROW | wxALL, 2);

    if (flags & wxTE_READONLY)
    {
      pBox->Disable();
    }
    else
    {
      pBox->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED , 
                    wxCommandEventHandler(gtPropertyDlg::OnComboChanged), NULL, this);
    }
    m_hControls[strName] = pBox;
  }
}

void gtPropertyDlg::AddProperty(const char* strName, const wxArrayString& aLabels, const wxString& strValue, 
                                  const wxString& strLabel, long flags)
{
  const wxString strHandle = strName;
  wxPanel* pPanel = GetCurrPanel();
  wxSizer* pSizer = pPanel->GetSizer();
  AddLabel(strLabel);

  gtComboBox* pBox = new gtComboBox(pPanel, wxID_ANY, strValue, wxDefaultPosition, wxDefaultSize,
                                         aLabels, flags | wxCB_READONLY, wxDefaultValidator, strHandle);
  pBox->SetValue(strValue);
  pSizer->Add(pBox, 1, wxGROW|wxALL, 1);
  if (flags & wxTE_READONLY)
  {
    pBox->Disable();
  }
  else
  {
    pBox->Connect(wxEVT_COMMAND_COMBOBOX_SELECTED , 
                  wxCommandEventHandler(gtPropertyDlg::OnComboChanged), NULL, this);
  }
  m_hControls[strName] = pBox;
}


void gtPropertyDlg::AddProperty(const char* strName, int nValue, const wxString& strLabel, 
                                  long flags, const wxString& strHint)
{
  const wxString strHandle = strName;
  wxPanel* pPanel = GetCurrPanel();
  wxSizer* pSizer = pPanel->GetSizer();

  AddLabel(strLabel);

  wxTextCtrl* pText = new gtNaturalCtrl(pPanel, strHandle, wxSize(64, -1), wxTE_RIGHT | flags);
  //SetPropertyColor(*pText);
  SetPropertyHint(*pText, strHint);
  if (flags & wxTE_READONLY)
    pText->Disable();
  if (nValue != 0)
  {
    wxString strValue; strValue.Printf("%d", nValue);
    pText->ChangeValue(strValue);
  }
  pSizer->Add(pText, 0, wxALL, 1);

  pText->Connect(wxEVT_KILL_FOCUS, 
                 wxFocusEventHandler(gtPropertyDlg::OnTextChanged), NULL, this);
  m_hControls[strName] = pText;
}

void gtPropertyDlg::AddProperty(const char* strName, double nValue, const wxString& strLabel, 
                                long flags, const wxString& strHint)
{
  const wxString strHandle = strName;
  wxPanel* pPanel = GetCurrPanel();
  wxSizer* pSizer = pPanel->GetSizer();

  AddLabel(strLabel);

  wxTextCtrl* pText = new gtFloatCtrl(pPanel, strHandle, flags);
   if (flags & wxTE_READONLY)
    pText->Disable();
  wxString strValue; strValue.Printf("%.2lf", nValue);
  pText->ChangeValue(strValue);
  SetPropertyHint(*pText, strHint);
  pSizer->Add(pText, 0, wxALL, 1);

  pText->Connect(wxEVT_KILL_FOCUS, 
                 wxFocusEventHandler(gtPropertyDlg::OnTextChanged), NULL, this);
  m_hControls[strName] = pText;
}

void gtPropertyDlg::AddProperty(const char* strName, bool bValue, const wxString& strLabel, long flags)
{
  const wxString strHandle = strName;
  wxPanel* pPanel = GetCurrPanel();
  wxSizer* pSizer = pPanel->GetSizer();

  AddLabel(strLabel);

  wxCheckBox* pBox = new wxCheckBox(pPanel, wxID_ANY, wxEmptyString, 
                                    wxDefaultPosition, wxDefaultSize,
                                    flags, wxDefaultValidator, strHandle);
  pSizer->Add(pBox, 0, wxALL, 2);
  pBox->SetValue(bValue);

  if (flags & wxTE_READONLY)
    pBox->Disable();
  else
    pBox->Connect(wxEVT_COMMAND_CHECKBOX_CLICKED, 
                  wxCommandEventHandler(gtPropertyDlg::OnCheckChanged), NULL, this);
  m_hControls[strName] = pBox;
}

void gtPropertyDlg::AddProperty(const char* strName, const wxDateTime& dt, const wxString& strLabel, long flags)
{
  AddLabel(strLabel);
  wxPanel* pPanel = GetCurrPanel();

  const bool bDisable = (flags & wxTE_READONLY) != 0;
  if (bDisable)
    flags &= ~wxTE_READONLY;

  wxControl* pCtrl = NULL;
  /*
  if (flags & wxTE_MULTILINE)
  {
    flags = wxCAL_SHOW_HOLIDAYS | wxCAL_MONDAY_FIRST;
    wxCalendarCtrl* cc = new wxCalendarCtrl(pPanel, wxID_ANY, wxDefaultDateTime, 
                                            wxDefaultPosition, wxSize(256,-1), flags, strName);
    if (dt.IsValid())
      cc->SetDate(dt);
    cc->Connect(wxEVT_CALENDAR_SEL_CHANGED, wxCalendarEventHandler(gtPropertyDlg::OnDateChanged), NULL, this);
    pCtrl = cc;
  }
  else
  */
  {
    wxDatePickerCtrl* dp = new wxDatePickerCtrl(pPanel, wxID_ANY, dt, wxDefaultPosition, wxDefaultSize, 
                                                4, wxDefaultValidator, strName);
    dp->Connect(wxEVT_DATE_CHANGED, wxDateEventHandler(gtPropertyDlg::OnDatePickChanged), NULL, this);
    pCtrl = dp;
  }

  pPanel->GetSizer()->Add(pCtrl, 1, wxALL|wxGROW, 2);
  if (bDisable)
    pCtrl->Disable();
  m_hControls[strName] = pCtrl;
}

void gtPropertyDlg::AddPropertyDB(const char* strName, const wxString& strValue, const wxString& strLabel, 
                                  long flags, const wxString& strHint, const char* strTable)
{
  wxPanel* pPanel = GetCurrPanel();
  wxSizer* pSizer = pPanel->GetSizer();
    
  wxSizer* pButtonSizer = new wxBoxSizer(wxHORIZONTAL);
  pSizer->Add(pButtonSizer, 1, wxGROW|wxALL, 1);

  pButtonSizer->Add(new wxStaticText(pPanel, wxID_ANY, strLabel), 1, wxGROW|wxALIGN_CENTER_VERTICAL);
  pButtonSizer->AddSpacer(8);

  wxButton* pButton = NULL;
  const wxBitmap bmp = wxArtProvider::GetBitmap(wxART_REPORT_VIEW, wxART_BUTTON);
  if (bmp.Ok())
    pButton= new wxBitmapButton(pPanel, wxID_ANY, bmp, wxDefaultPosition, wxSize(24,-1),
                                0, wxDefaultValidator, wxString("Btn_")+strName);
  else
    pButton= new wxButton(pPanel, wxID_ANY, wxT("..."), wxDefaultPosition, wxSize(24,-1),
                          0, wxDefaultValidator, wxString("Btn_")+strName);

  GTTableInfo* info = new GTTableInfo;
  info->m_strTable = strTable;
  pButton->Connect(wxEVT_COMMAND_BUTTON_CLICKED, 
                   wxCommandEventHandler(gtPropertyDlg::OnSqlPressed), info, this);
  pButtonSizer->Add(pButton, 0, wxALIGN_RIGHT);
    
  gtPropertyDlg::AddProperty(strName, strValue, "", flags, strHint);
}

wxWindow* gtPropertyDlg::FindControl(const char* strName) const
{
  wxString key = strName;
  wxWindow* pWin = ((gtPropertyCtrls&)m_hControls)[key];
  if (pWin == NULL)
  {
    pWin = wxWindowBase::FindWindowByName(key, m_pNoteBook);
    if (pWin != NULL)
    {
      if (pWin->GetName() == key) 
        ((gtPropertyCtrls&)m_hControls)[key] = pWin;
      else
        pWin = NULL; // Succede con wxStaticText
    }
  }
  return pWin;
}

wxVariant gtPropertyDlg::GetProperty(const char* strName) const
{ 
  const wxString name(strName);
  wxWindow* pCtrl = FindControl(strName);
  if (pCtrl == NULL || !pCtrl->IsShown())
    return wxNullVariant;

  wxVariant var;
  var.SetName(name);

  gtComboBox* pStrCombo = wxDynamicCast(pCtrl, gtComboBox);
  if (pStrCombo)
    var = pStrCombo->GetValue();
  else
  {
    wxComboBox* pCombo = wxDynamicCast(pCtrl, wxComboBox);
    if (pCombo)
      var = (long)pCombo->GetCurrentSelection();
    else
    {
      wxCheckBox* pCheck= wxDynamicCast(pCtrl, wxCheckBox);
      if (pCheck)
      {
        var = pCheck->GetValue();
      }
      else
      {
        wxRadioBox* pRadioBox= wxDynamicCast(pCtrl, wxRadioBox);
        if (pRadioBox)
        {
          var = (long)pRadioBox->GetSelection();
        }
        else
        {
          wxRadioButton* pRadio= wxDynamicCast(pCtrl, wxRadioButton);
          if (pRadio)
          {
            var = pRadio->GetValue();
          }
          else
          {
            /*
            wxCalendarCtrl* pCalendar = wxDynamicCast(pCtrl, wxCalendarCtrl);
            if (pCalendar)
            {
              var = pCalendar->GetDate();
            }
            else
            */
            {
              wxDatePickerCtrl* pDate = wxDynamicCast(pCtrl, wxDatePickerCtrl);
              if (pDate)
              {
                var = pDate->GetValue();
              } else
              {

                wxTextCtrl* pText = wxDynamicCast(pCtrl, wxTextCtrl);
                if (pText)
                {
                  const wxString str = pText->GetValue();
                  if (!str.IsEmpty() && wxIsdigit(str[0]) && pText->GetAlignment() == wxALIGN_RIGHT)
                    var = wxAtol(str);
                  else
                    var = str;
                }
                else
                  var = pCtrl->GetLabel();
              }
            }
          }
        }
      }
    }
  }

  return var; 
}

bool gtPropertyDlg::SetProperty(const char* strName, const wxVariant& var)
{ 
  wxWindow* pCtrl = FindControl(strName);
  if (pCtrl == NULL)
    return false;
    
  gtComboBox* pStrCombo = wxDynamicCast(pCtrl, gtComboBox);
  if (pStrCombo)
  {
    if (var.IsType(wxT("long")))
      pStrCombo->SetSelection(var.GetLong());
    else
      pStrCombo->SetValue(var.GetString());
  }
  else
  {
    wxComboBox* pCombo = wxDynamicCast(pCtrl, wxComboBox);
    if (pCombo)
    {
      if (var.IsType(wxT("long")))
        pCombo->SetSelection(var.GetLong());
      else
      {
        const wxString val = var.GetString();
        if (!pCombo->SetStringSelection(val))
          pCombo->SetSelection(wxAtoi(val));
      }
    }
    else
    {
      wxCheckBox* pCheck= wxDynamicCast(pCtrl, wxCheckBox);
      if (pCheck)
      {
        if (var.IsType("string"))
          pCheck->SetValue(!var.GetString().IsEmpty());
        else
          pCheck->SetValue(var.GetBool());
      }
      else
      {
        /*
        wxCalendarCtrl* pCalendar= wxDynamicCast(pCtrl, wxCalendarCtrl);
        if (pCalendar)
        {
          if (var.IsType("datetime"))
            pCalendar->SetDate(var.GetDateTime());
          else
          {
            const long val = var.GetLong();
            if (val >= 19000101)
            {
              const wxDateTime dt(val%100, (val/100)%100, val/10000, 12);
              pCalendar->SetDate(dt);
            }
            else
              pCalendar->SetDate(wxDateTime::Now());
          }
        }
        else
        */
        {
          wxDatePickerCtrl* pDate= wxDynamicCast(pCtrl, wxDatePickerCtrl);
          if (pDate)
          {
            if (var.IsType("datetime"))
              pDate->SetValue(var.GetDateTime());
            else
            {
              const long val = var.GetLong();
              if (val >= 19000101)
              {
                const wxDateTime dt(val%100, (val/100)%100, val/10000, 12);
                pDate->SetValue(dt);
              }
              else
                pDate->SetValue(wxDateTime::Now());
            }
          }
          else
          {
            wxTextCtrl* pText = wxDynamicCast(pCtrl, wxTextCtrl);
            if (pText)
            {
              if (var.IsType(wxT("double")))
              {
                const double d = var.GetDouble();
                wxString str;
                if (d)
                  str.Printf("%.2lf", d);
                pText->ChangeValue(str);
              }
              else
                pText->ChangeValue(var.GetString());
            }
            else
              pCtrl->SetLabel(var.GetString());
          }
        }
      }
    }
  }
  return true; 
}

wxString gtPropertyDlg::GetString(const char* strName) const
{ return GetProperty(strName).GetString(); }

int gtPropertyDlg::GetInt(const char* strName) const
{ 
  const wxVariant& var = GetProperty(strName);
  if (var.GetType() == "datetime")
  {
    const wxDateTime dt = var.GetDateTime();
    return dt.GetYear()*10000 + (dt.GetMonth()+1)*100 + dt.GetDay();
  }
  return var.GetLong(); 
}

wxDateTime gtPropertyDlg::GetDate(const char* strName) const
{
  wxDateTime dt;
  wxWindow* pCtrl = FindControl(strName);
  if (pCtrl != NULL)
  {
/*
    const wxCalendarCtrl* pCalendar = wxDynamicCast(pCtrl, wxCalendarCtrl);
    if (pCalendar)
      dt = pCalendar->GetDate();
    else
    */
    {
      const wxDatePickerCtrl* pDate = wxDynamicCast(pCtrl, wxDatePickerCtrl);
      if (pDate)
        dt = pDate->GetValue();
    }
  }
  return dt;
}

double gtPropertyDlg::GetDouble(const char* strName) const
{ 
  const wxVariant v = GetProperty(strName);
  double d = 0; v.Convert(&d);
  return d; 
}

bool gtPropertyDlg::GetBool(const char* strName) const
{ return GetProperty(strName).GetBool(); }

bool gtPropertyDlg::EnableProperty(const wxString& name, bool on)
{
  wxWindow* pCtrl = FindControl(name);
  if (pCtrl != NULL)
    pCtrl->Enable(on);
  return pCtrl != NULL;
}

bool gtPropertyDlg::IsPropertyEnabled(const wxString& name) const
{
  wxWindow* pCtrl = FindControl(name);
  return (pCtrl != NULL) && pCtrl->IsEnabled();
}

bool gtPropertyDlg::ShowProperty(const wxString& name, bool on)
{
  wxWindow* pCtrl = FindControl(name);
  if (pCtrl != NULL)
    pCtrl->Show(on);
  return pCtrl != NULL;
}

bool gtPropertyDlg::IsPropertyShown(const wxString& name) const
{
  wxWindow* pCtrl = FindControl(name);
  return (pCtrl != NULL) && pCtrl->IsShown();
}

bool gtPropertyDlg::OnDecodeProperty(wxVariant& var)
{
  return true;
}

bool gtPropertyDlg::OnValidateProperty(wxVariant& var)
{
  if (!OnDecodeProperty(var))
  {
    wxString msg;
    msg << wxT("Valore non ammesso per ") << var.GetName();
    return gtError(msg);
  }
  return true;
}

bool gtPropertyDlg::OnPropertyChanged(const wxVariant&)
{
  return true;
}

int gtPropertyDlg::ShowModal()
{
  if (m_pNoteBook == NULL)
    Init();
  const int ret =  gtBaseDlg::ShowModal(); 
  return ret;
}

bool gtPropertyDlg::SaveDefault() const
{
/*
  const wxFileName fpath = ((gtApp*)wxTheApp)->OutputName("ini"); 
  
  const wxString strIni = fpath.GetFullPath();
  const wxString strPar = GetTitle();

  for (auto it = m_hControls.begin(); it != m_hControls.end(); ++it )
  {
    const wxString key = it->first;
    const wxWindow* pCtl = it->second;
    if (pCtl != NULL && pCtl->IsEnabled())
    {
      wxString val = GetProperty(key).GetString();
      val.Replace("\n", "<br/>");
      ::WritePrivateProfileString(strPar, key, val, strIni);
    }
  }

  return fpath.FileExists();
*/
  return false;
}

bool gtPropertyDlg::LoadDefault()
{
/*
  const wxFileName fpath = ((gtApp*)wxTheApp)->OutputName("ini"); 

  bool bDone = fpath.FileExists();
  if (bDone)
  {
    if (m_pNoteBook == NULL)
      Init();
    const wxString strIni = fpath.GetFullPath();
    const wxString strPar = GetTitle();
  
    for (auto it = m_hControls.begin(); it != m_hControls.end(); ++it )
    {
      const wxString key = it->first;
      char buf[2048];
      ::GetPrivateProfileStringA(strPar, key, "", buf, sizeof(buf), strIni);
      wxString val = buf;
      val.Replace("<br/>", "\n");
      SetProperty(key, wxVariant(val, key));
    }
    for (auto it = m_hControls.begin(); it != m_hControls.end(); ++it )
    {
      wxVariant var = GetProperty(it->first);
      if (OnDecodeProperty(var))
        OnPropertyChanged(var);
    }
  }

  return bDone;
*/
  return false;
}

gtPropertyDlg::gtPropertyDlg(const wxString& strTitle, int flags) 
               : gtBaseDlg(strTitle, flags), m_pNoteBook(NULL) 
{}