{xDEFINE CONLOG}
unit uFormFileManager;

{$IFDEF FPC}
  {$MODE Delphi}
{$ENDIF}

interface

uses
{$IFDEF WINDOWS}
  Windows, Messages, Variants, Dialogs, Forms,
{$ELSE}
  uWinMsgs, ERRORS, baseunix, unix,
{$ENDIF}
  SysUtils, Classes, ubuffrw, {uAuxiliares,}
  uMsgsFileManager, uFichasFileManager, MD5,
  winLinuxUtils,
{$IFDEF NETTOPOS_DLL}
  uimportnettopos
{$ELSE}
  unettopos,
  unettopostypes,
  uglobsharedmem
{$ENDIF};

const
  timeOutComs_ms = 2000;

type
  TProcMsgNotificacion= procedure(msg : String);

{$IFDEF LINUX}
  TFileManager = class(TComponent)
{$ELSE}
  TFileManager = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
{$ENDIF}
  private
    maxBufferSize: Cardinal;
    archivosAbiertos: TList {of TFichaArchivo};
    ultimoHnd: Cardinal;
    ultimoError: Integer;

    procedure msgp_OpenWrite(var Msg: TMessage); message MSGP_OPENWRITE;
    procedure msgp_OpenRead(var Msg: TMessage); message MSGP_OPENREAD;
    procedure msgp_Write(var Msg: TMessage); message MSGP_WRITE;
    procedure msgp_Read(var Msg: TMessage); message MSGP_READ;
    procedure msgp_CloseFile(var Msg: TMessage); message MSGP_CLOSEFILE;
    procedure msgp_FileExists(var Msg: TMessage); message MSGP_FILEEXISTS;
    procedure msgp_SameFileExists(var Msg: TMessage); message MSGP_SAMEFILEEXISTS;

    function levantarComunicado(idComunicado: Cardinal; pf: PFichaComunicado; var datos: Pointer): Cardinal;
    function comunicarError(xidNodoDestino, xidDestino : Cardinal; codError: Integer) : Cardinal;
    procedure invertirComunicado(var comunicado: TFichaComunicado);

    function indiceFicha(hnd : Cardinal): Integer;
  public
{$IFDEF LINUX}
 	  recolectar: boolean;
    constructor Create(AOwner: TComponent); reintroduce;
    procedure Free; virtual;
{$ENDIF}  
  end;

var
  FileManager: TFileManager;

implementation

uses
  uconstantes_nettopos;

{$IFNDEF LINUX}
{$IFNDEF FPC}
  {$R *.dfm}
{$ELSE}
  {$R *.lfm}
{$ENDIF}
{$ELSE}
var
  SActionRec: SigActionRec;

{ Procedimientos agregados para el manejo de seņales
del sistema.}

procedure Handler(Sig : Integer); cdecl;
begin
//  writeln('--estoy en el Handler---', GetThreadId);
  case Sig of
    SIGALRM:
    begin
      writeln('SIGALRM');
//      umensajesretardados.tic_Barrer;
      exit;
    end;
    SIGINT, SIGTERM :
    begin
      writeln('--- recibi SIGINT o SIGTERM --- pongo recolectar=false ' );
      FileManager.recolectar:= false;
      exit;
    end;
    //  SIGIO: writeln('SIGIO');
  end; { case }
end;

procedure InstallHandlers;
begin
//  writeln('Instalo Handlers, ThreadId= ', GetThreadId);
  with SActionRec do
  begin
	  sa_handler:= SigActionHandler(@Handler);
  	fpsigemptyset(sa_mask);
	  sa_flags:= 0;
  end; { with }
	fpsigaction(SIGINT, @SActionRec, nil);
	fpsigaction(SIGTERM, @SActionRec, nil);
	fpsigaction(SIGALRM, @SActionRec, nil);
//   sigaction(SIGIO, @SActionRec, nil );
//  umensajesretardados.IniciarBarridos;
end;
{$ENDIF}

{$IFDEF CONLOG}
procedure conlog( s: string; const msg: TMessage );
begin
  writeln(now(), 'clog> ('+s+'), wp:'+IntToStr( msg.wparam )+', lp: '+IntToStr( msg.lparam ) );
end;
{$ENDIF}

procedure subirDirectorio(var path: String);
var
  i, posUltimaBarra: Integer;
begin
  posUltimaBarra:= MAXINT;
  //el -2 es para evitar directorios con la barra al final
  //               01234
  // si el path es a:\b\ arranca de la pos 3 y busca la ultima barra
  //      0123
  //si es a:\l arranca de la pos 2 y frena directamente
  for i:= length(path) - 2 downto 0 do
  begin
    if path[i] = DirectorySeparator then
    begin
      posUltimaBarra:= i;
      break
    end
  end;
  path:= copy(path, 0, posUltimaBarra);
end;

procedure crearDirectorios(nomArch: String);
var
  tmp: String;
  k: Integer;
  base: String;
begin
  base:= '';
  k:= pos(DirectorySeparator, nomArch);
  while k <> 0 do
  begin
    tmp:= Copy(nomArch, 0, k - 1);
    nomArch:= Copy(nomArch, k+1, Length(nomArch) - k);
    k:= pos(DirectorySeparator, nomArch);
    base:= base + tmp + DirectorySeparator;
    if not DirectoryExists(base) then
      MkDir(base);
  end;
end;

{$IFDEF LINUX}
constructor TFileManager.Create(AOwner: TComponent);
{$ELSE}
procedure TFileManager.FormCreate(Sender: TObject);
{$ENDIF}
begin
{$IFDEF LINUX}
  inherited Create(AOwner);
  installHandlers;
  recolectar:= false;
{$ENDIF}
  inicializar;
  maxBufferSize:= RecommendedBufferSize;
{$IFDEF WINDOWS}
  registrarAplicacion(uMsgsFileManager.AppName, handle);
{$ELSE}
  registrarAplicacion(uMsgsFileManager.AppName, fpGetPid);
{$ENDIF}
  ultimoHnd:= 1;
  archivosAbiertos:= TList.Create;
  ultimoError:= 0;
  if idAplicYo = 0 then
  begin
    logError('ERROR: ' + getNetTopos_StrError(getUltimoError));
    writeln('ERROR: ' + uconstantes_nettopos.getNetTopos_StrError(getUltimoError));
{$IFDEF WINDOWS}
    PostQuitMessage(0);
{$ENDIF}
  end
  else
  begin
    writeln('FileManager.idAplic= ', idAplicYo);
{$IFDEF LINUX}
    recolectar:= true;
{$ENDIF}
  end;
end;

{$IFDEF LINUX}
procedure TFileManager.Free;
{$ELSE}
procedure TFileManager.FormDestroy(Sender: TObject);
{$ENDIF}
var
  i: Integer;
begin
  for i:= 0 to archivosAbiertos.Count - 1 do
    TFichaArchivo(archivosAbiertos[i]).Free;
  archivosAbiertos.Free;
  if idAplicYo > 0 then
    desregistrarAplicacion(idAplicYo);
  finalizar;
end;

procedure TFileManager.msgp_OpenWrite(var Msg: TMessage);
var
  nomArch: String;
  res: boolean;

  comunicado: TFichaComunicado;
  nuevaFicha: TFichaArchivo;
  datosSalientes: PRespuesta;
  datosEntrantes: PPregunta;
begin
{$IFDEF CONLOG}
  conlog('OpenWrite...begin', msg);
{$ENDIF}
  if levantarComunicado(msg.WParam, @comunicado, Pointer(datosEntrantes)) <> 0 then
  begin
    nomArch:= PChar(datosEntrantes);
    toOSBarraDirs(nomArch);
    toNetoposPath(nomArch);

    ForceDirectories(ExtractFilePath(nomArch));
    //crearDirectorios(nomArch);
    writeln('TFileManager.msgp_OpenWrite: Escribiendo archivo ' + nomArch);

    FreeMem(datosEntrantes, comunicado.nBytesDatos);

    invertirComunicado(comunicado);
    comunicado.codigoMsg:= MSGR_OPENWRITE;
    comunicado.nBytesDatos:= SizeOf(Cardinal) + SizeOf(Integer);
    GetMem(datosSalientes, comunicado.nBytesDatos);

    nuevaFicha:= TFichaArchivo.CreateWrite(ultimoHnd, nomArch, res);
    if res then
    begin
      inc(ultimoHnd);
      archivosAbiertos.Add(nuevaFicha);
      datosSalientes^.resultado:= nuevaFicha.hnd;
      datosSalientes^.msj_Error:= 0;
    end
    else
    begin
      datosSalientes^.resultado:= 0;
      datosSalientes^.msj_Error:= ERROR_NO_SE_PUDO_ASIGNAR_EL_ARCHIVO_PARA_ESCRITURA;
    end;
    comunicar(@comunicado, datosSalientes, timeOutComs_ms);
    FreeMem(datosSalientes, comunicado.nBytesDatos);
  end
  else if ultimoError = ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL then
  begin
    comunicarError(comunicado.idNodoOrigen, comunicado.idOrigen, ultimoError);
    FreeMem(datosEntrantes, comunicado.nBytesDatos);
    logError('FormFileManager.msgp_OpenWrite Error: ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL');
  end
  else if ultimoError = ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL then
  begin
    logError('FormFileManager.msgp_OpenWrite Error: ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL');
  end;
{$IFDEF CONLOG}
    conlog('OpenWrite...end:', Msg);
{$ENDIF}
end;

procedure TFileManager.msgp_OpenRead(var Msg: TMessage);
var
  nomArch: String;
  res: boolean;

  comunicado: TFichaComunicado;
  nuevaFicha: TFichaArchivo;
  datosSalientes: PRespuesta;
  datosEntrantes: PPregunta;
begin
{$IFDEF CONLOG}
  conlog('OpenRead...begin', Msg);
{$ENDIF}
  if levantarComunicado(msg.WParam, @comunicado, Pointer(datosEntrantes)) <> 0 then
  begin
    nomArch:= PChar(datosEntrantes);
    toOSBarraDirs(nomArch);    
    toNetoposPath(nomArch);

    writeln('TFileManager.msgp_OpenRead: Leyendo archivo ' + nomArch);
    FreeMem(datosEntrantes, comunicado.nBytesDatos);

    invertirComunicado(comunicado);
    comunicado.codigoMsg:= MSGR_OPENREAD;
    comunicado.nBytesDatos:= SizeOf(Cardinal) + SizeOf(Integer);
    GetMem(datosSalientes, comunicado.nBytesDatos);

    nuevaFicha:= TFichaArchivo.CreateRead(ultimoHnd, nomArch, res);
    if res then
    begin
      inc(ultimoHnd);
      archivosAbiertos.Add(nuevaFicha);
      datosSalientes^.resultado:= nuevaFicha.hnd;
      datosSalientes^.msj_Error:= 0;
    end
    else
    begin
      datosSalientes^.resultado:= 0;
      datosSalientes^.msj_Error:= ERROR_NO_SE_PUDO_ASIGNAR_EL_ARCHIVO_PARA_ESCRITURA;
    end;
    comunicar(@comunicado, datosSalientes, timeOutComs_ms);
    FreeMem(datosSalientes, comunicado.nBytesDatos);
  end
  else if ultimoError = ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL then
  begin
    comunicarError(comunicado.idNodoOrigen, comunicado.idOrigen, ultimoError);
    FreeMem(datosEntrantes, comunicado.nBytesDatos);
    logError('FormFileManager.msgp_OpenRead Error: ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL');
  end
  else if ultimoError = ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL then
  begin
    logError('FormFileManager.msgp_OpenRead Error: ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL');
  end;
{$IFDEF CONLOG}
    conlog('OpenRead...end:', Msg);
{$ENDIF}
end;

procedure TFileManager.msgp_Write(var Msg: TMessage);
var
  iFicha: Integer;

  nDatosEscritos: Integer;
  comunicado: TFichaComunicado;
  Ficha: TFichaArchivo;
  datosSalientes: PRespuesta;
  datosEntrantes: PPregunta;
begin
{$IFDEF CONLOG}
  conlog('Write...begin', Msg);
{$ENDIF}
  if levantarComunicado(msg.WParam, @comunicado, Pointer(datosEntrantes)) <> 0 then
  begin
    iFicha:= indiceFicha(datosEntrantes^.handle);
    invertirComunicado(comunicado);
    comunicado.codigoMsg:= MSGR_WRITE;

    if iFicha <> -1 then
    begin
      ficha:= archivosAbiertos[iFicha];
      if ficha.EscribirDatos(@datosEntrantes^.datos[0], datosEntrantes^.NBytesDatos, nDatosEscritos) then
      begin
        FreeMem(datosEntrantes, comunicado.nBytesDatos);
        comunicado.nBytesDatos:= 2 * SizeOf(Cardinal) + 2 * SizeOf(Integer);
        GetMem(datosSalientes, comunicado.nBytesDatos);
        datosSalientes^.resultado:= ficha.hnd;
        datosSalientes^.msj_Error:= 0;
        datosSalientes^.NBytesDatos:= SizeOf(Integer);
        datosSalientes^.datos:= Pointer(nDatosEscritos);
      end
      else
      begin
        FreeMem(datosEntrantes, comunicado.nBytesDatos);
        comunicado.nBytesDatos:= SizeOf(Cardinal) + SizeOf(Integer);
        GetMem(datosSalientes, comunicado.nBytesDatos);
        datosSalientes^.resultado:= 0;
        datosSalientes^.msj_Error:= ficha.ultimoError;
      end;
    end
    else
    begin
      FreeMem(datosEntrantes, comunicado.nBytesDatos);
      comunicado.nBytesDatos:= SizeOf(Cardinal) + SizeOf(Integer);
      GetMem(datosSalientes, comunicado.nBytesDatos);
      datosSalientes^.resultado:= 0;
      datosSalientes^.msj_Error:= ERROR_NO_SE_ASIGNO_EL_ARCHIVO;
    end;

    comunicar(@comunicado, datosSalientes, timeOutComs_ms);
    FreeMem(datosSalientes, comunicado.nBytesDatos);
  end
  else if ultimoError = ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL then
  begin
    comunicarError(comunicado.idNodoOrigen, comunicado.idOrigen, ultimoError);
    FreeMem(datosEntrantes, comunicado.nBytesDatos);
    logError('FormFileManager.msgp_Write Error: ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL');
  end
  else if ultimoError = ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL then
  begin
    logError('FormFileManager.msgp_Write Error: ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL');
  end;
{$IFDEF CONLOG}
    conlog('Write...end:', Msg);
{$ENDIF}
end;

procedure TFileManager.msgp_Read(var Msg: TMessage);
var
  iFicha: Integer;
  datosLeidos: Cardinal;

  maxNDatosALeer: Integer;
  comunicado: TFichaComunicado;
  Ficha: TFichaArchivo;
  datosSalientes: PRespuesta;
  datosEntrantes: PPregunta;
begin
{$IFDEF CONLOG}
  conlog('Read...begin', Msg);
{$ENDIF}
  if levantarComunicado(msg.WParam, @comunicado, Pointer(datosEntrantes)) <> 0 then
  begin
    iFicha:= indiceFicha(datosEntrantes^.handle);
    FreeMem(datosEntrantes, comunicado.nBytesDatos);
    invertirComunicado(comunicado);
    comunicado.codigoMsg:= MSGR_READ;

    if iFicha <> -1 then
    begin
      ficha:= archivosAbiertos[iFicha];
      comunicado.nBytesDatos:= maxBufferSize;
      GetMem(datosSalientes, comunicado.nBytesDatos);
      maxNDatosALeer:= comunicado.nBytesDatos - 2 * sizeOf(Cardinal) - sizeOf(Integer);
      if ficha.LeerDatos(datosSalientes^.datos, maxNDatosALeer, datosLeidos) then
      begin
        comunicado.nBytesDatos:= 2 * SizeOf(Cardinal) + SizeOf(Integer) + datosLeidos;
  //      GetMem(datosSalientes, com.comunicadoSaliente.nBytesDatos);
        datosSalientes^.resultado:= ficha.hnd;
        datosSalientes^.msj_Error:= 0;
        datosSalientes^.NBytesDatos:= datosLeidos;
      end
      else
      begin
        FreeMem(datosSalientes, comunicado.nBytesDatos);
        comunicado.nBytesDatos:= SizeOf(Cardinal) + SizeOf(Integer);
        GetMem(datosSalientes, comunicado.nBytesDatos);
        datosSalientes^.resultado:= 0;
        datosSalientes^.msj_Error:= ficha.ultimoError;
      end;
    end
    else
    begin//No encontre la ficha, le respondo al que me pidiķ
      comunicado.nBytesDatos:= SizeOf(Cardinal) + SizeOf(Integer);
      GetMem(datosSalientes, comunicado.nBytesDatos);
      datosSalientes^.resultado:= 0;
      datosSalientes^.msj_Error:= ERROR_NO_SE_ASIGNO_EL_ARCHIVO;
    end;

    comunicar(@comunicado, datosSalientes, timeOutComs_ms);
    FreeMem(datosSalientes, comunicado.nBytesDatos);
  end
  else if ultimoError = ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL then
  begin
    comunicarError(comunicado.idNodoOrigen, comunicado.idOrigen, ultimoError);
    FreeMem(datosEntrantes, comunicado.nBytesDatos);
    logError('FormFileManager.msgp_Read Error: ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL');
  end
  else if ultimoError = ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL then
  begin
    logError('FormFileManager.msgp_Read Error: ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL');
  end;
{$IFDEF CONLOG}
    conlog('Read...end:', Msg);
{$ENDIF}
end;

procedure TFileManager.msgp_CloseFile(var Msg: TMessage);
var
  iFicha: Integer;

  comunicado: TFichaComunicado;
  Ficha: TFichaArchivo;
  datosSalientes: PRespuesta;
  datosEntrantes: PPregunta;
begin
{$IFDEF CONLOG}
  conlog('CloseFile...begin', Msg);
{$ENDIF}
  if levantarComunicado(msg.WParam, @comunicado, Pointer(datosEntrantes)) <> 0 then
  begin
    iFicha:= indiceFicha(datosEntrantes^.handle);
    FreeMem(datosEntrantes, comunicado.nBytesDatos);
    invertirComunicado(comunicado);
    comunicado.codigoMsg:= MSGR_CLOSEFILE;
    comunicado.nBytesDatos:= sizeOf(Cardinal) + sizeOf(Integer);
    GetMem(datosSalientes, comunicado.nBytesDatos);

    if iFicha <> -1 then
    begin
      ficha:= archivosAbiertos[iFicha];
      if ficha.CerrarArchivo then
      begin
        datosSalientes^.resultado:= ficha.hnd;
        datosSalientes^.msj_Error:= 0;
        ficha.Free;
        archivosAbiertos.delete(iFicha);
      end
      else
      begin
        datosSalientes^.resultado:= 0;
        datosSalientes^.msj_Error:= ficha.ultimoError;
      end;
    end
    else
    begin
      datosSalientes^.resultado:= 0;
      datosSalientes^.msj_Error:= ERROR_NO_SE_ASIGNO_EL_ARCHIVO;
    end;
    comunicar(@comunicado, datosSalientes, timeOutComs_ms);
    FreeMem(datosSalientes, comunicado.nBytesDatos);
  end
  else if ultimoError = ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL then
  begin
    comunicarError(comunicado.idNodoOrigen, comunicado.idOrigen, ultimoError);
    FreeMem(datosEntrantes, comunicado.nBytesDatos);
    logError('FormFileManager.msgp_CloseFile Error: ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL');
  end
  else if ultimoError = ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL then
  begin
    logError('FormFileManager.msgp_CloseFile Error: ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL');
  end;
{$IFDEF CONLOG}
    conlog('CloseFile...end:', Msg);
{$ENDIF}
end;

procedure TFileManager.msgp_FileExists(var Msg: TMessage);
var
  nomArch: String;

  comunicado: TFichaComunicado;
  datosSalientes: PRespuesta;
  datosEntrantes: PPregunta;
begin
{$IFDEF CONLOG}
  conlog('FileExists...begin', Msg);
{$ENDIF}
  if levantarComunicado(msg.WParam, @comunicado, Pointer(datosEntrantes)) <> 0 then
  begin
    nomArch:= PChar(datosEntrantes);
    toOSBarraDirs(nomArch);
    toNetoposPath(nomArch);
    FreeMem(datosEntrantes, comunicado.nBytesDatos);

    invertirComunicado(comunicado);
    comunicado.codigoMsg:= MSGR_FILEEXISTS;
    comunicado.nBytesDatos:= SizeOf(Cardinal);
    GetMem(datosSalientes, comunicado.nBytesDatos);

    if FileExists(nomArch) then
      datosSalientes^.resultado:= 1
    else
      datosSalientes^.resultado:= 0;
    comunicar(@comunicado, datosSalientes, timeOutComs_ms);
    FreeMem(datosSalientes, comunicado.nBytesDatos);
  end
  else if ultimoError = ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL then
  begin
    comunicarError(comunicado.idNodoOrigen, comunicado.idOrigen, ultimoError);
    FreeMem(datosEntrantes, comunicado.nBytesDatos);
    logError('FormFileManager.msgp_OpenRead Error: ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL');
  end
  else if ultimoError = ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL then
  begin
    logError('FormFileManager.msgp_OpenRead Error: ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL');
  end;
{$IFDEF CONLOG}
  conlog('FileExists...end:', Msg);
{$ENDIF}
end;

procedure TFileManager.msgp_SameFileExists(var Msg: TMessage);
var
  nomArch, md5: String;

  comunicado: TFichaComunicado;
  datosEntrantes: TBuffReader;
  datosSalientes: TBuffWriter;
  resultado: Cardinal;
  codError: Integer;
  md5Rec: TMD5Digest;
begin
{$IFDEF CONLOG}
  conlog('SameFileExists...begin', Msg);
{$ENDIF}
  if leerFichaComunicado(msg.WParam, @comunicado) > 0 then
  begin
    datosEntrantes:= TBuffReader.Create(comunicado.pdatos, comunicado.nBytesDatos);
    datosEntrantes.xString(nomArch);
    datosEntrantes.xString(md5);
    datosEntrantes.Free;
    if levantarDatosComunicado(msg.WParam, NIL, 0) <> 0 then
    begin
      toOSBarraDirs(nomArch);
      toNetoposPath(nomArch);
      invertirComunicado(comunicado);
      comunicado.codigoMsg:= MSGR_SAMEFILEEXISTS;
      comunicado.nBytesDatos:= SizeOf(resultado) + SizeOf(codError);
      datosSalientes:= TBuffWriter.Create(comunicado.nBytesDatos);

      if FileExists(nomArch) then
      begin
        md5Rec:= MD5File(nomArch);
        if md5 = MD5DigestToStr(md5Rec) then
        begin
          resultado:= 1;
          codError:= 0;
        end
        else
        begin
          resultado:= 0;
          codError:= -1;
        end;
      end
      else
      begin
        resultado:= 0;
        codError:= 0;
      end;
      datosSalientes.xCardinal(resultado);
      datosSalientes.xInteger(codError);
      comunicar(@comunicado, datosSalientes.pBuff, timeOutComs_ms);
      datosSalientes.Free;
    end
    else
      if ultimoError = ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL then
      begin
        comunicarError(comunicado.idNodoOrigen, comunicado.idOrigen, ultimoError);
        logError('FormFileManager.msgp_OpenRead Error: ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL');
      end
  end
  else if ultimoError = ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL then
    logError('FormFileManager.msgp_OpenRead Error: ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL');
{$IFDEF CONLOG}
  conlog('SameFileExists...end:', Msg);
{$ENDIF}
end;

function TFileManager.levantarComunicado(idComunicado: Cardinal; pf: PFichaComunicado; var datos: Pointer): Cardinal;
begin
  if leerFichaComunicado(idComunicado, pf) <> 0 then
  begin
    GetMem(datos, pf^.nBytesDatos);
    if levantarDatosComunicado(idComunicado, datos, pf^.nBytesDatos) <> 0 then
      result:= idComunicado
    else
    begin
      ultimoError:= ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL;
      result:= 0;
    end;
  end
  else
  begin
    ultimoError:= ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL;
    result:= 0;
  end;
end;

function TFileManager.indiceFicha(hnd : Cardinal): Integer;
var
  i: Integer;
  res: Integer;
begin
  res:= -1;
  for i := 0 to archivosAbiertos.Count - 1 do
    if (TFichaArchivo(archivosAbiertos[i]).hnd = hnd) then
    begin
      res:= i;
      break;
    end;
  result:= res;
end;

function TFileManager.comunicarError(xidNodoDestino, xidDestino : Cardinal; codError: Integer) : Cardinal;
var
  comunicadoSaliente: TFichaComunicado;
  datosSalientes: PRespuesta;
begin
  with comunicadoSaliente do
  begin
    idNodoOrigen:= 0;
    idOrigen:= idAplicYo;
    idNodoDestino:= xidNodoDestino;
    idDestino:= xidDestino;
    NBytesDatos:= sizeOf(Integer) + SizeOf(Cardinal);
    GetMem(datosSalientes, nBytesDatos);
    codigoMsg:= uMsgsFileManager.MSGR_OPENREAD;
  end;
  datosSalientes.resultado:= 0;
  datosSalientes.msj_Error:= codError;
  result:= comunicar(@comunicadoSaliente, datosSalientes, timeOutComs_ms);
  FreeMem(datosSalientes, comunicadoSaliente.nBytesDatos);
end;

procedure TFileManager.invertirComunicado(var comunicado: TFichaComunicado);
var
  aux_Swap: Cardinal;
begin
  aux_Swap:= comunicado.idNodoOrigen;
  comunicado.idNodoOrigen:= comunicado.idNodoDestino;
  comunicado.idNodoDestino:= aux_Swap;

  aux_Swap:= comunicado.idOrigen;
  comunicado.idOrigen:= comunicado.idDestino;
  comunicado.idDestino:= aux_Swap;
end;

end.
