//Il sorgente va scritto in notazione ungherese.
//Le variabili seguono la seguente regola: 'acronimo tipo'+'nome variabile cammellata' 
//Es. wxArrayString 'as' + 'AcceptRefuse' -> asAcceptRefuse
#include "wxinc.h"
#include "utils.h"

///////////////////////////////////////////////////////////
//  UpdateFrame
///////////////////////////////////////////////////////////

class UpdateFrame : public wxFrame
{
protected:
  DECLARE_EVENT_TABLE();
  virtual void OnErase(wxEraseEvent& e);
public:
  UpdateFrame();
};

BEGIN_EVENT_TABLE(UpdateFrame, wxFrame)
  EVT_ERASE_BACKGROUND(UpdateFrame::OnErase)
END_EVENT_TABLE()

void UpdateFrame::OnErase(wxEraseEvent& e)
{
  //preparazione background
  wxDC& dc = *e.GetDC();
  const wxRect rect = GetClientSize();
  wxColour c0 = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
  wxColour c1 = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
  wxColour c2 = wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW);
  
  wxRect rect1 = rect; rect1.SetBottom(rect.GetBottom() / 2);
  dc.GradientFillLinear(rect1, c0, c1, wxSOUTH);

  wxRect rect2 = rect; rect2.SetTop(rect.GetBottom() / 2);
  dc.GradientFillLinear(rect2, c1, c2, wxDOWN);

  const int nHeight = rect.GetHeight()/10;
  wxFont* pFont = wxTheFontList->FindOrCreateFont(nHeight, wxFONTFAMILY_SWISS, wxFONTSTYLE_ITALIC, 
                                                  wxFONTWEIGHT_BOLD);
  dc.SetFont(*pFont);
  dc.SetBackgroundMode(wxTRANSPARENT);

  const int k = nHeight / 16 + 1;

  dc.SetTextForeground(c2);
  dc.DrawText("Tower", k, k);
  dc.SetTextForeground(c1);
  dc.DrawText("Tower", k/2, k/2);

  int w, h;
  const wxString strSetup = wxT("Backup");
  dc.GetTextExtent(strSetup, &w, &h);

  dc.SetTextForeground(c2);
  dc.DrawText(strSetup, rect.GetRight()-w-k/2, rect.GetHeight()-h-k/2);
  dc.SetTextForeground(c1);
  dc.DrawText(strSetup, rect.GetRight()-w-k, rect.GetHeight()-h-k);
}

UpdateFrame::UpdateFrame()
       : wxFrame(NULL, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0)
{
  ShowFullScreen(true);
}

WX_DECLARE_STRING_HASH_MAP( int, HashMap );

///////////////////////////////////////////////////////////
// UpdateExternal
///////////////////////////////////////////////////////////
//classe principale, ovvero applicazione
class UpdateExternal : public wxApp
{
  UpdateFrame* m_pMainFrame;
  wxLocale m_locale;
  wxString m_strSetupPath;

protected:
  DECLARE_EVENT_TABLE()

  //metodi principali dell'applicazione
  void OnTimer(wxTimerEvent& e);

  //metodi di utility per i vari modi di aggiornamento
  void CopyDir(const wxString& strSourcePath, const wxString& strDestPath, const wxString& strModule,
               HashMap& hmBadExt, wxArrayString& asBadDir) const;
  bool CheckAndCopyFile(const wxString& FilesListI, wxString strFileCurr, HashMap& hmBadExt, wxArrayString& asBadDir) const;  
 
public:
  virtual bool OnInit();
};

IMPLEMENT_APP(UpdateExternal)

BEGIN_EVENT_TABLE(UpdateExternal, wxApp)
  EVT_TIMER(883, OnTimer)
END_EVENT_TABLE()



//----------------------------------------------------------------
// Metodi di utility per i vari tipi di aggiornamento
//----------------------------------------------------------------
static int PatchCompare(const wxString& first, const wxString& second)
{
  const wxFileName fn1(first);
  const wxFileName fn2(second);
  const wxString strName1 = fn1.GetName().Lower();
  const wxString strName2 = fn2.GetName().Lower();
  if (strName1 == "syinst1")
    return -1;
  if (strName2 == "syinst1")
    return 1;

  return strName1.CompareTo(strName2);
}


bool UpdateExternal::CheckAndCopyFile(const wxString& FilesListI, wxString strFileCurr, 
                                      HashMap& hmBadExt, wxArrayString& asBadDir) const
{
  bool ok = true;
  strFileCurr.MakeLower();  //minuscolizzazione di sicurezza
  const wxFileName strFileName(strFileCurr);

  //NON copiare i sorgenti cocco!!
  const wxString strExt = strFileName.GetExt();

  //if (strFileCurr.Find("/cvs/") < 0 && strFileCurr.Find("/modf24/") < 0 )
  if (hmBadExt[strExt] == 0)
  {
    //e nemmeno le directory personali o inutili!
    size_t nBadDirItems = asBadDir.GetCount();
    for (size_t i = 0; i < nBadDirItems; i++)
    {
      wxString strBadDir = asBadDir[i];
      int nFound = strFileCurr.Find(strBadDir);
      if (nFound >= 0)
        return ok; // salta sottocartella proibita
    }

    //eventuali sottodirectory le crea (solo se hanno un nome)
    const wxString strDir = strFileName.GetPath();
    if (!strDir.IsEmpty() && !wxDirExists(strDir))
    {
      for (size_t d = 0; d < strFileName.GetDirCount(); d++)
      {
        wxString strCartellina = strFileName.GetVolume() + ":";
        for (size_t e = 0; e <= d; e++)
        {
          strCartellina << "\\" << strFileName.GetDirs()[e];
        }
        if (!wxDirExists(strCartellina))
          wxMkdir(strCartellina);
      }
    }

    //solo i files piu' nuovi vanno copiati
    bool bCopia = !::wxFileName::FileExists(strFileCurr);
    if (!bCopia)
    {
      time_t t_local = ::wxFileModificationTime(FilesListI);
      time_t t_remote = ::wxFileModificationTime(strFileCurr);
      bCopia  = t_local > t_remote;
    }
    if (bCopia)
      ok = CopiaFile(FilesListI, strFileCurr);
  }
  return ok;
}

//metodo per copiare una directory e tutti i files che contiene
void UpdateExternal::CopyDir(const wxString& strSrc, const wxString& strDest, const wxString& strModule, 
                             HashMap& hmBadExt, wxArrayString& asBadDir) const
{
  wxArrayString asList;
  const size_t uFilesToCopy = wxDir::GetAllFiles(strSrc + strModule, &asList);
  wxString strFileCurr;
  const size_t nPathLenght = strSrc.Len();
  CampoProgressDialog pi("Copia files...", (int)uFilesToCopy);      
  for (size_t i = 0; i < uFilesToCopy; i++)
  {
    if (!pi.Update((int)i, asList[i]))
      break;

    asList[i].Lower();
    strFileCurr = strDest;
    strFileCurr += asList[i].Mid(nPathLenght);
           
    if (!strFileCurr.IsEmpty())
    {
      if (!CheckAndCopyFile(asList[i], strFileCurr, hmBadExt, asBadDir))
        break;
    }
  }
}



//metodo principale che sceglie la modalita' di lancio del programma
void UpdateExternal::OnTimer(wxTimerEvent& WXUNUSED(e))
{
  const wxString strCurrDir = wxGetCwd();
  const wxString strIniName = strCurrDir + "\\update.ini";
  wxString strSrcPath;
  wxString strDestPath;

  //legge il file di configurazione per sapere i path di origine e destinazione (tra {} x poterlo chiudere subito)
  {
	  CampoIniFile UpdateIni(strIniName, "path");
    strSrcPath = UpdateIni.Get("origine");
    strDestPath = UpdateIni.Get("destinazione");
  }

  //array con le estensioni proibite
  HashMap hmBadExt;
  {
    CampoIniFile UpdateExt(strIniName, "badext");
    wxString strWrk;
    long nIndex;
    wxString strBadExt;
    for (bool ok = UpdateExt.GetFirstEntry(strWrk, nIndex); ok; ok = UpdateExt.GetNextEntry(strWrk, nIndex))
    {
      strBadExt = UpdateExt.Get(strWrk);
      hmBadExt[strBadExt] = 1;
    }
  }

  //array con le directory proibite
  wxArrayString asBadDir;
  {
    CampoIniFile UpdateDir(strIniName, "baddir");
    wxString strWrk;
    long nIndex;
    wxString strBadDir;
    for (bool ok = UpdateDir.GetFirstEntry(strWrk, nIndex); ok; ok = UpdateDir.GetNextEntry(strWrk, nIndex))
    {
      strBadDir = UpdateDir.Get(strWrk);
      asBadDir.Add(strBadDir);
    }
  }

	//legge il file di configurazione per avere l'elenco delle directory da copiare e le copia finche ce n'e'!
  CampoIniFile UpdateDirs(strIniName, "dirs");
  wxString strWrk;
  long nIndex;
  wxString strNomeDir;
  for (bool ok = UpdateDirs.GetFirstEntry(strWrk, nIndex); ok; ok = UpdateDirs.GetNextEntry(strWrk, nIndex))
  {
    strNomeDir = UpdateDirs.Get(strWrk);
    CopyDir(strSrcPath, strDestPath, strNomeDir, hmBadExt, asBadDir);
  }

  m_pMainFrame->Destroy();
}


bool UpdateExternal::OnInit()
{
  wxInitAllImageHandlers();
  m_locale.Init();

  m_pMainFrame = new UpdateFrame;
  SetTopWindow(m_pMainFrame);

  wxTimerEvent e(883);
  AddPendingEvent(e);   
  
  return true;
}