unit uFileHandler;

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

interface

uses
  ubuffrw, xMatDefs, uMsgsFileManager, sysutils, uconstantes_nettopos, MD5, classes,
{$IFDEF NETTOPOS_DLL}
  uimportnettopos,
{$ELSE}
  unettopos,
  unettopostypes,
  uglobsharedmem
{$ENDIF};

const
  tOutOpenWrite = 2000;
  TOutOpenRead = 2000;
  tOutClose = 2000;
  tOutFileExists = 2000;
  tOutWritePorByte = 0.1;

type
  TFileHandler = class
    public
      Constructor Create;
      function enviarArchivo(idNodo: Cardinal; nomArchivo: String): Integer; overload;
      //Envia el archivo indicado a los nodos indicados
      //El path del archivo se tomara desde uconstantes.dirbase, si nomArchivo
      //no incluye uconstantes.dirbase al comienzo este se le agrega
      //El resultado es un arreglo de cardinals con el resultado para cada nodo
      //Si es 1 el archivo fue transferido correctamente
      //Sino si es:
      //-1  No se encontro el fileManager en el nodo
      //-2  El file manager respondió 0 al MSGP_OPEN_WRITE
      //-3  No se pudo levantar datos comunicado al pedir MSGP_OPEN_WRITE
      //-4  No se pudo leer ficha comunicado al pedir MSGP_OPEN_WRITE
      //-5  No se pudo comunicarTS al pedir MSGP_OPEN_WRITE
      //-6  El file manager respondió 0 al MSGP_WRITE
      //-7  No se pudo levantar datos comunicado al pedir MSGP_WRITE
      //-8  No se pudo leer ficha comunicado al pedir MSGP_WRITE
      //-9  No se pudo comunicarTS al pedir MSGP_WRITE
      //-10  El file manager respondió 0 al MSGP_CLOSEFILE
      //-11  No se pudo levantar datos comunicado al pedir MSGP_CLOSEFILE
      //-12  No se pudo leer ficha comunicado al pedir MSGP_CLOSEFILE
      //-13  No se pudo comunicarTS al pedir MSGP_CLOSEFILE
      function enviarArchivo(idNodos: TDAofNCardinal; nomArchivo: String): TDAofNInt; overload;

      //Chequea que el mismo archivo no exista en los nodos y si no existe lo envia
      //el resultado es 1 si el archivo queda en los nodos, 0 en otro caso
      function enviarArchivosSiNoExisten(idNodos: TDAofNCardinal; archivos: TStringList): TDAofNInt;

      //Trae el archivo indicado a la máquina local
      //El path del archivo se tomara desde uconstantes.dirbase, si nomArchivo
      //no incluye uconstantes.dirbase al comienzo este se le agrega
      //El resultado es un cardinal con el resultado de la operación
      //Si es 1 el archivo fue transferido correctamente
      //Sino si es:
      //-1  No se encontro el fileManager en el nodo
      //-2  El file manager respondió 0 al MSGP_OPEN_READ
      //-3  No se pudo levantar datos comunicado al pedir MSGP_OPEN_READ
      //-4  No se pudo leer ficha comunicado al pedir MSGP_OPEN_READ
      //-5  No se pudo comunicarTS al pedir MSGP_OPEN_READ
      //-6  El file manager respondió 0 al MSGP_READ
      //-7  No se pudo levantar datos comunicado al pedir MSGP_READ
      //-8  No se pudo leer ficha comunicado al pedir MSGP_READ
      //-9  No se pudo comunicarTS al pedir MSGP_READ
      //-10  El file manager respondió 0 al MSGP_CLOSEFILE
      //-11  No se pudo levantar datos comunicado al pedir MSGP_CLOSEFILE
      //-12  No se pudo leer ficha comunicado al pedir MSGP_CLOSEFILE
      //-13  No se pudo comunicarTS al pedir MSGP_CLOSEFILE
      function traerArchivo(idNodo: Cardinal; nomArchivo: String): Integer;
{      function abrirArchivoLectura(idTopo: Cardinal; nomArchivo: String) : Integer;
      function abrirArchivoEscritura(idTopo: Cardinal; nomArchivo: String) : Integer;
      function write(idTopo: Cardinal; handle: Integer) : Integer;
      function read(idTopo: Cardinal; handle: Integer) : Integer;}

      //Chequean si el archivo nomArchivo existe en los nodos especificados
      //retornan 0 si el archivo no existe, 1 si si
      function fileExists(idNodo: Cardinal; nomArchivo: String): Integer; overload;
      function fileExists(idNodos: TDAofNCardinal; nomArchivo: String): TDAofNInt; overload;

      //Para un archivo que exista en el nodo local chequea que el mismo archivo
      //exista en los nodos especificados.
      //Retorna 1 si el archivo existe y es el mismo, 0 si no existe y -1 si existe
      //pero es diferente
      function sameFileExists(idNodo: Cardinal; nomArchivo: String): Integer; overload;
      function sameFileExists(idNodos: TDAofNCardinal; nomArchivo: String): TDAofNInt; overload;

      //Cuando se llama indica que se debe preguntar nuevamente por los id de los fileManagers
      procedure resetIdsFileManagers;
    private
      maxBufferSize: Cardinal;
      idsFileManagers: TDAofNCardinal;
      procedure getFileManagers(const idNodos: TDAofNCardinal);
      procedure checkRes(op: String; const res: TDAofNInt; const idNodos: TDAofNCardinal);
  end;

procedure test;

implementation

function strNodosFallados(const nodosFallados: TDAofNCardinal; const resFallados: TDAofNInt): String;
var
  i: Integer;
  res: String;
begin
  res:= 'Nodos Fallados: ';
  for i:= 0 to High(nodosFallados) - 1 do
    res:= res + IntToStr(nodosFallados[i]) + ', res: ' + IntToStr(resFallados[i]) + '; ';
  res:= res + IntToStr(nodosFallados[High(nodosFallados)]) + ', res: ' + IntToStr(resFallados[High(nodosFallados)]);
  result:= res;
end;

//=======================
//Metodos de TFileHandler
//-----------------------

Constructor TFileHandler.Create;
begin
  inherited Create;
  maxBufferSize:= uMsgsFileManager.RecommendedBufferSize;
end;

function TFileHandler.enviarArchivo(idNodo: Cardinal; nomArchivo: String): Integer;
var
  aux: TDAofNCardinal;
  res: TDAofNInt;
begin
  SetLength(aux, 1);
  aux[0]:= idNodo;
  res:= enviarArchivo(aux, nomArchivo);
  SetLength(aux, 0);
  result:= Res[0];
end;

function TFileHandler.enviarArchivo(idNodos: TDAofNCardinal; nomArchivo: String): TDAofNInt;
var
  comunicadoAEnviar, comunicadoRecibido: TFichaComunicado;
  iNodos: Integer;
  f: File;
  handles: TDAOfNInt;
  nomArchivoAsPChar: PAnsiChar;
  res: TDAofNInt;

  idPeticion, maxNDatosALeer: Cardinal;
  respuesta: PRespuesta;
  pregunta: PPregunta;
begin
  comunicadoAEnviar.idNodoOrigen:= getIdNodoLocal;
  comunicadoAEnviar.idOrigen:= idAplicYo;

  SetLength(res, length(idNodos));
  for iNodos:= 0 to high(res) do
    res[iNodos]:= 0;

  AssignFile(f, nomArchivo);
  Reset(f, 1);
  try
    getFileManagers(idNodos);

    for iNodos:= 0 to high(idNodos) do
    begin
      if idsFileManagers[iNodos] = 0 then
        res[iNodos]:= -1
      else
        res[iNodos]:= 1; //Inicializo los que tengan fileManager levantado en 1
    end;

    //Abro los archivos para escritura en los nodos
//    toNetoposPath(nomArchivo);

    GetMem(nomArchivoAsPChar, length(nomArchivo) + 1);
    StrPCopy(nomArchivoAsPChar, nomArchivo);
    comunicadoAEnviar.codigoMsg:= uMsgsFileManager.MSGP_OPENWRITE;
    comunicadoAEnviar.nBytesDatos:= length(nomArchivo) +1;
    SetLength(handles, length(idNodos));

    for iNodos:= 0 to high(idNodos) do
    begin
      if res[iNodos] >= 0 then  //los que sigan en juego
      begin
        comunicadoAEnviar.idNodoDestino:= idNodos[iNodos];
        comunicadoAEnviar.idDestino:= idsFileManagers[iNodos];
        idPeticion:= comunicarTS(@comunicadoAEnviar, nomArchivoAsPChar, trunc(timeOutComsCte + timeOutComsPorByte * comunicadoAEnviar.nBytesDatos) + tOutOpenWrite );
        if idPeticion > 0 then
        begin
          if leerFichaComunicado(idPeticion, @comunicadoRecibido) > 0 then
          begin
            GetMem(respuesta, comunicadoRecibido.nBytesDatos);
            if levantarDatosComunicado(idPeticion, respuesta, comunicadoRecibido.nBytesDatos) > 0 then
            begin
              if respuesta^.resultado <> 0 then
                handles[iNodos]:= respuesta^.resultado
              else
                res[iNodos]:= -2;
            end
            else
              res[iNodos]:= -3;
            FreeMem(respuesta, comunicadoRecibido.nBytesDatos);
          end
          else
            res[iNodos]:= -4;
        end
        else
          res[iNodos]:= -5;
      end;
    end;
    FreeMem(nomArchivoAsPChar, length(nomArchivo) + 1);
    write('Enviando archivo ' + nomArchivo);

    //Transferencia del archivo
    maxNDatosALeer:= maxBufferSize - SizeOf(Cardinal) - SizeOf(Integer);
    GetMem(pregunta, maxBufferSize);
    comunicadoAEnviar.codigoMsg:= uMsgsFileManager.MSGP_WRITE;
    while not eof(f) do
    begin
      BlockRead(f, pregunta^.datos, maxNDatosALeer, pregunta^.NBytesDatos);
      comunicadoAEnviar.nBytesDatos:= SizeOf(Cardinal) + SizeOf(Integer) + pregunta^.NBytesDatos;

      for iNodos:= 0 to high(idNodos) do
      begin
        if res[iNodos] >= 0 then  //los que sigan en juego
        begin
          comunicadoAEnviar.idNodoDestino:= idNodos[iNodos];
          comunicadoAEnviar.idDestino:= idsFileManagers[iNodos];
          pregunta^.handle:= handles[iNodos];
          idPeticion:= comunicarTS(@comunicadoAEnviar, pregunta, trunc(timeOutComsCte + (timeOutComsPorByte + tOutWritePorByte) * comunicadoAEnviar.nBytesDatos));
          if idPeticion > 0 then
          begin
            if leerFichaComunicado(idPeticion, @comunicadoRecibido) > 0 then
            begin
              GetMem(respuesta, comunicadoRecibido.nBytesDatos);
              if levantarDatosComunicado(idPeticion, respuesta, comunicadoRecibido.nBytesDatos) > 0 then
              begin
                if respuesta^.resultado = 0 then
                  res[iNodos]:= -6;
              end
              else
                res[iNodos]:= -7;
              FreeMem(respuesta, comunicadoRecibido.nBytesDatos);
            end
            else
              res[iNodos]:= -8;
          end
          else
            res[iNodos]:= -9;
        end;
      end;
      write('.');
    end;
    FreeMem(pregunta, maxBufferSize);

    //Cierro los archivos remotos
    comunicadoAEnviar.codigoMsg:= MSGP_CLOSEFILE;
    comunicadoAEnviar.nBytesDatos:= sizeOf(Cardinal);
    GetMem(pregunta, comunicadoAEnviar.nBytesDatos);
    for iNodos:= 0 to high(idNodos) do
    begin
      if (res[iNodos] >= 0) or (res[iNodos] <= -6) then  //los que sigan en juego o abrieron sus archivos
      begin
        comunicadoAEnviar.idNodoDestino:= idNodos[iNodos];
        comunicadoAEnviar.idDestino:= idsFileManagers[iNodos];
        pregunta^.handle:= handles[iNodos];
        idPeticion:= comunicarTS(@comunicadoAEnviar, pregunta, trunc(timeOutComsCte + timeOutComsPorByte * comunicadoAEnviar.nBytesDatos) + tOutClose);
        if idPeticion > 0 then
        begin
          if leerFichaComunicado(idPeticion, @comunicadoRecibido) > 0 then
          begin
            GetMem(respuesta, comunicadoRecibido.nBytesDatos);
            if levantarDatosComunicado(idPeticion, respuesta, comunicadoRecibido.nBytesDatos) > 0 then
            begin
              if respuesta^.resultado = 0 then
                res[iNodos]:= -10;
            end
            else
              res[iNodos]:= -11;
            FreeMem(respuesta, comunicadoRecibido.nBytesDatos);
          end
          else
            res[iNodos]:= -12;
        end
        else
          res[iNodos]:= -13;
      end;
    end;
  finally
    closefile(f);
  end;
  FreeMem(pregunta, sizeof(Cardinal));
  SetLength(handles, 0);

  checkRes('transmitir el archivo ' + nomArchivo, res, idNodos);
  writeln('Ok');
  result:= res;
end;

function TFileHandler.enviarArchivosSiNoExisten(idNodos: TDAofNCardinal; archivos: TStringList): TDAofNInt;
var
  i, i2, j: Integer;
  archivosPresentes, archivosEnviados, res: TDAofNInt;
  idNodos2: TDAofNCardinal;
begin
  SetLength(res, archivos.Count);
  for i:= 0 to archivos.Count - 1 do
  begin
    writeln('Enviar archivo: ' + archivos[i]);  
    archivosPresentes:= self.sameFileExists(idNodos, archivos[i]);
    SetLength(idNodos2, length(idNodos));
    i2:= 0;
    for j:= 0 to High(idNodos) do
      if (archivosPresentes[j] = 0) or    //Los que no tienen el archivo
         (archivosPresentes[j] = -1) then //o lo tienen distinto
      begin
        idNodos2[i2]:= idNodos[j];
        i2:= i2 + 1;
      end;
    res[i]:= 1;//Asumo que se envia correctamente o que todos lo tienen
    if i2 <> 0 then //Si hay nodos sin el archivo
    begin
      idNodos2:= copy(idNodos2, 0, i2);
      archivosEnviados:= self.enviarArchivo(idNodos2, archivos[i]);
      for i2:= 0 to high(archivosEnviados) do
        if archivosEnviados[i2] <> 1 then //Si alguno de los nodos no recibio el archivo, asigno 0 al resultado 
        begin
          res[i]:= 0;
          break;
        end;
    end;
  end;
  result:= res;
end;

function TFileHandler.traerArchivo(idNodo: Cardinal; nomArchivo: String): Integer;
var
  comunicadoAEnviar, comunicadoRecibido: TFichaComunicado;
  idPeticion: Cardinal;

  pregunta : PPregunta;
  respuesta: PRespuesta;
  nomArchivoAsPChar: PAnsiChar;

  seguir: boolean;
  handle: Cardinal;
  arch: File;
begin
  comunicadoAEnviar.idNodoOrigen:= getIdNodoLocal;
  comunicadoAEnviar.idOrigen:= idAplicYo;
  comunicadoAEnviar.idNodoDestino:= idNodo;
  comunicadoAEnviar.idDestino:= getIdAplicacion(comunicadoAEnviar.idNodoDestino, uMsgsFileManager.AppName);
  if comunicadoAEnviar.idDestino = 0 then
    result:= -1
  else
    result:= 1;
  handle:= 0;

  if result >= 0 then
  begin
    //Pido abrir el archivo
    toNetoposPath(nomArchivo);

    comunicadoAEnviar.codigoMsg:= uMsgsFileManager.MSGP_OPENREAD;
    GetMem(nomArchivoAsPChar, Length(nomArchivo) + 1);
    StrPCopy(nomArchivoAsPChar, nomArchivo);
    comunicadoAEnviar.nBytesDatos:= Length(nomArchivo) + 1;

    idPeticion:= comunicarTS(@comunicadoAEnviar, nomArchivoAsPChar, trunc(timeOutComsCte + timeOutComsPorByte * comunicadoAEnviar.nBytesDatos) + tOutOpenRead);
    if idPeticion <> 0 then
    begin
      if leerFichaComunicado(idPeticion, @comunicadoRecibido) > 0 then
      begin
        GetMem(respuesta, comunicadoRecibido.nBytesDatos);
        if levantarDatosComunicado(idPeticion, respuesta, comunicadoRecibido.nBytesDatos) > 0 then
        begin
          handle:= respuesta^.resultado;
          if handle = 0 then
            result:= -2;
        end
        else //Fallo levantarDatosComunicado MSGP_OPENREAD
          result:= -3;
        FreeMem(respuesta, comunicadoRecibido.nBytesDatos);
      end
      else //Fallo leerFichaComunicado MSGP_OPENREAD
        result:= -4;
    end
    else //Fallo comunicarTS MSGP_OPENREAD
      result:= -5;
    FreeMem(nomArchivoAsPChar, length(nomArchivo) + 1);
  end;

  if result >= 0 then
  begin
    AssignFile(arch, nomArchivo);
    Rewrite(arch, 1);
    try
      comunicadoAEnviar.codigoMsg:= uMsgsFileManager.MSGP_READ;
      comunicadoAEnviar.nBytesDatos:= SizeOf(Cardinal);
      GetMem(pregunta, comunicadoAEnviar.nBytesDatos);
      pregunta^.handle:= handle;
      GetMem(respuesta, maxBufferSize);
      repeat
        idPeticion:= comunicarTS(@comunicadoAEnviar, pregunta, trunc(timeOutComsCte + timeOutComsPorByte * comunicadoAEnviar.nBytesDatos) + 20000);
        if idPeticion <> 0 then
        begin
          seguir:= leerFichaComunicado(idPeticion, @comunicadoRecibido) > 0;
          if seguir then
          begin
            seguir:= levantarDatosComunicado(idPeticion, respuesta, comunicadoRecibido.nBytesDatos) > 0;
            if seguir then
            begin
              if respuesta^.resultado > 0 then
              begin
                if respuesta.NBytesDatos > 0 then
                  BlockWrite(arch, respuesta^.datos, respuesta^.NBytesDatos)
                else
                  seguir:= false;
              end
              else
              begin
                result:= - 6;
                seguir:= false;
              end;
            end
            else
              result:= -7;
          end
          else
            result:= -8;
        end
        else
        begin
          seguir:= false;
          result:= -9;
        end;
      until not seguir;
      FreeMem(respuesta, maxBufferSize);
    finally
      CloseFile(arch);
    end;

    comunicadoAEnviar.codigoMsg:= MSGP_CLOSEFILE;
    idPeticion:= comunicarTS(@comunicadoAEnviar, pregunta, trunc(timeOutComsCte + timeOutComsPorByte * comunicadoAEnviar.nBytesDatos) + tOutClose);
    if idPeticion > 0 then
    begin
      if leerFichaComunicado(idPeticion, @comunicadoRecibido) > 0 then
      begin
        GetMem(respuesta, comunicadoRecibido.nBytesDatos);
        if levantarDatosComunicado(idPeticion, respuesta, comunicadoRecibido.nBytesDatos) > 0 then
        begin
          if respuesta^.resultado = 0 then
            result:= -10;
        end
        else
          result:= -11;
        FreeMem(respuesta, comunicadoRecibido.nBytesDatos);
      end
      else
        result:= -12;
    end
    else
     result:= -13;
    FreeMem(pregunta, comunicadoAEnviar.nBytesDatos);
  end;
end;

function TFileHandler.fileExists(idNodo: Cardinal; nomArchivo: String): Integer;
var
  aux: TDAofNCardinal;
  res: TDAofNInt;
begin
  SetLength(aux, 1);
  aux[0]:= idNodo;
  res:= fileExists(aux, nomArchivo);
  SetLength(aux, 0);
  result:= Res[0];
end;

function TFileHandler.fileExists(idNodos: TDAofNCardinal; nomArchivo: String): TDAofNInt;
var
  comunicadoAEnviar, comunicadoRecibido: TFichaComunicado;
  iNodos: Integer;
  nomArchivoAsPChar: PAnsiChar;
  res: TDAofNInt;

  idPeticion: Cardinal;
  respuesta: PRespuesta;
begin
  comunicadoAEnviar.idNodoOrigen:= getIdNodoLocal;
  comunicadoAEnviar.idOrigen:= idAplicYo;

  SetLength(res, length(idNodos));
  getFileManagers(idNodos);
  for iNodos:= 0 to high(idNodos) do
  begin
    if idsFileManagers[iNodos] = 0 then
      res[iNodos]:= -1
    else
      res[iNodos]:= 1; //Inicializo los que tengan fileManager levantado en 1
  end;

  //Abro los archivos para escritura en los nodos
  toNetoposPath(nomArchivo);

  GetMem(nomArchivoAsPChar, length(nomArchivo) + 1);
  StrPCopy(nomArchivoAsPChar, nomArchivo);
  comunicadoAEnviar.codigoMsg:= uMsgsFileManager.MSGP_FILEEXISTS;
  comunicadoAEnviar.nBytesDatos:= length(nomArchivo) +1;
  for iNodos:= 0 to high(idNodos) do
  begin
    if res[iNodos] >= 0 then  //los que sigan en juego
    begin
      comunicadoAEnviar.idNodoDestino:= idNodos[iNodos];
      comunicadoAEnviar.idDestino:= idsFileManagers[iNodos];
      idPeticion:= comunicarTS(@comunicadoAEnviar, nomArchivoAsPChar, trunc(timeOutComsCte + comunicadoAEnviar.nBytesDatos * timeOutComsPorByte) + tOutFileExists);
      if idPeticion > 0 then
      begin
        if leerFichaComunicado(idPeticion, @comunicadoRecibido) > 0 then
        begin
          GetMem(respuesta, comunicadoRecibido.nBytesDatos);
          if levantarDatosComunicado(idPeticion, respuesta, comunicadoRecibido.nBytesDatos) > 0 then
          begin
            res[iNodos]:= respuesta^.resultado;
          end
          else
            res[iNodos]:= -3;
          FreeMem(respuesta, comunicadoRecibido.nBytesDatos);
        end
        else
          res[iNodos]:= -4;
      end
      else
        res[iNodos]:= -5;
    end;
  end;
  FreeMem(nomArchivoAsPChar, length(nomArchivo) + 1);
  result:= res;
end;

function TFileHandler.sameFileExists(idNodo: Cardinal; nomArchivo: String): Integer;
var
  aux: TDAofNCardinal;
  res: TDAofNInt;
begin
  SetLength(aux, 1);
  aux[0]:= idNodo;
  res:= sameFileExists(aux, nomArchivo);
  SetLength(aux, 0);
  result:= Res[0];
end;

function TFileHandler.sameFileExists(idNodos: TDAofNCardinal; nomArchivo: String): TDAofNInt;
var
  comunicadoAEnviar, comunicadoRecibido: TFichaComunicado;
  iNodos: Integer;
  md5Rec: TMD5Digest;
  md5: String;
  res: TDAofNInt;

  idPeticion: Cardinal;
  datosSalientes: TBuffWriter;
  datosEntrantes: TBuffReader;
  resultado: Cardinal;
  codError: Integer;

  tMd5MSecs: Cardinal;
  ahora: TDateTime;
begin
  comunicadoAEnviar.idNodoOrigen:= getIdNodoLocal;
  comunicadoAEnviar.idOrigen:= idAplicYo;

  ahora:= now;
  md5:= '';
  md5Rec:= MD5File(nomArchivo);
  md5:= MD5DigestToStr(md5Rec);
  tMd5MSecs:= trunc(((now - ahora) * 24 * 3600 * 1000) * 1.4);//Tiempo que tardo en hacer el MD5

  if md5 <> '' then
  begin
    SetLength(res, length(idNodos));
    getFileManagers(idNodos);
    for iNodos:= 0 to high(idNodos) do
    begin
      if idsFileManagers[iNodos] = 0 then
        res[iNodos]:= -1
      else
        res[iNodos]:= 1; //Inicializo los que tengan fileManager levantado en 1
    end;
    toNetoposPath(nomArchivo);

    comunicadoAEnviar.codigoMsg:= uMsgsFileManager.MSGP_SAMEFILEEXISTS;
    comunicadoAEnviar.nBytesDatos:= xSizeOf(nomArchivo) + xSizeOf(md5);
    datosSalientes:= TBuffWriter.Create(comunicadoAEnviar.nBytesDatos);
    datosSalientes.xString(nomArchivo);
    datosSalientes.xString(md5);

    for iNodos:= 0 to high(idNodos) do
    begin
      if res[iNodos] >= 0 then //los que sigan en juego
      begin
        comunicadoAEnviar.idNodoDestino:= idNodos[iNodos];
        comunicadoAEnviar.idDestino:= idsFileManagers[iNodos];
        idPeticion:= comunicarTS(@comunicadoAEnviar, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicadoAEnviar.nBytesDatos) + tMd5MSecs);
        if idPeticion > 0 then
        begin
          if leerFichaComunicado(idPeticion, @comunicadoRecibido) > 0 then
          begin
            datosEntrantes:= TBuffReader.Create(comunicadoRecibido.pdatos, comunicadoRecibido.nBytesDatos);
            datosEntrantes.xCardinal(resultado);
            datosEntrantes.xInteger(codError);
            if levantarDatosComunicado(idPeticion, NIL, 0) > 0 then
            begin
              if resultado = 1 then
                res[iNodos]:= resultado
              else
              begin
                res[iNodos]:= codError;
              end;
            end
            else
              res[iNodos]:= -3;
            datosEntrantes.Free
          end
          else
            res[iNodos]:= -4;
        end
        else
          res[iNodos]:= -5;
      end;
    end;
    datosSalientes.Free;
  end
  else
  begin
    for iNodos:= 0 to high(idNodos) do
      res[iNodos]:= -6; //Hubo problemas abriendo el archivo local
  end;
  result:= res;
end;

procedure TFileHandler.resetIdsFileManagers;
begin
  idsFileManagers:= NIL;
end;

procedure TFileHandler.getFileManagers(const idNodos: TDAofNCardinal);
var
  i: Integer;
begin
  SetLength(idsFileManagers, length(idNodos));
  for i:= 0 to high(idNodos) do
    idsFileManagers[i]:= getIdAplicacion(idNodos[i], uMsgsFileManager.AppName);
end;

procedure TFileHandler.checkRes(op: String; const res: TDAofNInt; const idNodos: TDAofNCardinal);
var
  i, j: Integer;
  nodosFallados: TDAofNCardinal;
  resFallados: TDAofNInt;
begin
  SetLength(nodosFallados, length(res));
  SetLength(resFallados, length(res));
  j:= 0;
  for i:= 0 to high(res) do
  begin
    if res[i] <= 0 then
    begin
      nodosFallados[j]:= idNodos[i];
      resFallados[j]:= res[i];
      j:= j + 1;
    end;
    if j > 0 then
    begin
      nodosFallados:= copy(nodosFallados, 0, j);
      resFallados:= copy(resFallados, 0, j);
      raise Exception.Create('No se pudo ' + op + ' a todos los nodos.' + #13 + strNodosFallados(nodosFallados, resFallados));
    end;
  end;
end;

procedure test;
var
  handler: TFileHandler;
  nodos: TDAofNCardinal;
begin
  handler:= TFileHandler.Create;
  SetLength(nodos, 2);
  nodos[0]:= 3232235544;
  nodos[1]:= 3232235549;
  handler.enviarArchivo(3232235547, '\netopos\bin\darPaso.xlt');
  handler.traerArchivo(3232235547, '\netopos\bin\darPaso.xlt');
  handler.Free;
end;

end.
