{xDEFINE CONLOG}
{xDEFINE DEBUG_COMS}
unit uOptDisV2;

interface

uses
{$IFDEF WINDOWS}
  Windows, Messages, Interfaces, Forms, Dialogs,
//  Variants, Controls, StdCtrls,
{$ELSE}
  uWinMsgs,
  baseunix,
  unix,
{$ENDIF}
  SysUtils, Classes, usalasdejuego, //uSalasDeJuego,
  uMsgsOptDisV2, ubuffrw, xMatDefs, uCosa,
  uCosaConNombre, uAuxiliares,
  uSalasDeJuegoParaEditor, uInicioYFinal, uMsgsDespachador, uconstantes_nettopos, uglobs,
  uconstantesSimSEE, winLinuxUtils, uLibFuncionesComunes,
{$IFDEF NETTOPOS_DLL}
  uimportnettopos,
{$ELSE}
  unettopos,
  unettopostypes,
  uglobsharedmem
{$ENDIF};

const
  //Constante para prioridad debajo de la normal
  sleepComs = 50;
  BELOW_NORMAL_PRIORITY_CLASS=$00004000;

type
{$IFDEF LINUX}
  TOptDisV2 = class(TComponent)
{$ELSE}
  TOptDisV2 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
{$ENDIF}
  private
    myIdEnLaDll: Cardinal;

    sala: TSalaDeJuego;
    idTareaActual: Cardinal;
    multiHilo: boolean;

{$IFDEF DEBUG_COMS}
    fCalcularRango, fLlenarRango, fDarPaso, fLlenarRangoDarPasoYCalcular: TextFile;
{$ENDIF}
    procedure msgp_Cargar_E_Inicializar_Sala(var Msg: TMessage); message MSGP_CARGAR_E_INICIALIZAR_SALA;
    procedure msgp_Calcular_Rango_Estrellas(var Msg: TMessage); message MSGP_CALCULAR_RANGO_ESTRELLAS;
    procedure msgp_Llenar_Rango_Estrellas(var Msg: TMessage); message MSGP_LLENAR_RANGO_ESTRELLAS;
    procedure msgp_Get_Rango_Estrellas(var Msg: TMessage); message MSGP_GET_RANGO_ESTRELLAS;
    procedure msgp_Dar_Paso(var Msg: TMessage); message MSGP_DAR_PASO;
    procedure msgp_Estado(var Msg: TMessage); message uMsgsDespachador.MSGP_ESTADO;
    procedure msgp_Llenar_Rangos_Y_Dar_Paso(var Msg: TMessage); message MSGP_LLENAR_RANGOS_Y_DAR_PASO;
    procedure msgp_Llenar_Rangos_Dar_Paso_Y_Calcular_Rango(var Msg: TMessage); message MSGP_LLENAR_RANGO_DAR_PASO_Y_CALCULAR_RANGO;
    procedure msgp_Get_Estado_Madre_Uniforme(var Msg: TMessage); message MSGP_GET_ESTADO_MADRE_UNIFORME;
    procedure msgp_Set_Estado_Madre_Uniforme(var Msg: TMessage); message MSGP_SET_ESTADO_MADRE_UNIFORME;
    procedure CargarSala(archiSala: String);
  public
{$IFDEF LINUX}
    recolectar: boolean;
    constructor Create(AOwner: TComponent); reintroduce;
    procedure Free; virtual;
{$ENDIF}
  end;

procedure procedimientoAlerta(const s: String);

var
  OptDisV2: TOptDisV2;

implementation

{$IFNDEF LINUX}
{$R *.dfm}
{$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 ' );
      OptDisV2.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}

procedure procedimientoAlerta(const s: String);
begin
  writeln(s);
end;

{$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 TOptDisV2.msgp_Cargar_E_Inicializar_Sala(var Msg: TMessage);
var
  comunicado: TFichaComunicado;
  archiSala: String;
  datosEntrantes: TBuffReader;
  datosSalientes: TBuffWriter;

  codRespuesta, resRespuesta, nIntentosComunicacion: Integer;
  msjError: String;
  dimX: integer;

begin
{$IFDEF CONLOG}
  conlog('Cargar_E_Inicializar...begin:', msg );
{$ENDIF}
  if leerFichaComunicado(msg.WParam, @comunicado) > 0 then
  begin
    idTareaActual:= comunicado.idTarea;
    datosEntrantes:= TBuffReader.Create(comunicado.pdatos, comunicado.nBytesDatos);
    datosEntrantes.xString(archiSala);
    datosEntrantes.Free;

    if levantarDatosComunicado(msg.WParam, nil, 0) > 0 then
    begin
      if sala <> NIL then
      begin
        //------sala.liberarVariablesMultiCore;
        sala.Free;
        sala:= NIL;
      end;
      msjError:= '';
      try
        CargarSala(dirbase + archiSala);
        sala.globs.setProcAlerta(procedimientoAlerta);

        dimX:= sala.inicializarOptimizacion(nil, nil);

        {sala.nHilos:= 1;
        sala.forzarNumeroDeHilos:= true;
        multiHilo:= sala.nHilos > 1;
        if multiHilo then
          sala.inicializarVariablesMultiCore(false);
               }
        codRespuesta:= 1;
      except
        On E: Exception do
        begin
          msjError:= 'Error cargando la Sala.'#13 +  E.Message;
          if sala <> NIL then
          begin
            sala.Free;
            sala:= NIL;
          end;
          codRespuesta:= 0;
        end;
      end;

      uLibFuncionesComunes.invertirComunicado(comunicado);
      comunicado.codigoMsg:= uMsgsDespachador.MSGP_RECIBIR_RESPUESTA;
      if msjError <> '' then
      begin
        comunicado.nBytesDatos:= xSizeOf(codRespuesta) + xSizeOf(msjError);
        datosSalientes:= TBuffWriter.Create(comunicado.nBytesDatos);
        datosSalientes.xInteger(codRespuesta);
        datosSalientes.xString(msjError);
      end
      else
      begin
        comunicado.nBytesDatos:= xSizeOf(codRespuesta);
        datosSalientes:= TBuffWriter.Create(comunicado.nBytesDatos);
        datosSalientes.xInteger(codRespuesta);
      end;

      resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      nIntentosComunicacion:= 1;
      while (resRespuesta = 0) and (nIntentosComunicacion < MAX_REINTENTOS_COMUNICACION) do
      begin
        sleep(sleepComs);
        nIntentosComunicacion:= nIntentosComunicacion + 1;
        resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      end;
      if resRespuesta = 0 then
        logError(codErrorToString(ERROR_NO_SE_PUDO_COMUNICAR_LA_TAREA));
      datosSalientes.Free;
    end
    else
      logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL));
  end
  else
    logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL));
{$IFDEF CONLOG}
  conlog( 'Cargar_E_Inicializar...end:'+IntToStr( idTareaActual ), msg );
{$ENDIF}
  idTareaActual:= 0;
end;



procedure TOptDisV2.msgp_Calcular_Rango_Estrellas(var Msg: TMessage);
var
  comunicado: TFichaComunicado;
  estrellaIni, estrellaFin: Integer;
  costosFuturos: TDAofNReal;
  datosEntrantes: TBuffReader;
  datosSalientes: TBuffWriter;

  resRespuesta, nIntentosComunicacion: Integer;
{$IFDEF DEBUG_COMS}
  idbg: Integer;
{$ENDIF}
begin
{$IFDEF CONLOG}
  conlog('Calcular...begin:', msg );
{$ENDIF}
  if leerFichaComunicado(msg.WParam, @comunicado) > 0 then
  begin
    idTareaActual:= comunicado.idTarea;
    datosEntrantes:= TBuffReader.Create(comunicado.pdatos, comunicado.nBytesDatos);
    datosEntrantes.xInteger(estrellaIni);
    datosEntrantes.xInteger(estrellaFin);
    datosEntrantes.Free;

    if levantarDatosComunicado(msg.WParam, nil, 0) > 0 then
    begin
      {if multiHilo then
        sala.calcularRangoEstrellasMultiCore(estrellaIni, estrellaFin)
      else}

      sala.calcularRangoEstrellas(estrellaIni, estrellaFin, false, false );

      costosFuturos:= sala.getRangoEstrellasCF(estrellaIni, estrellaFin, sala.globs.kPaso_);

      uLibFuncionesComunes.invertirComunicado(comunicado);
      comunicado.codigoMsg:= uMsgsDespachador.MSGP_RECIBIR_RESPUESTA;
      comunicado.nBytesDatos:= xCompressedSizeOf(costosFuturos, uMsgsOptDisV2.tipoCompresionReales);
      datosSalientes:= TBuffWriter.Create(comunicado.nBytesDatos);
      datosSalientes.xCompressedTDAOfNReal(costosFuturos, uMsgsOptDisV2.tipoCompresionReales);
      resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      nIntentosComunicacion:= 1;
      while (resRespuesta = 0) and (nIntentosComunicacion < MAX_REINTENTOS_COMUNICACION) do
      begin
        sleep(sleepComs);
        nIntentosComunicacion:= nIntentosComunicacion + 1;
        resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      end;
      if resRespuesta = 0 then
        logError(codErrorToString(ERROR_NO_SE_PUDO_COMUNICAR_LA_TAREA));
      datosSalientes.Free;
    end
    else
      logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL));
  end
  else
    logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL));
{$IFDEF CONLOG}
  conlog( 'Calcular...end:'+IntToStr( idTareaActual ), msg );
{$ENDIF}
  idTareaActual:= 0;

{$IFDEF DEBUG_COMS}
  write(fCalcularRango, 'paso= ', #9, sala.globs.kPaso_, #9, 'estrellaIni= ', #9, estrellaIni, #9, 'estrellaFin= ', #9, estrellaFin);
  for idbg:= 0 to high(costosFuturos) do
    write(fCalcularRango, #9, FloatToStrF(costosFuturos[idbg], ffGeneral, 6, 3));
  writeln(fCalcularRango);
{$ENDIF}
end;

procedure TOptDisV2.msgp_Llenar_Rango_Estrellas(var Msg: TMessage);
var
  comunicado: TFichaComunicado;
  estrellaIni: Integer;
  costosFuturos: TDAOfNreal;
  datosEntrantes: TBuffReader;
  datosSalientes: TBuffWriter;

  codRespuesta: Integer;
  resRespuesta, nIntentosComunicacion: Integer;

{$IFDEF DEBUG_COMS}
  idbg: Integer;
{$ENDIF}
begin
{$IFDEF CONLOG}
  conlog( 'Llenar...begin:', msg );
{$ENDIF}
  if leerFichaComunicado(msg.WParam, @comunicado) > 0 then
  begin
    idTareaActual:= comunicado.idTarea;
    datosEntrantes:= TBuffReader.Create(comunicado.pdatos, comunicado.nBytesDatos);
    datosEntrantes.xInteger(estrellaIni);
    datosEntrantes.xCompressedTDAOfNReal(costosFuturos, uMsgsOptDisV2.tipoCompresionReales);
    datosEntrantes.Free;

    if levantarDatosComunicado(msg.WParam, nil, 0) > 0 then
    begin

      sala.SetRangoEstrellasCF( estrellaIni, costosFuturos, sala.globs.kPaso_);

      writeln('llenando rangos');

      codRespuesta:= 1;
      uLibFuncionesComunes.invertirComunicado(comunicado);
      comunicado.codigoMsg:= uMsgsDespachador.MSGP_RECIBIR_RESPUESTA;
      comunicado.nBytesDatos:= xSizeOf(codRespuesta);
      datosSalientes:= TBuffWriter.Create(comunicado.nBytesDatos);
      datosSalientes.xInteger(codRespuesta);

      resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      nIntentosComunicacion:= 1;
      while (resRespuesta = 0) and (nIntentosComunicacion < MAX_REINTENTOS_COMUNICACION) do
      begin
        sleep(sleepComs);
        nIntentosComunicacion:= nIntentosComunicacion + 1;
        resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      end;
      if (resRespuesta = 0) then
        logError(codErrorToString(ERROR_NO_SE_PUDO_COMUNICAR_LA_TAREA));
      datosSalientes.Free;
    end
    else
      logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL));
  end
  else
    logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL));
{$IFDEF CONLOG}
 conlog( 'Llenar...end:'+IntToStr(idTareaActual), msg );
 {$ENDIF}    
  idTareaActual:= 0;

{$IFDEF DEBUG_COMS}
  write(fLlenarRango, 'paso= ', #9, sala.globs.kPaso_, #9, 'estrellaIni= ', #9, estrellaIni);
  for idbg:= 0 to high(costosFuturos) do
    write(fLlenarRango, #9, FloatToStrF(costosFuturos[idbg], ffGeneral, 6, 3));
  writeln(fLlenarRango);
{$ENDIF}
end;

procedure TOptDisV2.msgp_Get_Rango_Estrellas(var Msg: TMessage);
var
  comunicado: TFichaComunicado;
  estrellaIni, estrellaFin: Integer;
  costosFuturos: TDAOfNreal;
  datosEntrantes: TBuffReader;
  datosSalientes: TBuffWriter;

  resRespuesta, nIntentosComunicacion: Integer;
begin
{$IFDEF CONLOG}
  conlog( 'Get...begin:', msg );
{$ENDIF}
  if leerFichaComunicado(msg.WParam, @comunicado) > 0 then
  begin
    idTareaActual:= comunicado.idTarea;
    datosEntrantes:= TBuffReader.Create(comunicado.pdatos, comunicado.nBytesDatos);
    datosEntrantes.xInteger(estrellaIni);
    datosEntrantes.xInteger(estrellaFin);
    datosEntrantes.Free;

    if levantarDatosComunicado(msg.WParam, nil, 0) > 0 then
    begin
      costosFuturos:= sala.getRangoEstrellasCF(estrellaIni, estrellaFin, sala.globs.kPaso_);

      uLibFuncionesComunes.invertirComunicado(comunicado);
      comunicado.codigoMsg:= uMsgsDespachador.MSGP_RECIBIR_RESPUESTA;
      comunicado.nBytesDatos:= xCompressedSizeOf(costosFuturos, uMsgsOptDisV2.tipoCompresionReales);
      datosSalientes:= TBuffWriter.Create(comunicado.nBytesDatos);
      datosSalientes.xCompressedTDAOfNReal(costosFuturos, uMsgsOptDisV2.tipoCompresionReales);

      resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      nIntentosComunicacion:= 1;
      while (resRespuesta = 0) and (nIntentosComunicacion < MAX_REINTENTOS_COMUNICACION) do
      begin
        sleep(sleepComs);
        nIntentosComunicacion:= nIntentosComunicacion + 1;
        resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      end;
      if (resRespuesta = 0) then
        logError(codErrorToString(ERROR_NO_SE_PUDO_COMUNICAR_LA_TAREA));
      datosSalientes.Free;
    end
    else
      logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL));
  end
  else
    logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL));
{$IFDEF CONLOG}
	conlog( 'Get...end:'+IntTostr( idTareaActual ), msg );
{$ENDIF}
  idTareaActual:= 0;
end;

procedure TOptDisV2.msgp_Dar_Paso(var Msg: TMessage);
var
  comunicado: TFichaComunicado;
  datosSalientes: TBuffWriter;

  codRespuesta: Integer;
  resRespuesta, nIntentosComunicacion: Integer;
begin
{$IFDEF CONLOG}
  conlog( 'DarPaso...begin:', msg );
{$ENDIF}
{$IFDEF DEBUG_COMS}
  writeln(fDarPaso, 'paso= ', #9, sala.globs.kPaso_);
{$ENDIF}
  if leerFichaComunicado(msg.WParam, @comunicado) > 0 then
  begin
    idTareaActual:= comunicado.idTarea;
    if levantarDatosComunicado(msg.WParam, nil, 0) > 0 then
    begin
      codRespuesta:= sala.irAPaso(Msg.LParam-1);

      uLibFuncionesComunes.invertirComunicado(comunicado);
      comunicado.codigoMsg:= uMsgsDespachador.MSGP_RECIBIR_RESPUESTA;
      comunicado.nBytesDatos:= xSizeOf(codRespuesta) + xSizeOf(sala.globs.kPaso_);
      datosSalientes:= TBuffWriter.Create(comunicado.nBytesDatos);
      datosSalientes.xInteger(codRespuesta);
      datosSalientes.xInteger(sala.globs.kPaso_);

      resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));      
      nIntentosComunicacion:= 1;
      while (resRespuesta = 0) and (nIntentosComunicacion < MAX_REINTENTOS_COMUNICACION) do
      begin
        sleep(sleepComs);
        nIntentosComunicacion:= nIntentosComunicacion + 1;
        resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));        
      end;
      if (resRespuesta = 0) then
        logError(codErrorToString(ERROR_NO_SE_PUDO_COMUNICAR_LA_TAREA));
      datosSalientes.Free;
    end
    else
      logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL));
  end
  else
    logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL));
{$IFDEF CONLOG}
  conlog( 'DarPaso...end:'+IntToStr( idTareaActual ), msg );
{$ENDIF}
  idTareaActual:= 0;
end;

procedure TOptDisV2.msgp_Estado(var Msg: TMessage);
var
  comunicado: TFichaComunicado;
  datosSalientes: TBuffWriter;

  resRespuesta, nIntentosComunicacion: Integer;
begin
  if leerFichaComunicado(msg.WParam, @comunicado) > 0 then
  begin
    if levantarDatosComunicado(msg.WParam, nil, 0) > 0 then
    begin
      uLibFuncionesComunes.invertirComunicado(comunicado);
      comunicado.codigoMsg:= uMsgsDespachador.MSGP_RECIBIR_RESPUESTA;
      comunicado.nBytesDatos:= xSizeOf(idTareaActual);
      datosSalientes:= TBuffWriter.Create(comunicado.nBytesDatos);
      datosSalientes.xCardinal(idTareaActual);

      resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      nIntentosComunicacion:= 1;
      while (resRespuesta = 0) and (nIntentosComunicacion < MAX_REINTENTOS_COMUNICACION) do
      begin
        Sleep(sleepComs);
        nIntentosComunicacion:= nIntentosComunicacion + 1;
        resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      end;
      if (resRespuesta = 0) then
        logError(codErrorToString(ERROR_NO_SE_PUDO_COMUNICAR_LA_TAREA));
      datosSalientes.Free;
    end
    else
      logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL));
  end
  else
    logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL));
end;

procedure TOptDisV2.msgp_Llenar_Rangos_Y_Dar_Paso(var Msg: TMessage);
var
  comunicado: TFichaComunicado;
  nRangos: Integer;
  estrellasIni: TDAofNInt;
  costosFuturos: TDAOfDAOfNreal;
  datosEntrantes: TBuffReader;
  datosSalientes: TBuffWriter;

  codRespuesta: Integer;
  resRespuesta, nIntentosComunicacion: Integer;
  i: Integer;

{$IFDEF DEBUG_COMS}
  idbg, idbg2: Integer;
{$ENDIF}
begin
{$IFDEF CONLOG}
  conlog( 'LlenarYDarPaso...begin:', msg );
{$ENDIF}
  if leerFichaComunicado(msg.WParam, @comunicado) > 0 then
  begin
    idTareaActual:= comunicado.idTarea;
    datosEntrantes:= TBuffReader.Create(comunicado.pdatos, comunicado.nBytesDatos);
    datosEntrantes.xInteger(nRangos);
    SetLength(estrellasIni, nRangos);
    SetLength(costosFuturos, nRangos);
    for i:= 0 to nRangos - 1 do
    begin
      datosEntrantes.xInteger(estrellasIni[i]);
      datosEntrantes.xCompressedTDAOfNReal(costosFuturos[i], uMsgsOptDisV2.tipoCompresionReales);
    end;
    datosEntrantes.Free;

    if levantarDatosComunicado(msg.WParam, nil, 0) > 0 then
    begin

      codRespuesta:= sala.llenarRangoDeEstrellasYDarPaso(estrellasIni, costosFuturos, msg.lparam);

      uLibFuncionesComunes.invertirComunicado(comunicado);
      comunicado.codigoMsg:= uMsgsDespachador.MSGP_RECIBIR_RESPUESTA;
      comunicado.nBytesDatos:= xSizeOf(codRespuesta) + xSizeOf(sala.globs.kPaso_);
      datosSalientes:= TBuffWriter.Create(comunicado.nBytesDatos);
      datosSalientes.xInteger(codRespuesta);
      datosSalientes.xInteger(sala.globs.kPaso_);

      resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      nIntentosComunicacion:= 1;
      while (resRespuesta = 0) and (nIntentosComunicacion < MAX_REINTENTOS_COMUNICACION) do
      begin
        Sleep(sleepComs);
        nIntentosComunicacion:= nIntentosComunicacion + 1;
        resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      end;
      if (resRespuesta = 0) then
        logError(codErrorToString(ERROR_NO_SE_PUDO_COMUNICAR_LA_TAREA));
      datosSalientes.Free;
    end
    else
      logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL));
  end
  else
    logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL));
{$IFDEF CONLOG}
 conlog( 'LlenarYDarPaso...end:'+IntToStr(idTareaActual), msg );
 {$ENDIF}
  idTareaActual:= 0;

{$IFDEF DEBUG_COMS}
  write(fLlenarRango, 'paso= ', #9, sala.globs.kPaso_);
  for idbg:= 0 to high(costosFuturos) do
  begin
   write(fLlenarRango, #9, 'estrellasIni[', idbg, ']= ', #9, estrellasIni[idbg]);
    for idbg2:= 0 to high(costosFuturos[idbg]) do
      write(fLlenarRango, #9, FloatToStrF(costosFuturos[idbg][idbg2], ffGeneral, 6, 3));
  end;
  writeln(fLlenarRango);
{$ENDIF}
end;

procedure TOptDisV2.msgp_Llenar_Rangos_Dar_Paso_Y_Calcular_Rango(var Msg: TMessage);
var
  comunicado: TFichaComunicado;
  nRangos: Integer;
  estrellasIni: TDAofNInt;
  costosFuturos: TDAOfDAOfNreal;
  estrellaIniCalc, estrellaFinCalc: Integer;
  datosEntrantes: TBuffReader;
  datosSalientes: TBuffWriter;

  codRespuesta: Integer;
  resRespuesta, nIntentosComunicacion: Integer;
  i: Integer;

{$IFDEF DEBUG_COMS}
  idbg, idbg2: Integer;
{$ENDIF}
begin
{$IFDEF CONLOG}
  conlog( 'LlenarDarPasoYCalcular...begin:', msg );
{$ENDIF}
  if leerFichaComunicado(msg.WParam, @comunicado) > 0 then
  begin
    idTareaActual:= comunicado.idTarea;
    datosEntrantes:= TBuffReader.Create(comunicado.pdatos, comunicado.nBytesDatos);
    datosEntrantes.xInteger(nRangos);
    SetLength(estrellasIni, nRangos);
    SetLength(costosFuturos, nRangos);
    for i:= 0 to nRangos - 1 do
    begin
      datosEntrantes.xInteger(estrellasIni[i]);
      datosEntrantes.xCompressedTDAOfNReal(costosFuturos[i], uMsgsOptDisV2.tipoCompresionReales);
    end;
    datosEntrantes.xInteger(estrellaIniCalc);
    datosEntrantes.xInteger(estrellaFinCalc);
    datosEntrantes.Free;

    if levantarDatosComunicado(msg.WParam, nil, 0) > 0 then
    begin
      if msg.LParam mod 100 = 0 then
        writeln('TOptDisV2.msgp_Llenar_Rangos_Dar_Paso_Y_Calcular_Rango: Paso ', msg.LParam);
        
      {codRespuesta:= sala.llenarRangosEstrellasYDarPaso(estrellasIni, costosFuturos, msg.lparam);
      if multiHilo then
        sala.calcularRangoEstrellasMultiCore(estrellaIniCalc, estrellaFinCalc)
      else }

      sala.calcularRangoEstrellas(estrellaIniCalc, estrellaFinCalc, false, false );

      uLibFuncionesComunes.invertirComunicado(comunicado);
      comunicado.codigoMsg:= uMsgsDespachador.MSGP_RECIBIR_RESPUESTA;
      comunicado.nBytesDatos:= xSizeOf(codRespuesta) + xSizeOf(sala.globs.kPaso_) + xCompressedSizeOf(sala.globs.CF.constelacion.fCosto[sala.globs.kPaso_], estrellaIniCalc, estrellaFinCalc, uMsgsOptDisV2.tipoCompresionReales);
      datosSalientes:= TBuffWriter.Create(comunicado.nBytesDatos);
      datosSalientes.xInteger(codRespuesta);
      datosSalientes.xInteger(sala.globs.kPaso_);
      datosSalientes.xCompressedTDAOfNReal(sala.globs.CF.constelacion.fCosto[sala.globs.kPaso_], estrellaIniCalc, estrellaFinCalc, uMsgsOptDisV2.tipoCompresionReales);

      resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      nIntentosComunicacion:= 1;
      while (resRespuesta = 0) and (nIntentosComunicacion < MAX_REINTENTOS_COMUNICACION) do
      begin
        Sleep(sleepComs);
        nIntentosComunicacion:= nIntentosComunicacion + 1;
        resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      end;
      if (resRespuesta = 0) then
        logError(codErrorToString(ERROR_NO_SE_PUDO_COMUNICAR_LA_TAREA));
      datosSalientes.Free;
    end
    else
      logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL));
  end
  else
    logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL));
{$IFDEF CONLOG}
 conlog( 'LlenarDarPasoYCalcular...end:'+IntToStr(idTareaActual), msg );
 {$ENDIF}
  idTareaActual:= 0;

{$IFDEF DEBUG_COMS}
  write(fLlenarRangoDarPasoYCalcular, 'pasoLlenado= '#9, msg.LParam);
  for idbg:= 0 to high(costosFuturos) do
  begin
   write(fLlenarRangoDarPasoYCalcular, #9#9'estrellasIni[', idbg, ']= '#9, estrellasIni[idbg]);
    for idbg2:= 0 to high(costosFuturos[idbg]) - 1 do
      write(fLlenarRangoDarPasoYCalcular, #9, FloatToStrF(costosFuturos[idbg][idbg2], ffGeneral, 6, 3));
    writeln(fLlenarRangoDarPasoYCalcular, #9, FloatToStrF(costosFuturos[idbg][high(costosFuturos[idbg])], ffGeneral, 6, 3));
  end;
  if length(costosFuturos) = 0 then
    Writeln(fLlenarRangoDarPasoYCalcular);
  writeln(fLlenarRangoDarPasoYCalcular, 'pasoCalculado= '#9, sala.globs.kPaso_, #9'estrellaIniCalc= '#9, estrellaIniCalc, #9'estrellaFinCalc= '#9, estrellaFinCalc);
  for idbg:= estrellaIniCalc to estrellaFinCalc - 1 do
    write(fLlenarRangoDarPasoYCalcular, FloatToStrF(sala.globs.CF.constelacion.fCosto[sala.globs.kPaso_][idbg], ffGeneral, 6, 3), #9);
  writeln(fLlenarRangoDarPasoYCalcular, FloatToStrF(sala.globs.CF.constelacion.fCosto[sala.globs.kPaso_][estrellaFinCalc], ffGeneral, 6, 3));
  writeln(fLlenarRangoDarPasoYCalcular);
{$ENDIF}
end;

procedure TOptDisV2.msgp_Get_Estado_Madre_Uniforme(var Msg: TMessage);
var
  comunicado: TFichaComunicado;
  glmaAux: TDAofNInt;
  datosSalientes: TBuffWriter;

  resRespuesta, nIntentosComunicacion: Integer;
  i: Integer;
begin
{$IFDEF CONLOG}
  conlog('Get_Estado_Madre...begin:', msg );
{$ENDIF}
  if leerFichaComunicado(msg.WParam, @comunicado) > 0 then
  begin
    idTareaActual:= comunicado.idTarea;
    if levantarDatosComunicado(msg.WParam, nil, 0) > 0 then
    begin
      uLibFuncionesComunes.invertirComunicado(comunicado);
      comunicado.codigoMsg:= uMsgsDespachador.MSGP_RECIBIR_RESPUESTA;

      SetLength(glmaAux, length(sala.globs.sorteadorUniforme.glma));
      for i:= low(sala.globs.sorteadorUniforme.glma) to high(sala.globs.sorteadorUniforme.glma) do
        glmaAux[i - low(sala.globs.sorteadorUniforme.glma)]:= sala.globs.sorteadorUniforme.glma[i];

      comunicado.nBytesDatos:= xSizeOf(glmaAux) + xSizeOf(sala.globs.sorteadorUniforme.glinext) * 2;
      datosSalientes:= TBuffWriter.Create(comunicado.nBytesDatos);
      datosSalientes.xTDAOfNInt(glmaAux);
      datosSalientes.xInteger(sala.globs.sorteadorUniforme.glinext);
      datosSalientes.xInteger(sala.globs.sorteadorUniforme.glinextp);

      resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      nIntentosComunicacion:= 1;
      while (resRespuesta = 0) and (nIntentosComunicacion < MAX_REINTENTOS_COMUNICACION) do
      begin
        sleep(sleepComs);
        nIntentosComunicacion:= nIntentosComunicacion + 1;
        resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      end;
      if resRespuesta = 0 then
        logError(codErrorToString(ERROR_NO_SE_PUDO_COMUNICAR_LA_TAREA));
      datosSalientes.Free;
      SetLength(glmaAux, 0);
    end
    else
      logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL));
  end
  else
    logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL));
{$IFDEF CONLOG}
  conlog( 'Get_Estado_Madre...end:'+IntToStr( idTareaActual ), msg );
{$ENDIF}
  idTareaActual:= 0;
end;

procedure TOptDisV2.msgp_Set_Estado_Madre_Uniforme(var Msg: TMessage);
var
  comunicado: TFichaComunicado;
  glma: TDAofNInt;
  glinext, glinextp: Integer;
  datosEntrantes: TBuffReader;

  codRespuesta: Integer;
  datosSalientes: TBuffWriter;

  resRespuesta, nIntentosComunicacion: Integer;
{$IFDEF DEBUG_COMS}
  idbg: Integer;
{$ENDIF}
begin
{$IFDEF CONLOG}
  conlog('Set_Estado_Madre...begin:', msg );
{$ENDIF}
  if leerFichaComunicado(msg.WParam, @comunicado) > 0 then
  begin
    idTareaActual:= comunicado.idTarea;
    datosEntrantes:= TBuffReader.Create(comunicado.pdatos, comunicado.nBytesDatos);
    datosEntrantes.xTDAOfNInt(glma);
    datosEntrantes.xInteger(glinext);
    datosEntrantes.xInteger(glinextp);
    datosEntrantes.Free;

    if levantarDatosComunicado(msg.WParam, nil, 0) > 0 then
    begin

      //sala.asignarEstadosFuentesMadreUniforme(glma, glinext, glinextp);

      uLibFuncionesComunes.invertirComunicado(comunicado);
      comunicado.codigoMsg:= uMsgsDespachador.MSGP_RECIBIR_RESPUESTA;

      codRespuesta:= 1;
      comunicado.nBytesDatos:= xSizeOf(codRespuesta);

      datosSalientes:= TBuffWriter.Create(comunicado.nBytesDatos);
      datosSalientes.xInteger(codRespuesta);
      resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      nIntentosComunicacion:= 1;
      while (resRespuesta = 0) and (nIntentosComunicacion < MAX_REINTENTOS_COMUNICACION) do
      begin
        sleep(sleepComs);
        nIntentosComunicacion:= nIntentosComunicacion + 1;
        resRespuesta:= comunicar(@comunicado, datosSalientes.pBuff, trunc(timeOutComsCte + timeOutComsPorByte * comunicado.nBytesDatos));
      end;
      if resRespuesta = 0 then
        logError(codErrorToString(ERROR_NO_SE_PUDO_COMUNICAR_LA_TAREA));
      datosSalientes.Free;
    end
    else
      logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_LOS_DATOS_DEL_COMUNICADO_DESDE_LA_DLL));
  end
  else
    logError(codErrorToString(ERROR_NO_SE_PUDO_TRAER_EL_COMUNICADO_DESDE_LA_DLL));
{$IFDEF CONLOG}
  conlog( 'Set_Estado_Madre...end:'+IntToStr( idTareaActual ), msg );
{$ENDIF}
  idTareaActual:= 0;
end;

{$IFDEF LINUX}
constructor TOptDisV2.Create(AOwner: TComponent);
{$ELSE}
procedure TOptDisV2.FormCreate(Sender: TObject);
{$ENDIF}
begin
{$IFDEF LINUX}
  inherited Create(AOwner);
  installHandlers;
  recolectar:= false;
{$ENDIF}
  inicializar;
{$IFDEF LINUX}
  myIdEnLaDll:= registrarAplicacion( uMsgsOptDisV2.AppName, fpGetPid);
{$ELSE}
  myIdEnLaDll:= registrarAplicacion( uMsgsOptDisV2.AppName, handle);
{$ENDIF}
  uconstantesSimSEE.crearDirectorios;
  writeln(uMsgsOptDisV2.AppName + '.idAplic= ', myIdEnLaDll);
  if myIdEnLaDll = 0 then
  begin
    logError('ERROR: ' + codErrorToString(getUltimoError));
{$IFDEF WINDOWS}
    PostQuitMessage(0);
{$ELSE}
    exit;
{$ENDIF}
  end
  else
  begin
    sysutils.DecimalSeparator := '.';
    DecimalSeparator:= '.';
    DateSeparator:= '/';
    ShortDateFormat:='d/m/y';
    uInicioYFinal.AlInicio;
    if ParamCount > 0 then
    begin
      try
        CargarSala(dirbase + ParamStr(1));
        sala.inicializarOptimizacion(nil, nil);
        //sala.inicializarVariablesMultiCore(false);
      except
        On E: Exception do
        begin
          ShowMessage('Error cargando la Sala.' + #13 + E.Message);
{$IFDEF WINDOWS}
          PostQuitMessage(0);
{$ELSE}
          Exit;
{$ENDIF}
        end;
      end
    end
    else
      sala:= nil;
    idTareaActual:= 0;
    //La prioridad BELOW_NORMAL_PRIORITY_CLASS solo esta a partir de windows XP
    //Si no podemos fijarla en BELOW_NORMAL_PRIORITY_CLASS la fijamos en IDLE
{$IFDEF WINDOWS}
    if not SetPriorityClass(GetCurrentProcess, BELOW_NORMAL_PRIORITY_CLASS) then
      SetPriorityClass(GetCurrentProcess, IDLE_PRIORITY_CLASS);
    self.Top:= Screen.Height div 2;
    self.Left:= Screen.Width - Self.Width - 15;
{$ELSE}
    recolectar:= true;
{$ENDIF}
{$IFDEF DEBUG_COMS}
    AssignFile(fCalcularRango, 'calcRango.xlt');
    Rewrite(fCalcularRango);
    AssignFile(fLlenarRango, 'llenarRango.xlt');
    Rewrite(fLlenarRango);
    AssignFile(fDarPaso, 'darPaso.xlt');
    Rewrite(fDarPaso);
    AssignFile(fLlenarRangoDarPasoYCalcular, 'llenarRangoDarPasoYCalcular.xlt');
    Rewrite(fLlenarRangoDarPasoYCalcular);
{$ENDIF}
  end;
end;

{$IFDEF LINUX}
procedure TOptDisV2.Free;
{$ELSE}
procedure TOptDisV2.FormDestroy(Sender: TObject);
{$ENDIF}
begin
  if myIdEnLaDll > 0 then
  begin
    desregistrarAplicacion(myIdEnLaDll);
  end;
  if sala <> NIL then
  begin
    if multiHilo then
      //sala.liberarVariablesMultiCore;
    sala.Free;
  end;
  finalizar;
{$IFDEF DEBUG_COMS}
  CloseFile(fCalcularRango);
  CloseFile(fLlenarRango);
  CloseFile(fDarPaso);
  CloseFile(fLlenarRangoDarPasoYCalcular);
{$ENDIF}
end;

procedure TOptDisV2.CargarSala(archiSala: String);
begin
  toOSBarraDirs(archiSala);
  
  Writeln('TOptDisV2.CargarSala: ' + archiSala);

	if Sala <> nil then
  begin
    //sala.liberarVariablesMultiCore;
		Sala.Free;
  end;
  try
    sala:= TSalaDeJuego.cargarSala(archiSala, '__principal__', true);
    sala.setDirCorrida(archiSala);
  except
    on E: Exception do
    begin
      Writeln('Error cargando la sala:');
      writeln(E.Message);
      raise;
    end;
  end;
end;

end.
