#include "wxinc.h"
#include "incstr.h"
#include "agasys.h"

///////////////////////////////////////////////////////////
// Unzip support
///////////////////////////////////////////////////////////

#include <wx/dir.h>
#include <wx/progdlg.h>
#include <wx/wfstream.h>
#include <wx/zipstrm.h>

static unsigned int aga_getziplist(const char* zipfile, wxArrayString& aFiles)
{
	wxFFileInputStream fin(zipfile);
  wxZipInputStream zip(fin);
  for (wxZipEntry* z = zip.GetNextEntry(); z; z = zip.GetNextEntry())
  {
    const wxString str = z->GetInternalName();
    aFiles.Add(str);
  }

	return aFiles.GetCount();
}

static int aga_find_slash(const wxString& path, int from)
{
  for (int i = from; path[i]; i++)
    if (wxIsPathSeparator(path[i]))
      return i;

    return -1;
}

static void aga_create_dir(wxString strPath)
{
  if (!wxEndsWithPathSeparator(strPath))
		strPath += wxFILE_SEP_PATH;

  for (int i = aga_find_slash(strPath, 0); i > 0; i = aga_find_slash(strPath, i+1))
  {
    const wxString strDir = strPath.Mid(0,i);
	  if (!::wxDirExists(strDir))
    {
      if (!::wxMkdir(strDir))
      {
        wxString strMsg = "Impossibile creare la cartella ";
        strMsg << strDir << " !!";
        wxMessageBox(strMsg, "Attenzione!", wxICON_ERROR);
      }
    }			
  }
}

bool aga_unzip(const char* zipfile, const char* destdir)
{
	wxArrayString aFiles;
	const unsigned int files = aga_getziplist(zipfile, aFiles);

  wxProgressDialog pi("Unzip", "", files, NULL, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
  pi.SetSize(480, 120);
  pi.Center();

	for (unsigned int f = 0; f < files; f++)
	{
    const wxString& strFileName = aFiles[f];
    if (!pi.Update(f, strFileName))
      break;

    if (wxEndsWithPathSeparator(strFileName) || strFileName.Find('.') < 0)  // Is dir name
    {
		  wxString strOutDir = destdir;
      if (!wxEndsWithPathSeparator(strOutDir))
		    strOutDir += wxFILE_SEP_PATH;
		  strOutDir += strFileName;
      aga_create_dir(strOutDir);
    }
    else
    {
		  wxZipInputStream fin(zipfile, strFileName);

		  wxString strOutFile = destdir;
      if (!wxEndsWithPathSeparator(strOutFile) && !wxIsPathSeparator(strFileName[0]))
		    strOutFile += wxFILE_SEP_PATH;
		  strOutFile += strFileName;

		  wxString strPath;
		  ::wxSplitPath(strOutFile, &strPath, NULL, NULL);
      aga_create_dir(strPath);
	
      wxFileOutputStream fout(strOutFile);
		  fout.Write(fin);
    }
	}
	return files > 0;
}

///////////////////////////////////////////////////////////
// Zip support
///////////////////////////////////////////////////////////

static void AddFileToZip(const wxString& strPrefix, const wxString& strFile,
												 wxZipOutputStream& zip)
{
	if (!wxFileExists(strFile))
		return;

	wxString strPath, strName, strExt;
	wxSplitPath(strFile, &strPath, &strName, &strExt);	

	wxString strRelName;
	strRelName = strPath.Mid(strPrefix.Length());
	if (!strRelName.IsEmpty())
	  strRelName += '/';
	strRelName += strName;
	strRelName += '.';
	strRelName += strExt;

  zip.PutNextEntry(strRelName);
 	wxFileInputStream fin(strFile);
	zip.Write(fin);                                  // Scrivo file compresso
}

static bool AddFilesToZip(const wxString& strBase, wxArrayString& aFiles, const char* zipfile)
{
	wxFFileOutputStream out(zipfile);
	wxZipOutputStream zip(out);

  const size_t nFiles = aFiles.GetCount();
  wxProgressDialog pi("Zip", "", nFiles, NULL, wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT);
  pi.SetSize(480, 120);
  pi.Center();

  for (size_t i = 0; i < nFiles; i++) 
  {
    const wxString& str = aFiles[i];
    if (!pi.Update(i, str))
      break;
		AddFileToZip(strBase, str, zip);
  }
	return true;
}

bool aga_zip(const char* srcfiles, const char* zipfile)
{
	wxString strBase, strMask, strExt;
	wxSplitPath(srcfiles, &strBase, &strMask, &strExt);
	strMask += '.';
	strMask += strExt;

	wxArrayString aFiles;
  wxDir::GetAllFiles(strBase, &aFiles, strMask);

	return AddFilesToZip(strBase, aFiles, zipfile);
}

bool aga_zip_filelist(const char* filelist, const char* zipfile)
{
  wxArrayString aFiles;
	ifstream fin(filelist);
	while (!fin.eof())
	{
		char name[_MAX_PATH];
		fin.getline(name, sizeof(name));
		if (*name)
		  aFiles.Add(name);
		else
			break;
	}
	return AddFilesToZip("", aFiles, zipfile);
}

///////////////////////////////////////////////////////////
// DDE
///////////////////////////////////////////////////////////

#ifdef WIN32
  #include <wx/dde.h>
  #define wxAgaClient wxDDEClient
  #define wxAgaConnection wxDDEConnection
#else
  // Forse inutile: forse gia' fatto da wxWidgets
  #include <wx/sckipc.h>
  #define wxAgaClient wxTCPClient
  #define wxAgaConnection wxTCPConnection
#endif

static wxAgaClient* _net_client = NULL;
static unsigned long _net_conns = 0;

unsigned long aga_dde_connect(const char* host, const char* service, const char* topic)
{
  if (_net_client == NULL)
  {
    _net_client = new wxAgaClient;
    _net_conns = 0;
  }

  wxConnectionBase* conn = _net_client->MakeConnection(host, service, topic);
  if (conn != NULL)
    _net_conns++;

  return (unsigned long)conn;
}

bool aga_dde_execute(unsigned long connection, const char* msg)
{
  bool ok = false;
  if (connection != 0)
  {
    wxAgaConnection* conn = (wxAgaConnection*)connection;
    ok = conn->Execute((char*)msg, -1);
  }
  return ok;
}

bool aga_dde_terminate(unsigned long connection)
{
  bool ok = false;
  if (connection != 0 && _net_client != NULL)
  {
    wxAgaConnection* conn = (wxAgaConnection*)connection;
    ok = conn->Disconnect();
    if (ok && _net_conns > 0)
    {
      _net_conns--;
      if (_net_conns == 0)
      {
        delete _net_client;
        _net_client = NULL;
      }
    }
  }
  return ok;
}