#include <stdio.h>
#include <xvt.h>

#if XVT_OS == XVT_OS_SCOUNIX
#include <sys/fcntl.h>
#include <sys/wait.h>
#endif

#if XVT_OS == XVT_OS_WIN
#define STRICT
#include <windows.h>
#include <toolhelp.h>
#endif

#include <applicat.h>
#include <execp.h> 
#include <prefix.h>
#include <utility.h>
#include <window.h>

// @doc EXTERNAL

// @mfunc Controlla se il processo puo' essere eseguito
//
// @rdesc Ritorna i seguenti valori:
//
// @flag TRUE | Se l'applicazione puo' essere eseguita
// @flag FALSE | Se l'applicazione non puo' essere eseguita
bool TExternal_app::can_run() const

// @comm Se si opera sotto Windows si controlla se vi sono risorse necessarie
//       per l'esecuzione del processo, altrimenti viene tornato sempre TRUE.
{                    
#if XVT_OS == XVT_OS_WIN
  const TFixed_string p(_path);           
  const bool big = p.find("cg0") == 0 && p.right(2) == "-1";
  const int richieste = big ? 50 : 15;
  const int libere = GetFreeSystemResources(GFSR_SYSTEMRESOURCES);
  return libere >= richieste;
#else
  return TRUE;
#endif
}

// @mfunc Esegue il processo
int TExternal_app::run(
  bool async,  // @parm Per eseguire il processo in parallelo (default FALSE)
  bool utente) // @parm Permette di inserire il nome dell'utente nella riga 
  //       di comando(default TRUE)

  // @comm Se <p asyn> e' FALSE aspetta che termini il processo in esecuzione prima di iniziare il nuovo

{
  TString256 path(_path);                                  
  
  if (utente)
#if XVT_OS == XVT_OS_WIN
    path << " /u" << user();
#else
  path << " -u" << user();
#endif    
  
  _error = 0;
  _exitcode =  0;

  // save cwd
  xvt_fsys_save_dir();

#if XVT_OS == XVT_OS_WIN
  if (can_run())
  {                
    TFilename dir(_path); 
    
    dir = dir.path();
    if (dir.not_empty())
    {
      DIRECTORY d;
      
      if (xvt_fsys_convert_str_to_dir((char *) (const char *) dir, &d))
        xvt_fsys_set_dir(&d);
    }
    main_app().begin_wait();
    _exitcode = WinExec((char*)(const char*)path, SW_SHOW);

    for (int maxtry = 5 ; maxtry > 0 && _exitcode == 16; maxtry--)
    {
      int spc = path.find(' ');
      
      if (spc < 0)
        spc = path.len();
      TFilename name(path.left(spc)), oldname(name);
      
      name.ext("");
      if (isdigit(name.right(1)[0]))
        name << 'a';
      else
        name[name.len() - 1]++;
      name.ext("exe");
      if (!fexist(name))
      {       
        oldname.ext("exe");
        fcopy(oldname, name);
      }                      
      name << path.mid(spc);
      path = name;
      _exitcode = WinExec((char*)(const char*)path, SW_SHOW);
    }     
    if (_exitcode >= 32)
    {        
      if (!async)
      {                            
        TTemp_window tw(TASK_WIN);
        if (utente) 
        {
          tw.iconize();
          tw.deactivate();
        }  
        
        HTASK child = NULL;
        TASKENTRY te; te.dwSize = sizeof(TASKENTRY); 
        for (bool ok = TaskFirst(&te); ok; ok = TaskNext(&te))
          if (te.hInst == (HINSTANCE)_exitcode)
          {
            child = te.hTask;
            break;
          }  
        
        // Warning! child could be NULL if you run that beast called Foxpro        
        
        main_app().wait_for((word)child); 
        for (byte i = 0; main_app().waiting() == (word)child; i++)
        {
          if (i == 0 && ok && TaskFindHandle(&te, child) == FALSE) 
            break;
          xvt_app_process_pending_events();
        }
        
        if (utente) 
        {
          tw.maximize();
          tw.activate();             
        }  
      }
      xvt_statbar_refresh();
    }  
    main_app().end_wait();
  } else _exitcode = 8;

  switch (_exitcode)
  {
  case 0:          
  case 8:
    error_box("Risorse insufficienti per eseguire '%s'", (const char*)_path); break;
  case 2:
  case 3:
    error_box("Impossibile trovare '%s'", (const char*)_path); break;
  case 16:
    error_box("'%s' e' gia' in esecuzione", (const char*)_path); break;
  default:
    if (_exitcode < 32)
      error_box("Impossibile eseguire '%s':\nErrore %d", (const char*)_path, _exitcode); 
    else
      _exitcode = 0;  
    break;
  }  
#else

  switch (fork())
  {
  case -1:
    _error = errno;
    _exitcode = -1;
    break;
  case 0:
    const char* s = strdup(path);
    char* p = strchr(s, ' ');
    if (p) *p = '\0';
    const char* pathn = strdup(s);
    const char* args[21];
    int i = 0;
    args[i++] = pathn;
    while ((i < 20) && (p))
    {
      s = p + 1;
      p = strchr(s, ' ');
      if (p) *p = '\0';
      args[i++] = strdup(s);
    }
    args[i] = NULL;
    for (i = 3; i < _NFILE; i++) fcntl(i,F_SETFD,1);
    // execvp( path, NULL);
    execvp ( pathn , args );
    exit ( -1 );
  default:
    if(wait(&_exitcode) == -1)
    {
      error_box("Impossibile eseguire '%s':\nErrore %d", (const char*)_path, _exitcode);
      _exitcode = -1;
    }
    else _exitcode = _exitcode >> 8;
    break;
  }
  _error = errno;
  xvt_app_escape(XVT_ESC_CH_REFRESH);

#endif

  // restore cwd
  xvt_fsys_restore_dir();

  // update counts
  if (_exitcode == 0)
    _count++;
  return _exitcode;
}

TExternal_app::TExternal_app(const char* p)
{
  _path =  p;
  _count = 0;
  _error = 0;
  _exitcode =  0;
}