unit uMsgRetardados;

//{$DEFINE debug}

interface

uses

  Classes, SysUtils, dateutils,

  uglobsharedmem, unettopostypes, uconstantes_nettopos, unettopos,
  uConstantesSimSEE,
  {$IFDEF LINUX}
    cthreads,
    baseunix,
    unix,
    uEmuladorWinIPC in '../fctopos/IPC/Linux/uemuladorwinipc.pas',
    uKeyDir in '../libnettopos/ukeydir.pas',
    uWinMsgs in '../fctopos/IPC/Linux/uwinmsgs.pas',
    pthreads
  {$ELSE}
   Messages,
   ipcthrd,
   windows
  {$ENDIF}
  ;

type

  PFichaMsgRetardado = ^TFichaMsgRetardado;
  TFichaMsgRetardado = record
    fc: TFichaComunicado;
    nSecs: Integer;
    nSecsParaSerDespachado: Integer;
    periodico: Boolean;
    codigoMsg: Integer;
    idTimer: DWORD;
    idMensaje: Integer;
  end;


{$IFDEF LINUX}
  { TMensajesRetardados }

  TMensajesRetardados=class(TThread)

    flg_msg : Boolean;
    nSecsProxAlrm: cuint;

    constructor Create;

    procedure setAlrm (nSecs: integer);
    procedure waitAlrm;
    procedure Execute; override;


  end;
{$ENDIF}


var

  lst_Msg: TList;

  dt_ultimoCambio: TDateTime = 0;
  nSecsAlrmActual: Integer = 0;

  {$IFDEF LINUX}
   sigs: sigset_t;
   msgsRetardados: TMensajesRetardados;
  {$ELSE}
   ID_Timer: Integer = 1;
  {$ENDIF}


{Agrega un mensaje a lista, devuelve el identificador del mensaje}
function agendar_msgRetardado ( fc:TFichaComunicado; codigoMsg: Integer; nSecs: Integer; periodico: Boolean ):Integer;

{Desceunta tics a la ficha de mensajes}
function actualizar: Boolean;

{Quita el mensaje con id=idMsg y re-arma la alarma segun corresponda }
function desagendar_msgRetardado ( idMensaje: Integer ): Boolean;

{$IFDEF WINDOWS}

 procedure TimerProc(_para1:HWND; _para2:UINT; _para3:UINT; _para4:DWORD);stdcall;
{$ENDIF}

implementation


function agendar_msgRetardado(fc: TFichaComunicado; codigoMsg:Integer; nSecs: Integer;
  periodico: Boolean): Integer;
var

  smf: TMutex;
  pfcr: PFichaMsgRetardado;
  min: Integer;
  nSecsTranscurridos: Integer;
  i: Integer;

begin

  {$IFDEF LINUX}
   smf:= TMutex.Create( keySmfMensRetardado, 1);
  {$ELSE}
   smf:= TMutex.Create(nom_smf_mens_retardados);
  {$ENDIF}

  if not smf.Get(500) then
    begin
      result:= -1;
      exit;
    end;

  if nSecsAlrmActual = 0 then
    begin
      nSecsAlrmActual:= nSecs;
      dt_ultimoCambio:= now;
    end
  else
    begin

      nSecsTranscurridos:= SecondsBetween(dt_ultimoCambio, now);
      for i := 0 to lst_Msg.Count - 1 do
        begin
          pfcr := lst_Msg.Items[i];
          pfcr^.nSecsParaSerDespachado := pfcr^.nSecsParaSerDespachado - nSecsTranscurridos;
        end;
      if nSecs > nSecsAlrmActual - nSecsTranscurridos then
        nSecsAlrmActual := nSecsAlrmActual - nSecsTranscurridos
      else
        nSecsAlrmActual := nSecs;
    end;

  {$IFDEF LINUX}
    msgsRetardados.setAlrm(nSecsAlrmActual);
  {$ELSE}
    SetTimer(idAplicYo ,ID_Timer, nSecsAlrmActual*1000, @TimerProc);
  {$ENDIF}
    writeln (TimeToStr(now)+ ' prox alrm en: ',nSecsAlrmActual );
  new(pfcr);
  pfcr^.fc := fc;
  pfcr^.periodico:=periodico;
  pfcr^.nSecs := nSecs;
  pfcr^.nSecsParaSerDespachado := nSecs;
  pfcr^.codigoMsg:= codigoMsg;

  pfcr^.idMensaje := lst_Msg.Add(pfcr);

  result := pfcr^.idMensaje;
  smf.Release;
  smf.Free;

end;

function actualizar: Boolean;
var
 i: Integer;
 pfcr: PFichaMsgRetardado;
 smf: TMutex;
 minimo : Integer;
begin

  {$IFDEF LINUX}
    smf:= TMutex.Create( keySmfMensRetardado, 1);
  {$ELSE}
    smf:= TMutex.Create(nom_smf_mens_retardados);
  {$ENDIF}

  if not smf.Get(500) then
    begin
      result:= False;
      exit;
    end;

  result:= true;
  minimo := MaxInt;

  writeln ('nMensajesR: ',lst_Msg.Count);
  for i := 0 to lst_Msg.Count-1 do
   begin
     pfcr := lst_Msg.Items[i];
     pfcr^.nSecsParaSerDespachado := pfcr^.nSecsParaSerDespachado - nSecsAlrmActual;
     if pfcr^.nSecsParaSerDespachado <= 0 then
       begin
         writeln (' voy a comunicar ');
         comunicar( @(pfcr^.fc), nil, 500);
         writeln (' volvi de comunicar ');
         if pfcr^.periodico then
          begin
            pfcr^.nSecsParaSerDespachado:=pfcr^.nSecs;
            if minimo > pfcr^.nSecsParaSerDespachado then
              minimo := pfcr^.nSecsParaSerDespachado;
          end
         else
          begin
	   Dispose(pfcr);
           lst_Msg.Items[i]:=nil;
          end; 

           {$IFDEF debug}
           writeln('comunico...');
           {$ENDIF}
           result:=true;
       end
     else
       if minimo > pfcr^.nSecsParaSerDespachado then
           minimo := pfcr^.nSecsParaSerDespachado;
   end;


  lst_Msg.Pack;
  if lst_Msg.Count > 0 then
   begin
     nSecsAlrmActual := minimo;
     dt_ultimoCambio:= now;
     {$IFDEF LINUX}
       msgsRetardados.setAlrm(nSecsAlrmActual);
     {$ELSE}
       SetTimer(idAplicYo ,ID_Timer, nSecsAlrmActual*1000, @TimerProc)
     {$ENDIF}
   end
  else
   begin
     {$IFDEF LINUX}

     {$ELSE}
       KillTimer (idAplicYo ,ID_Timer);
       nSecsAlrmActual := 0;
     {$ENDIF}
  end;

  writeln (TimeToStr(now)+ 'prox alrm en: ',nSecsAlrmActual );

  smf.Release;
  smf.Free;

end;

function desagendar_msgRetardado(idMensaje: Integer): Boolean;
var
  pfcr: PFichaMsgRetardado;
  i: Integer;
  smf: TMutex;

begin

  {$IFDEF LINUX}
    smf:= TMutex.Create( keySmfMensRetardado, 1);
  {$ELSE}
    smf:= TMutex.Create(nom_smf_mens_retardados);
  {$ENDIF}
  if not smf.Get(500) then
    begin
      result:= false;
      exit;
    end;

  for i := 0 to lst_Msg.Count-1 do
   begin
     pfcr := lst_Msg.Items[i];
     if pfcr^.idMensaje = idMensaje then
      begin
        Dispose(pfcr);
        lst_Msg.Items[i]:=nil;
      end;

   end;

  lst_Msg.Pack;

  smf.Release;
  smf.Free;

  actualizar;

end;


{$IFDEF LINUX}

constructor TMensajesRetardados.Create;
var
 sigs_: sigset_t;

begin

  inherited Create(true);
  FreeOnTerminate:=true;
  flg_msg:=True;
  self.nSecsProxAlrm:=0;

  FpsigEmptySet(sigs_);
  FpSigAddSet(sigs, SIGALRM);
  pthread_sigmask(SIG_UNBLOCK, @sigs, nil);

end;

procedure TMensajesRetardados.setAlrm(nSecs: integer);
begin
  FpAlarm(nSecs);
end;

procedure TMensajesRetardados.waitAlrm;
begin
  FpPause;
end;

procedure TMensajesRetardados.Execute;
begin

  while flg_msg do
    begin
      actualizar;
      writeln('actializo');
      writeln('A pause');
      self.Suspend;
      writeln('despauso');

    end;
end;

{$ELSE}

procedure TimerProc(_para1:HWND; _para2:UINT; _para3:UINT; _para4:DWORD);stdcall;
begin
 begin
    {$IFDEF debug}
      writeln('tic...  ', _para3);

    {$ENDIF}

    actualizar;

  end;
end;
{$ENDIF}

initialization
begin

 lst_Msg:=TList.Create;

end;

end.
