/////////////////////////////////////////////////////////////////////////////
// Name:        utilsexec.cpp
// Purpose:     Various utilities
// Author:      Julian Smart
// Modified by:
// Created:     04/01/98
// RCS-ID:      $Id$
// Copyright:   (c) Julian Smart and Markus Holzem
// Licence:   	wxWindows license
/////////////////////////////////////////////////////////////////////////////

#ifdef __GNUG__
#pragma implementation
#endif

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/setup.h"
#include "wx/utils.h"
#include "wx/app.h"
#endif

#include "wx/msw/private.h"
#include <windows.h>

#include <ctype.h>

#ifndef __GNUWIN32__
#include <direct.h>
#include <dos.h>
#endif

#ifdef __GNUWIN32__
#include <sys/unistd.h>
#include <sys/stat.h>
#ifndef __MINGW32__
#include <std.h>
#endif

#endif

#ifdef __WIN32__
#include <io.h>

#ifndef __GNUWIN32__
#include <shellapi.h>
#endif
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef __WATCOMC__
#if !(defined(_MSC_VER) && (_MSC_VER > 800))
#include <errno.h>
#endif
#endif
#include <stdarg.h>

#define wxEXECUTE_WIN_MESSAGE 10000

struct wxExecuteData {
  HWND window;
  HINSTANCE process;
  wxProcess *handler;
  char state;
};


#ifdef __WIN32__
static DWORD wxExecuteThread(wxExecuteData *data)
{
  WaitForSingleObject(data->process, INFINITE);

  // Send an implicit message to the window
  SendMessage(data->window, wxEXECUTE_WIN_MESSAGE, 0, (LPARAM)data);

  return 0;
}
#endif


LRESULT APIENTRY _EXPORT wxExecuteWindowCbk(HWND hWnd, UINT message,
                                            WPARAM wParam, LPARAM lParam)
{
  wxExecuteData *data = (wxExecuteData *)lParam;

  if (message == wxEXECUTE_WIN_MESSAGE) {
    DestroyWindow(hWnd);
    if (data->handler)
      data->handler->OnTerminate((int)data->process);

    if (data->state)
      data->state = 0;
    else
      delete data;
  }
  return 0;
}

extern char wxPanelClassName[];

long wxExecute(const wxString& command, bool sync, wxProcess *handler)
{
  if (command == "")
    return 0;

#ifdef __WIN32__
  char * cl;
  char * argp;
  int clen;
  HINSTANCE result;
  DWORD dresult;
  HWND window;
  wxExecuteData *data;
  DWORD tid;

  // copy the command line
  clen = command.Length();
  if (!clen) return -1;
  cl = (char *) calloc( 1, 256);
  if (!cl) return -1;
  strcpy( cl, WXSTRINGCAST command);

  // isolate command and arguments
  argp = strchr( cl, ' ');
  if (argp)
    *argp++ = '\0';

#ifdef __GNUWIN32__
  result = ShellExecute((HWND) (wxTheApp->GetTopWindow() ? (HWND) wxTheApp->GetTopWindow()->GetHWND() : NULL),
     (const wchar_t) "open", (const wchar_t) cl, (const wchar_t) argp,
     (const wchar_t) NULL, SW_SHOWNORMAL);
#else
  result = ShellExecute( (HWND) (wxTheApp->GetTopWindow() ? wxTheApp->GetTopWindow()->GetHWND() : NULL),
     "open", cl, argp, NULL, SW_SHOWNORMAL);
#endif

  if (((long)result) <= 32) {
   free(cl);
   return 0;
  }

  // Alloc data
  data = new wxExecuteData;

  // Create window
  window = CreateWindow(wxPanelClassName, NULL, 0, 0, 0, 0, 0, NULL,
                        (HMENU) NULL, wxGetInstance(), 0);

  FARPROC ExecuteWindowInstance = MakeProcInstance((FARPROC) wxExecuteWindowCbk,
                                                   wxGetInstance());

  SetWindowLong(window, GWL_WNDPROC, (LONG) ExecuteWindowInstance);
  SetWindowLong(window, GWL_USERDATA, (LONG) data);

  data->process = result;
  data->window  = window;
  data->state   = sync;
  data->handler = (sync) ? NULL : handler;

  dresult = (DWORD)CreateThread(NULL, 0,
                                (LPTHREAD_START_ROUTINE)wxExecuteThread,
                                (void *)data, 0, &tid);
  if (dresult == 0) {
    wxDebugMsg("wxExecute PANIC: I can't create the waiting thread !"); 
    DestroyWindow(window);
    return (long)result;
  }

  if (!sync)
  {
    free(cl);
    return (long)result;
  }

  // waiting until command executed
  while (data->state)
    wxYield();

  free(cl);
  return 0;
#else
  long instanceID = WinExec((LPCSTR) WXSTRINGCAST command, SW_SHOW);
  if (instanceID < 32) return(0);

  if (sync) {
    int running;
    do {
      wxYield();
      running = GetModuleUsage((HANDLE)instanceID);
    } while (running);
  }
  return(instanceID);
#endif
}
