#include <xvt.h>

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

// Il programma attuale NON e' ne' ba0 ne ba1 e si usa il menu in stile Outlook?
static bool is_outlook_menu_chain()
{
  const TFilename n = __argv[0];
  const TString& app = n.name_only();
  if (app.match("ba[0,1]", true) != 0)
    return false;
  return ini_get_int(CONFIG_GUI, "Colors", "TreeView") == 3;
}

// @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

  // @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);

  //se c'e' - o / tronca il nome allo spazio precedente
  const int pm = comm_name.find(" -");	//c'e' un - nella stringa?
  const int ps = comm_name.find(" /");	//c'e' un / nella stringa?
  int params = -1;
  if (pm > 0 && (pm < ps || ps <= 0))	
    params = pm; else
  if (ps > 0)
    params = ps;
  if (params > 0)
    comm_name.cut(params); 
	if (*comm_name.ext() == '\0')	// se non c'e' estensione ci mette .exe (sono programmi)
    comm_name.ext("exe");

	const bool found = comm_name.custom_path();	//cerca il file in custom o in locale
  if (utente == 1)   // utente puo' essere 0 = No, 1 = Si, 3 = Forzatura
  {
    const TString& name = comm_name.name_only(); 
    bool our_app = name.len() > 2;
    if (our_app && atoi(name) < 70)
    {
      our_app = (isalpha(name[0]) && isalpha(name[1])) && 
                (isdigit(name[2]) || name.ends_with("cnv"));
    }
    if (!our_app)  // Non e' un programma di campo per cui ...
      utente = 0;  // ... non aggiungo il codice utente al comando
  }  

  if (found)
  {
    path = comm_name;
    if (params > 0)
      path << _path.mid(params);
  }

  if (utente && path.find(" /u") < 0)
    path << " /u" << user();
  
  // save cwd
  DIRECTORY oldir; xvt_fsys_get_dir(&oldir);

  if (!utente && found) // cambio directory se eseguo un programma estero
  {
    TFilename dir(path.path()); 
    if (dir.full())
    {
      DIRECTORY d;
      if (xvt_fsys_convert_str_to_dir(dir, &d))
        xvt_fsys_set_dir(&d);
    }                
  }
  
  TString256 old_title;      // Vecchio titolo della finestra principale
  bool close_all = false;    // Chiudi tutti i file in caso di manutenzione

  if (!async && utente)
  {
    if (dongle().local())    // Rilascio la chiave il prima possibile
      dongle().logout();

    close_all = _path.starts_with("ba1 -0") && prefix_valid();
		if (close_all)	//se lancia la gestione archivi forza la chiusura dei files e pure dei tracciati!
			prefix().set("");
		else
			safely_close_closeable_isamfiles();

    // Programma normale (non menu) che chiama "collega"
    if (iconize && is_outlook_menu_chain())
    {
      xvt_vobj_get_title(TASK_WIN, old_title.get_buffer(), old_title.size());
      xvt_vobj_set_title(TASK_WIN, __MAGIC_CAPTION__);
      iconize = false;
    }
  }

  _exitcode = xvt_sys_execute(path, !async, iconize);

  if (old_title.full()) // Rimetto le cose a posto
    xvt_vobj_set_title(TASK_WIN, old_title);
  
  // 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 && utente)
	{
		if (dongle().local())
			dongle().login();

		if (close_all)	//se lancia la gestione archivi forza la riapertura dei files e pure dei tracciati!
			prefix().set("DEF");					//..li aveva chiusi qualche riga sopra
	}

  return _exitcode;
}

bool TExternal_app::can_run() const
{                 
  if (*prefix().name() <= '.')
    return true;

  const TString& usr = user();
  if (usr.blank() || usr == dongle().administrator())
    return true;

  const TString_array& uag = user_and_groups();
  TToken_string perm(255, '\n'), row(80,SAFE_PIPE_CHR);
  FOR_EACH_ARRAY_ROW(uag, i, rec)
  {
    perm = rec->after(rec->separator());
    if (perm.full())
    {
      FOR_EACH_TOKEN(perm, tok)
      {
        row = tok;
        if (_path.compare(row.get(0), -1, true) == 0 && row.get_char(1) == 'N')
          return false;
      }
    }
  }  
  return true;
}
 
TExternal_app::TExternal_app(const char* p)
             : _path(p), _exitcode(0)
{
}