unit uTestNettoposHandler;

interface

uses
{$IFDEF WINDOWS}
  messages, Forms, Windows,
{$ELSE}
  uWinMsgs,
{$ENDIF}
  xMatDefs, uMsgsTestNettopos, sysutils, uconstantes_nettopos, classes, ubuffrw,
  uLibFuncionesComunes, uServiciosTopo, uDespachador, uMsgsDespachador, uDatosNodo,
  uTareas,
{$IFDEF NETTOPOS_DLL}
  uimportnettopos,
{$ELSE}
  unettopos,
  unettopostypes,
  uglobsharedmem
{$ENDIF};

const
{$IFDEF DEBUG}
  to_Pedidos = 500000;
{$ELSE}
  to_Pedidos = 50000;
{$ENDIF}
  tSleepDelayedToUpperCase = 1500;
  NPasosPedirUnoContraTodosAsincrono= 300;

type
  TRobotPedirTodosContraUnoDespachador = class(TThread)
    private
      sAEnviar: String;
      idsNodos: TDAofNCardinal;

      conjuntoEjecucion: TConjuntoDeEjecucion;
      despachador: TDespachador;

      tareasRecibidas,
      resultados: TMatOfBoolean;

      function getINodo(idNodo: Cardinal): Integer;
    public
      Constructor Create(despachador: TDespachador; s: String; testearLongBuffer: boolean);
      procedure Execute; override;

      function CrearListaTareasDelayedToUpperCase(paso: Integer): TList;
      procedure procesarListaTareasDelayedToUpperCase(var listaTareas: TList; paso: Integer);

      procedure Free;
  end;

  TTestNettoposHandler = class
    private
      robotTCU_Despachador: TRobotPedirTodosContraUnoDespachador;

      idNodoLocal: Cardinal;
      nNodosParaPedirUnoContraTodosAsincrono, nMensajesPorRecibirParaPedirUnoContraTodosAsincrono: Integer;
      idTareaPedirUnoContraTodosAsincrono: Integer;
      sAEnviarParaPedirUnoContraTodosAsincrono: String;
    public
      despachador: TDespachador;
      recibidoPedirUnoContraTodosAsincrono,
      resultadosPedirUnoContraTodosAsincrono: TMatOfBoolean;

      Constructor Create;
      procedure Free;

      function pedirX2Sincrono(idNodo: Cardinal; x: Integer): Integer;
      procedure pedirX2Asincrono(idNodo: Cardinal; x: Integer);
      function recibirX2Asincrono(var Msg: TMessage): Integer;

      function pedirTestMemoAddSincrono(idNodo: Cardinal; s: String; testearLongBuffer: boolean): Cardinal;
      procedure pedirTestMemoAddAsincrono(idNodo: Cardinal; s: String; testearLongBuffer: boolean);
      function recibirTestMemoAddAsincrono(var Msg: TMessage): Cardinal;

      function pedirCloseAppSincrono(idNodo: Cardinal; nomApp: String): Integer;
      procedure pedirCloseAppAsincrono(idNodo: Cardinal; nomApp: String);
      function recibirCloseAppAsincrono(var Msg: TMessage): Integer;

      function pedirRunCmdSincrono(idNodo: Cardinal; nomApp: String): Integer;
      procedure pedirRunCmdAsincrono(idNodo: Cardinal; nomApp: String);
      function recibirRunCmdAsincrono(var Msg: TMessage): Integer;

      procedure pedirUnoContraTodosAsincrono(s: String; testearLongBuffer: boolean);
      procedure pedirDelayedToUpperCaseParaUnoContraTodos(idNodo, idTestNettopos:Cardinal; s: String);
      procedure recibirDelayedToUpperCaseParaUnoContraTodos(var Msg: TMessage);

      procedure pedirUnoContraTodosDespachador(s: String; testearLongBuffer: boolean);
      procedure msg_LiberarRobotTCU_Despachador(var Msg: TMessage);
  end;

function escribirResultadosDelayedToUpperCase(const recibidos, resultados: TMatOfBoolean): String;

implementation

function escribirResultadosDelayedToUpperCase(const recibidos, resultados: TMatOfBoolean): String;
var
  fRes: TextFile;
  i, j: Integer;
begin
  AssignFile(fRes, 'ResultadosDelayedToUpperCase.xlt');
  Rewrite(fRes);

  Write(fRes, 'Paso');
  for j:= 0 to High(resultados[0]) do
    write(fRes, #9'Nodo', j + 1, '_resultado', #9'Nodo', j + 1, '_recibido');
  writeln(fRes);
  for i:= 0 to NPasosPedirUnoContraTodosAsincrono - 1 do
  begin
    write(fRes, i + 1);
    for j:= 0 to high(resultados[i]) do
      Write(fRes, #9, resultados[i][j], #9, recibidos[i][j]);
    Writeln(fRes);
  end;

  CloseFile(fRes);
  result:= 'OK';
end;

Constructor TRobotPedirTodosContraUnoDespachador.Create(despachador: TDespachador; s: String; testearLongBuffer: boolean);
var
  i, j: Integer;
begin
  inherited Create(true);
  self.FreeOnTerminate:= false;
  self.despachador:= despachador;

  idsNodos:= despachador.idsNodos;
  conjuntoEjecucion:= TConjuntoDeEjecucion.Create(idsNodos);
  despachador.setDatosNodos(conjuntoEjecucion);  

  SetLength(resultados, NPasosPedirUnoContraTodosAsincrono);
  SetLength(tareasRecibidas, NPasosPedirUnoContraTodosAsincrono);
  for i:= 0 to NPasosPedirUnoContraTodosAsincrono -1 do
  begin
    SetLength(resultados[i], length(idsNodos));
    SetLength(tareasRecibidas[i], length(idsNodos));
    for j:= 0 to high(idsNodos) do
    begin
      resultados[i][j]:= false;
      tareasRecibidas[i][j]:= false;
    end;
  end;

  if testearLongBuffer then
  begin
    sAEnviar:= s;
    while length(sAEnviar) < MAX_SIZE_BUFFER_CHICO do
      sAEnviar:= sAEnviar + s;
  end
  else
    sAEnviar:= s;
  self.Resume;
end;

procedure TRobotPedirTodosContraUnoDespachador.Execute;
var
  i: Integer;
  listaTareas: TList;
begin
  for i:= 0 to NPasosPedirUnoContraTodosAsincrono - 1 do
  begin
    listaTareas:= CrearListaTareasDelayedToUpperCase(i);

    writeln('Paso ', i + 1);
    despachador.forkAndJoin(listaTareas, tSleepDelayedToUpperCase * 2 * conjuntoEjecucion.Count);

    procesarListaTareasDelayedToUpperCase(listaTareas, i);
  end;

  Writeln('Escribiendo Resultados');
  escribirResultadosDelayedToUpperCase(tareasRecibidas, resultados);
  Writeln('Ok');  

{$IFDEF WINDOWS}
  PostMessage(idAplicYo, MSG_LIBERAR_ROBOT_T_C_U_DESPACHADOR, 0, 0);
{$ELSE}
  xPostMessage(idAplicYo, MSG_LIBERAR_ROBOT_T_C_U_DESPACHADOR, 0, 0);
{$ENDIF}
end;

function TRobotPedirTodosContraUnoDespachador.CrearListaTareasDelayedToUpperCase(paso: Integer): TList;
var
  res: TList;
  i: Integer;
  tarea: TFichaTarea;
  verdadero: boolean;
  paramsEntrada: TBuffWriter;
begin
  verdadero:= true;
  res:= TList.Create;
  for i:= 0 to conjuntoEjecucion.Count - 1 do
  begin
    paramsEntrada:= TBuffWriter.Create(xSizeOf(sAEnviar) + xSizeOf(verdadero));
    paramsEntrada.xString(sAEnviar);
    paramsEntrada.xBoolean(verdadero);

    tarea:= TFichaTarea.Create(uMsgsTestNettopos.AppName, uMsgsTestNettopos.MSGP_DELAYED_TO_UPPER_CASE,
                               paramsEntrada, paso, 2 * tSleepDelayedToUpperCase, false,
                               TDatosNodo(conjuntoEjecucion[i]).idNodo, true);
    res.Add(tarea);
  end;
  result:= res;
end;

procedure TRobotPedirTodosContraUnoDespachador.procesarListaTareasDelayedToUpperCase(var listaTareas: TList; paso: Integer);
var
  i, iNodo: Integer;
  tarea: TFichaTarea;
  sRecibido: String;
begin
  for i:= 0 to listaTareas.Count - 1 do
  begin
    tarea:= listaTareas[i];
    if tarea.estado = Terminada then
    begin
      iNodo:= getINodo(tarea.idNodoEjecutor);
      tarea.resultados.xString(sRecibido);
      tareasRecibidas[paso][iNodo]:= true;
      resultados[paso][iNodo]:= sRecibido = AnsiUpperCase(sAEnviar);
    end;
    tarea.Free;
  end;
  listaTareas.Free;
end;

procedure TRobotPedirTodosContraUnoDespachador.Free;
var
  i: Integer;
begin
  SetLength(idsNodos, 0);
  conjuntoEjecucion.FreeConElementos;
  for i:= 0 to high(resultados) do
  begin
    SetLength(resultados[i], 0);
    SetLength(tareasRecibidas[i], 0);
  end;
  SetLength(resultados, 0);
  SetLength(tareasRecibidas, 0);

  inherited Free;
end;

function TRobotPedirTodosContraUnoDespachador.getINodo(idNodo: Cardinal): Integer;
var
  res, i: Integer;
begin
  res:= -1;
  for i:= 0 to High(idsNodos) do
    if idsNodos[i] = idNodo then
    begin
      res:= i;
      break;
    end;
  result:= res;    
end;

Constructor TTestNettoposHandler.Create;
begin
  inherited Create;
  self.idNodoLocal:= getIdNodoLocal;
end;

procedure TTestNettoposHandler.Free;
begin
  inherited Free;
end;

function TTestNettoposHandler.pedirX2Sincrono(idNodo: Cardinal; x: Integer): Integer;
var
  comunicadoSaliente, comunicadoEntrante: TFichaComunicado;
  idPeticion: Cardinal;
  res: Integer;
  datosPedido, datosRespuesta: PInteger;
begin
  comunicadoSaliente.idNodoOrigen:= idNodoLocal;
  comunicadoSaliente.idOrigen:= idAplicYo;
  comunicadoSaliente.idNodoDestino:= idNodo;
  comunicadoSaliente.idDestino:= getIdAplicacion(comunicadoSaliente.idNodoDestino, uMsgsTestNettopos.AppName);
  comunicadoSaliente.codigoMsg:= MSGP_PEDIRX2;
  comunicadoSaliente.lParam:= 0;
  comunicadoSaliente.idTarea:= 0;
  comunicadoSaliente.nBytesDatos:= SizeOf(x);
  GetMem(datosPedido, comunicadoSaliente.nBytesDatos);
  datosPedido^:= x;
  comunicadoSaliente.pdatos:= PLArrOfBytes(datosPedido);

  idPeticion:= comunicarTS(@comunicadoSaliente, comunicadoSaliente.pdatos, to_Pedidos);
  FreeMem(datosPedido, comunicadoSaliente.nBytesDatos);
  if idPeticion = 0 then
    raise Exception.Create('TTestNettoposHandler.pedirX2Sincrono: error al comunicar tarea sincrona!');
  if leerFichaComunicado(idPeticion, @comunicadoEntrante) = 0 then
    raise Exception.Create('TTestNettoposHandler.pedirX2Sincrono: error al leer la ficha del comunicado de respuesta!');

  GetMem(datosRespuesta, comunicadoEntrante.nBytesDatos);

  if levantarDatosComunicado(idPeticion, datosRespuesta, comunicadoEntrante.nBytesDatos) = 0 then
    raise Exception.Create('TTestNettoposHandler.pedirX2Sincrono: error al levantar los datos de la respuesta!');

  res:= datosRespuesta^;
  FreeMem(datosRespuesta, comunicadoEntrante.nBytesDatos);
  Result:= res;
end;

procedure TTestNettoposHandler.pedirX2Asincrono(idNodo: Cardinal; x: Integer);
var
  datosPedido: PInteger;
  idPeticion: Cardinal;
  comunicadoSaliente: TFichaComunicado;
begin
  comunicadoSaliente.idNodoOrigen:= idNodoLocal;
  comunicadoSaliente.idOrigen:= idAplicYo;
  comunicadoSaliente.idNodoDestino:= idNodo;
  comunicadoSaliente.idDestino:= getIdAplicacion(comunicadoSaliente.idNodoDestino, uMsgsTestNettopos.AppName);
  comunicadoSaliente.codigoMsg:= MSGP_PEDIRX2;
  comunicadoSaliente.lParam:= 0;
  comunicadoSaliente.idTarea:= 0;
  comunicadoSaliente.nBytesDatos:= SizeOf(x);
  GetMem(datosPedido, comunicadoSaliente.nBytesDatos);
  datosPedido^:= x;
  comunicadoSaliente.pdatos:= PLArrOfBytes(datosPedido);

  idPeticion:= comunicar(@comunicadoSaliente, comunicadoSaliente.pdatos, to_Pedidos);
  FreeMem(datosPedido, comunicadoSaliente.nBytesDatos);
  if idPeticion = 0 then
    raise Exception.Create('TTestNettoposHandler.pedirX2Asincrono: error al comunicar tarea!');
end;

function TTestNettoposHandler.recibirX2Asincrono(var Msg: TMessage): Integer;
var
  comunicadoEntrante: TFichaComunicado;
  datosRespuesta: PInteger;
  res: Integer;
begin
  if leerFichaComunicado(Msg.WParam, @comunicadoEntrante) = 0 then
    raise Exception.Create('TTestNettoposHandler.recibirX2Asincrono: error al leer la ficha del comunicado de respuesta!');

  GetMem(datosRespuesta, comunicadoEntrante.nBytesDatos);

  if levantarDatosComunicado(Msg.WParam, datosRespuesta, comunicadoEntrante.nBytesDatos) = 0 then
    raise Exception.Create('TTestNettoposHandler.recibirX2Asincrono: error al levantar los datos de la respuesta!');

  res:= datosRespuesta^;
  FreeMem(datosRespuesta, comunicadoEntrante.nBytesDatos);
  Result:= res;
end;

function TTestNettoposHandler.pedirTestMemoAddSincrono(idNodo: Cardinal; s: String; testearLongBuffer: boolean): Cardinal;
var
  comunicadoSaliente, comunicadoEntrante: TFichaComunicado;
  idPeticion, res: Cardinal;
  datosPedido: TBuffWriter;
  datosRespuesta: TBuffReader;

  msg: String;
  maxSizeBufferChico: Cardinal;
  k: Integer;
begin
  with comunicadoSaliente do
  begin
    idNodoOrigen:= idNodoLocal;
    idOrigen:= idAplicYo;
    idNodoDestino:= idNodo;
    idDestino:= getIdAplicacion(idNodoDestino, uMsgsTestNettopos.AppName);
    codigoMsg:= MSGP_TESTMEMOADD;
    lParam:= 0;
    idTarea:= 0;
  end;

  if testearLongBuffer then
  begin
    maxSizeBufferChico:= getMaxSizeBufferChico;
    k:= 0;
    msg:= s;
    while Length(msg) <= maxSizeBufferChico do
    begin
      msg:= msg + IntToStr(k) + '_' + s;
      k:= k + 1;
    end;
    s:= msg;
  end;
  comunicadoSaliente.nBytesDatos:= xSizeOf(s);
  datosPedido:= TBuffWriter.Create(comunicadoSaliente.nBytesDatos);
  datosPedido.xString(s);

  idPeticion:= comunicarTS(@comunicadoSaliente, datosPedido.pBuff, to_Pedidos);
  datosPedido.Free;

  if idPeticion = 0 then
    raise Exception.Create('TTestNettoposHandler.testMemoAddSincrono: error al comunicar tarea sincrona!');
  if leerFichaComunicado(idPeticion, @comunicadoEntrante) = 0 then
    raise Exception.Create('TTestNettoposHandler.testMemoAddSincrono: error al leer la ficha del comunicado de respuesta!');

  datosRespuesta:= TBuffReader.Create(comunicadoEntrante.pdatos, comunicadoEntrante.nBytesDatos);
  datosRespuesta.xCardinal(res);
  datosRespuesta.Free;

  if levantarDatosComunicado(idPeticion, nil, 0) = 0 then
    raise Exception.Create('TTestNettoposHandler.testMemoAddSincrono: error al levantar los datos de la respuesta!');

  Result:= res;
end;

procedure TTestNettoposHandler.pedirTestMemoAddAsincrono(idNodo: Cardinal; s: String; testearLongBuffer: boolean);
var
  comunicadoSaliente: TFichaComunicado;
  idPeticion: Integer;
  datosPedido: TBuffWriter;

  msg: String;
  maxSizeBufferChico: Cardinal;
  k: Integer;
begin
  comunicadoSaliente.idNodoOrigen:= idNodoLocal;
  comunicadoSaliente.idOrigen:= idAplicYo;
  comunicadoSaliente.idNodoDestino:= idNodo;
  comunicadoSaliente.idDestino:= getIdAplicacion(comunicadoSaliente.idNodoDestino, uMsgsTestNettopos.AppName);
  comunicadoSaliente.codigoMsg:= MSGP_TESTMEMOADD;
  comunicadoSaliente.lParam:= 0;
  comunicadoSaliente.idTarea:= 0;

  if testearLongBuffer then
  begin
    maxSizeBufferChico:= getMaxSizeBufferChico;
    k:= 0;
    msg:= s;
    while Length(msg) <= maxSizeBufferChico do
    begin
      msg:= msg + IntToStr(k) + '_' + s;
      k:= k + 1;
    end;
    s:= msg;
  end;
  comunicadoSaliente.nBytesDatos:= xSizeOf(s);
  datosPedido:= TBuffWriter.Create(comunicadoSaliente.nBytesDatos);
  datosPedido.xString(s);

  idPeticion:= comunicar(@comunicadoSaliente, datosPedido.pBuff, to_Pedidos);
  datosPedido.Free;

  if idPeticion = 0 then
    raise Exception.Create('TTestNettoposHandler.pedirTestMemoAddAsincrono: error al comunicar tarea!');
end;

function TTestNettoposHandler.recibirTestMemoAddAsincrono(var Msg: TMessage): Cardinal;
var
  comunicadoEntrante: TFichaComunicado;
  res: Cardinal;
  datosRespuesta: TBuffReader;
begin
  if leerFichaComunicado(msg.WParam, @comunicadoEntrante) = 0 then
    raise Exception.Create('TTestNettoposHandler.recibirTestMemoAddAsincrono: error al leer la ficha del comunicado de respuesta!');

  datosRespuesta:= TBuffReader.Create(comunicadoEntrante.pdatos, comunicadoEntrante.nBytesDatos);
  datosRespuesta.xCardinal(res);
  datosRespuesta.Free;

  if levantarDatosComunicado(msg.WParam, nil, 0) = 0 then
    raise Exception.Create('TTestNettoposHandler.recibirTestMemoAddAsincrono: error al levantar los datos de la respuesta!');

  Result:= res;
end;

function TTestNettoposHandler.pedirCloseAppSincrono(idNodo: Cardinal; nomApp: String): Integer;
var
  idTopoRemoto: Cardinal;
  comunicadoSaliente, comunicadoEntrante: TFichaComunicado;
  idPeticion: Cardinal;
  res: Integer;
  datosPedido: TBuffWriter;
  datosRespuesta: TBuffReader;
begin
  idTopoRemoto:= getIdAplicacion(idNodo, uconstantes_nettopos.AppName_Topo);
  comunicadoSaliente:= crearComunicado(idNodo, idTopoRemoto, MSGP_CLOSEAPP, 0, 0, xSizeOf(nomApp));

  datosPedido:= TBuffWriter.Create(comunicadoSaliente.nBytesDatos);
  datosPedido.xString(nomApp);

  idPeticion:= comunicarTS(@comunicadoSaliente, datosPedido.pBuff, to_Pedidos);
  datosPedido.Free;

  if idPeticion = 0 then
    raise Exception.Create('TTestNettoposHandler.pedirCloseAppSincrono: error al comunicar tarea sincrona!');
  if leerFichaComunicado(idPeticion, @comunicadoEntrante) = 0 then
    raise Exception.Create('TTestNettoposHandler.pedirCloseAppSincrono: error al leer la ficha del comunicado de respuesta!');

  datosRespuesta:= TBuffReader.Create(comunicadoEntrante.pdatos, comunicadoEntrante.nBytesDatos);
  datosRespuesta.xInteger(res);
  datosRespuesta.Free;

  if levantarDatosComunicado(idPeticion, nil, 0) = 0 then
    raise Exception.Create('TTestNettoposHandler.pedirCloseAppSincrono: error al levantar los datos de la respuesta!');

  Result:= res;
end;

procedure TTestNettoposHandler.pedirCloseAppAsincrono(idNodo: Cardinal; nomApp: String);
var
  idTopoRemoto: Cardinal;
  comunicadoSaliente: TFichaComunicado;
  idPeticion: Integer;
  datosPedido: TBuffWriter;
begin
  idTopoRemoto:= getIdAplicacion(idNodo, uconstantes_nettopos.AppName_Topo);
  comunicadoSaliente:= crearComunicado(idNodo, idTopoRemoto, MSGP_CLOSEAPP, 0, 0, xSizeOf(nomApp));
  datosPedido:= TBuffWriter.Create(comunicadoSaliente.nBytesDatos);
  datosPedido.xString(nomApp);

  idPeticion:= comunicar(@comunicadoSaliente, datosPedido.pBuff, to_Pedidos);
  datosPedido.Free;

  if idPeticion = 0 then
    raise Exception.Create('TTestNettoposHandler.pedirCloseAppAsincrono: error al comunicar tarea!');
end;

function TTestNettoposHandler.recibirCloseAppAsincrono(var Msg: TMessage): Integer;
var
  comunicadoEntrante: TFichaComunicado;
  res: Integer;
  datosRespuesta: TBuffReader;
begin
  if leerFichaComunicado(msg.WParam, @comunicadoEntrante) = 0 then
    raise Exception.Create('TTestNettoposHandler.recibirTestMemoAddAsincrono: error al leer la ficha del comunicado de respuesta!');

  datosRespuesta:= TBuffReader.Create(comunicadoEntrante.pdatos, comunicadoEntrante.nBytesDatos);
  datosRespuesta.xInteger(res);
  datosRespuesta.Free;

  if levantarDatosComunicado(msg.WParam, nil, 0) = 0 then
    raise Exception.Create('TTestNettoposHandler.recibirTestMemoAddAsincrono: error al levantar los datos de la respuesta!');

  Result:= res;
end;

function TTestNettoposHandler.pedirRunCmdSincrono(idNodo: Cardinal; nomApp: String): Integer;
var
  idTopoRemoto: Cardinal;
  comunicadoSaliente, comunicadoEntrante: TFichaComunicado;
  idPeticion: Cardinal;
  res: Integer;
  datosPedido: TBuffWriter;
  datosRespuesta: TBuffReader;
begin
  idTopoRemoto:= getIdAplicacion(idNodo, uconstantes_nettopos.AppName_Topo);
  comunicadoSaliente:= crearComunicado(idNodo, idTopoRemoto, MSGP_RUNCMD, 0, 0, xSizeOf(nomApp));

  datosPedido:= TBuffWriter.Create(comunicadoSaliente.nBytesDatos);
  datosPedido.xString(nomApp);

  idPeticion:= comunicarTS(@comunicadoSaliente, datosPedido.pBuff, to_Pedidos);
  datosPedido.Free;

  if idPeticion = 0 then
    raise Exception.Create('TTestNettoposHandler.pedirRunCmdSincrono: error al comunicar tarea sincrona!');
  if leerFichaComunicado(idPeticion, @comunicadoEntrante) = 0 then
    raise Exception.Create('TTestNettoposHandler.pedirRunCmdSincrono: error al leer la ficha del comunicado de respuesta!');

  datosRespuesta:= TBuffReader.Create(comunicadoEntrante.pdatos, comunicadoEntrante.nBytesDatos);
  datosRespuesta.xInteger(res);
  datosRespuesta.Free;

  if levantarDatosComunicado(idPeticion, nil, 0) = 0 then
    raise Exception.Create('TTestNettoposHandler.pedirRunCmdSincrono: error al levantar los datos de la respuesta!');

  Result:= res;
end;

procedure TTestNettoposHandler.pedirRunCmdAsincrono(idNodo: Cardinal; nomApp: String);
var
  idTopoRemoto: Cardinal;
  comunicadoSaliente: TFichaComunicado;
  idPeticion: Integer;
  datosPedido: TBuffWriter;
begin
  idTopoRemoto:= getIdAplicacion(idNodo, uconstantes_nettopos.AppName_Topo);
  comunicadoSaliente:= crearComunicado(idNodo, idTopoRemoto, MSGP_RUNCMD, 0, 0, xSizeOf(nomApp));
  datosPedido:= TBuffWriter.Create(comunicadoSaliente.nBytesDatos);
  datosPedido.xString(nomApp);

  idPeticion:= comunicar(@comunicadoSaliente, datosPedido.pBuff, to_Pedidos);
  datosPedido.Free;

  if idPeticion = 0 then
    raise Exception.Create('TTestNettoposHandler.pedirRunCmdAsincrono: error al comunicar tarea!');
end;

function TTestNettoposHandler.recibirRunCmdAsincrono(var Msg: TMessage): Integer;
var
  comunicadoEntrante: TFichaComunicado;
  res: Integer;
  datosRespuesta: TBuffReader;
begin
  if leerFichaComunicado(msg.WParam, @comunicadoEntrante) = 0 then
    raise Exception.Create('TTestNettoposHandler.recibirRunCmdAsincrono: error al leer la ficha del comunicado de respuesta!');

  datosRespuesta:= TBuffReader.Create(comunicadoEntrante.pdatos, comunicadoEntrante.nBytesDatos);
  datosRespuesta.xInteger(res);
  datosRespuesta.Free;

  if levantarDatosComunicado(msg.WParam, nil, 0) = 0 then
    raise Exception.Create('TTestNettoposHandler.recibirRunCmdAsincrono: error al levantar los datos de la respuesta!');

  Result:= res;
end;

procedure TTestNettoposHandler.pedirUnoContraTodosAsincrono(s: String; testearLongBuffer: boolean);
var
  i, j: Integer;
  idsNodos, idsTestNettopos: TDAofNCardinal;
  topo: TServiciosTopo;
begin
  idTareaPedirUnoContraTodosAsincrono:= 0;
  if testearLongBuffer then
  begin
    sAEnviarParaPedirUnoContraTodosAsincrono:= s;
    while length(sAEnviarParaPedirUnoContraTodosAsincrono) < MAX_SIZE_BUFFER_CHICO do
      sAEnviarParaPedirUnoContraTodosAsincrono:= sAEnviarParaPedirUnoContraTodosAsincrono + s;
  end
  else
    sAEnviarParaPedirUnoContraTodosAsincrono:= s;

  topo:= TServiciosTopo.Create;
  idsNodos:= topo.pedirGet_NodosSincrono(false);
  nNodosParaPedirUnoContraTodosAsincrono:= length(idsNodos);
  SetLength(idsTestNettopos, length(idsNodos));
  for j:= 0 to high(idsTestNettopos) do
  begin
    idsTestNettopos[j]:= topo.lanzarAppSiNoExiste(idsNodos[j], uMsgsTestNettopos.AppName);
    if idsTestNettopos[j] = 0 then
      raise Exception.Create('TTestNettoposHandler.pedirUnoContraTodosAsincrono: el TesteadorNettopos en el nodo ' + IntToStr(idsNodos[j]) + ' no respondió');
  end;
  topo.Free;
  nMensajesPorRecibirParaPedirUnoContraTodosAsincrono:= NPasosPedirUnoContraTodosAsincrono * nNodosParaPedirUnoContraTodosAsincrono;

  if nNodosParaPedirUnoContraTodosAsincrono > 0 then
  begin
    SetLength(resultadosPedirUnoContraTodosAsincrono, NPasosPedirUnoContraTodosAsincrono);
    SetLength(recibidoPedirUnoContraTodosAsincrono, NPasosPedirUnoContraTodosAsincrono);
    for i:= 0 to NPasosPedirUnoContraTodosAsincrono -1 do
    begin
      SetLength(resultadosPedirUnoContraTodosAsincrono[i], length(idsNodos));
      SetLength(recibidoPedirUnoContraTodosAsincrono[i], length(idsNodos));
      for j:= 0 to high(idsNodos) do
      begin
        resultadosPedirUnoContraTodosAsincrono[i][j]:= false;
        recibidoPedirUnoContraTodosAsincrono[i][j]:= false;
      end;
    end;

    for i:= 0 to NPasosPedirUnoContraTodosAsincrono -1 do
    begin
      writeln('Paso ', i + 1);
      for j:= 0 to high(idsNodos) do
        pedirDelayedToUpperCaseParaUnoContraTodos(idsNodos[j], idsTestNettopos[j], sAEnviarParaPedirUnoContraTodosAsincrono);
{$IFDEF WINDOWS}
      Application.ProcessMessages;
{$ENDIF}
    end;
  end;
end;

procedure TTestNettoposHandler.pedirDelayedToUpperCaseParaUnoContraTodos(idNodo, idTestNettopos:Cardinal; s: String);
var
  comunicadoSaliente: TFichaComunicado;
  idPeticion: Integer;
  datosPedido: TBuffWriter;
  falso: boolean;
begin
  falso:= false;
  with comunicadoSaliente do
  begin
    idNodoOrigen:= idNodoLocal;
    idOrigen:= idAplicYo;
    idNodoDestino:= idNodo;
    idDestino:= idTestNettopos;
    codigoMsg:= uMsgsTestNettopos.MSGP_DELAYED_TO_UPPER_CASE;
    nBytesDatos:= xSizeOf(s) + xSizeOf(falso);
    lParam:= 0;
    idTarea:= self.idTareaPedirUnoContraTodosAsincrono;
  end;
  self.idTareaPedirUnoContraTodosAsincrono:= self.idTareaPedirUnoContraTodosAsincrono + 1;

  datosPedido:= TBuffWriter.Create(comunicadoSaliente.nBytesDatos);
  datosPedido.xString(s);
  datosPedido.xBoolean(falso);

  idPeticion:= comunicar(@comunicadoSaliente, datosPedido.pBuff, to_Pedidos);
  datosPedido.Free;

  if idPeticion = 0 then
    raise Exception.Create('TTestNettoposHandler.pedirDelayedToUpperCaseParaUnoContraTodos: error al comunicar tarea!');
end;

procedure TTestNettoposHandler.recibirDelayedToUpperCaseParaUnoContraTodos(var Msg: TMessage);
var
  comunicadoEntrante: TFichaComunicado;
  sRecibido: String;
  datosRespuesta: TBuffReader;
  iPaso, iNodo: Integer;
begin
  if robotTCU_Despachador <> NIL then
  begin
    if leerFichaComunicado(msg.WParam, @comunicadoEntrante) = 0 then
      raise Exception.Create('TTestNettoposHandler.recibirDelayedToUpperCaseParaUnoContraTodos: error al leer la ficha del comunicado de respuesta!');

    datosRespuesta:= TBuffReader.Create(comunicadoEntrante.pdatos, comunicadoEntrante.nBytesDatos);
    datosRespuesta.xString(sRecibido);
    datosRespuesta.Free;

    if levantarDatosComunicado(msg.WParam, nil, 0) = 0 then
      raise Exception.Create('TTestNettoposHandler.recibirDelayedToUpperCaseParaUnoContraTodos: error al levantar los datos de la respuesta!');

    iNodo:= comunicadoEntrante.idTarea mod Self.nNodosParaPedirUnoContraTodosAsincrono;
    iPaso:= comunicadoEntrante.idTarea div Self.nNodosParaPedirUnoContraTodosAsincrono;
    resultadosPedirUnoContraTodosAsincrono[iPaso][iNodo]:= AnsiUpperCase(sAEnviarParaPedirUnoContraTodosAsincrono) = sRecibido;

    if not recibidoPedirUnoContraTodosAsincrono[iPaso][iNodo] then
    begin
      recibidoPedirUnoContraTodosAsincrono[iPaso][iNodo]:= true;
      nMensajesPorRecibirParaPedirUnoContraTodosAsincrono:= nMensajesPorRecibirParaPedirUnoContraTodosAsincrono - 1;
    end
    else
      writeln('Recibido paso repetido', ipaso, ' de nodo ', iNodo, ' res= ', resultadosPedirUnoContraTodosAsincrono[iPaso][iNodo]);
    if not resultadosPedirUnoContraTodosAsincrono[iPaso][iNodo] then
      writeln('Recibido paso ', ipaso, ' de nodo ', iNodo, ' res= ', resultadosPedirUnoContraTodosAsincrono[iPaso][iNodo]);
  end
  else
    despachador.recibirRespuesta(Msg);
end;

procedure TTestNettoposHandler.pedirUnoContraTodosDespachador(s: String; testearLongBuffer: boolean);
begin
  if robotTCU_Despachador = NIL then
  begin
    Self.despachador:= TDespachador.Create;
    robotTCU_Despachador:= TRobotPedirTodosContraUnoDespachador.Create(despachador, s, testearLongBuffer);
  end;
end;

procedure TTestNettoposHandler.msg_LiberarRobotTCU_Despachador(var Msg: TMessage);
begin
  if robotTCU_Despachador <> NIL then
  begin
    writeln('Liberando robotTCU_Despachador');
    robotTCU_Despachador.WaitFor;
    robotTCU_Despachador.Free;
    robotTCU_Despachador:= NIL;
    despachador.Free;
    despachador:= NIL;
    writeln('Ok');
  end;
end;

end.
