#include <xvt.h>

#include <dongle.h>
#include <execp.h> 
#include <prefix.h>
#include <recarray.h>

// @doc EXTERNAL

// @mfunc Esegue il processo
//
// @rdesc Ritorna il codice di uscita del processo (0 in caso di errore).
long TExternal_app::run(
  bool async,   // @parm Per eseguire il processo in parallelo 
  byte utente,  // @parm Permette di inserire il nome dell'utente nella riga di comando
  bool iconize) // @parm Iconizza il programma chiamante
//  ,bool show)    // @parm Mostra o nascondi il programma chiamato

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

{
  TFilename path(_path);
  
  TFilename comm_name(_path);
  const int p = comm_name.find(' ');
  if (p >= 0)
    comm_name.cut(p);
	comm_name.custom_path();
  
  TString name(comm_name.name()); 
  if (utente == 1)   // utente puo' essere 0 = No, 1 = Si, 3 = Forzatura
  {
    bool our_app = name.len() > 2;
    if (our_app && atoi(name) < 70)
    {
      our_app = isalpha(name[0]) && isalpha(name[1]) && isdigit(name[2]);
    }
    if (!our_app)
      utente = FALSE;
  }  
  if (utente)
    path << " /u" << user();
  
  // save cwd
  DIRECTORY oldir;
  xvt_fsys_get_dir(&oldir);

  const TFilename dir(comm_name.path()); 
  if (dir.not_empty())
  {
    DIRECTORY d;
    if (xvt_fsys_convert_str_to_dir((char*)(const char*)dir, &d))
      xvt_fsys_set_dir(&d);
  }                
  
  if (!async)
  {
    safely_close_closeable_isamfiles();
    if (dongle().local())
      dongle().logout();
  }

  // iconize &= !async && show;
  // _exitcode = os_execute(path, !async, iconize, show);
  _exitcode = xvt_sys_execute(path, !async, iconize);
  
  // restore cwd
  xvt_fsys_set_dir(&oldir);

  // Ignora volutamente il return code da HL_LOGIN(). Se va bene riprende il posto
  // altrimenti fa lo stesso. Infatti puo' capitare con una chiave di rete, che
  // nel lasso di tempo trascorso dalla HL_LOGOUT() dell'applicazione chiamata,
  // a questa HL_LOGIN() [approssimativamente qualche decimo di secondo], qualche altro
  // programma si inserisca, occupando magari anche l'ultimo posto disponibile.
  // Quindi se si  verificasse tale sfigatissima condizione, sicuramente
  // non ci saranno piu' posti liberi nell'HL_server: il programma comunque non
  // puo' interrompersi a meta'; ecco perche il valore di ritorno di HL_LOGIN viene
  // ignorato.
  if (!async && dongle().local())
    dongle().login();

  return _exitcode;
}

bool TExternal_app::can_run() const
{                 
  if (*prefix().name() <= '.')
    return TRUE;
  
  const TLocalisamfile test(LF_USER);
  if (test.curr().exist("PERMISSION"))
  {
    TRecord_cache utonti(LF_USER); // Non uso cache() per problemi durante conversioni
    TToken_string perm(4096, '\n'), row(80,SAFE_PIPE_CHR);
    for (TString16 u = user(); u.not_empty(); u = utonti.get(u, "GROUPNAME"))
    {
      if (utonti.already_loaded(u))
      {   
        NFCHECK("L'utente %s ha dei permessi ricorsivi", (const char*)u);
        break;
      }
      perm = utonti.get(u, "PERMISSION");
      if (!perm.blank())
      {
        FOR_EACH_TOKEN(perm, tok)
        {
          row = tok;
          if (_path == row.get(0))   // Il nome corrisponde
          {
            if (*row.get(1) == 'N')
              return FALSE;
          }
        }
      }
    } 
  }  
  return TRUE;
}
 
TExternal_app::TExternal_app(const char* p)
             : _path(p), _exitcode(0)
{
}