unit udespachador_temporizadores;

{$mode delphi}

interface

uses
  Classes, SysUtils, uDatosNodo;


type
  TTemporizador = class
    public
      nMediciones: Integer;//La cantidad de mediciones de tiempo que se tienen
                           //para la tarea
      conjuntoDeEjecucion: TConjuntoDeEjecucion;
      despachador: TDespachador;

      Constructor Create(conjuntoDeEjecucion: TConjuntoDeEjecucion; despachador: TDespachador); virtual;
//      procedure empezarNuevaMedicion; virtual; abstract;
      procedure addMedicion(idNodo: Cardinal; pesoRelSobreT: NReal); virtual; abstract;
      procedure actualizarVelocidades; virtual; abstract;
      procedure eliminarMedicion(iNodo: Integer); virtual; abstract;
  end;

  TTemporizadorUniOperacionPromedio = class(TTemporizador)
    public
      maxNMediciones: Integer;
      Constructor Create(conjuntoDeEjecucion: TConjuntoDeEjecucion; despachador: TDespachador; maxNMediciones: Integer); reintroduce;
      procedure addMedicion(idNodo: Cardinal; pesoRelSobreT: NReal); override;
      procedure actualizarVelocidades; override;
      procedure eliminarMedicion(iNodo: Integer); override;
    private
      pesosRelsSobreTs: TDAofNReal;
  end;

  TTemporizadorUniOperacionPromedioMovil = class(TTemporizador)
    public
      Constructor Create(conjuntoDeEjecucion: TConjuntoDeEjecucion; despachador: TDespachador; nMuestras: Integer); reintroduce;
      procedure addMedicion(idNodo: Cardinal; pesoRelSobreT: NReal); override;
      procedure actualizarVelocidades; override;
      procedure eliminarMedicion(iNodo: Integer); override;
    private
      iDatoAReemplazar, iUltimoDato, tamanioBuff, nMuestras: Integer;
      invNMuestras: NReal;
      pesosRelsSobreTs: TMatOfNReal;
  end;


implementation

//========================
//Métodos de TTemporizador
//------------------------

Constructor TTemporizador.Create(conjuntoDeEjecucion: TConjuntoDeEjecucion; despachador: TDespachador);
begin
  inherited Create;
  self.conjuntoDeEjecucion:= conjuntoDeEjecucion;
  self.despachador:= despachador;
  if self.conjuntoDeEjecucion <> despachador.conjuntoDeEjecucion then
    raise Exception.Create('TTemporizador.Create: el temporizador y el despachador deben tener la misma lista de datos de nodos');
  nMediciones:= 0;
end;

//============================================
//Métodos de TTemporizadorUniOperacionPromedio
//--------------------------------------------

Constructor TTemporizadorUniOperacionPromedio.Create(conjuntoDeEjecucion: TConjuntoDeEjecucion; despachador: TDespachador; maxNMediciones: Integer);
begin
  inherited Create(conjuntoDeEjecucion, despachador);
  SetLength(pesosRelsSobreTs, conjuntoDeEjecucion.Count);
  if maxNMediciones = 0 then
    self.maxNMediciones:= MAXINT
  else
    self.maxNMediciones:= maxNMediciones;
end;

procedure TTemporizadorUniOperacionPromedio.addMedicion(idNodo: Cardinal; pesoRelSobreT: NReal);
begin
  pesosRelsSobreTs[conjuntoDeEjecucion.getINodo(idNodo)]:= pesoRelSobreT;
end;

procedure TTemporizadorUniOperacionPromedio.actualizarVelocidades;
var
  i: Integer;
  invNMedicionesMasUno: NReal;
  datosNodo: TDatosNodo;
  smf_Procesando: TMutex;
begin
  if nMediciones < maxNMediciones then
  begin
{$IFDEF WINDOWS}
    smf_Procesando:= TMutex.Create(despachador.nom_smf_Procesando);
{$ELSE}
    smf_Procesando:= TMutex.Create(despachador.nom_smf_Procesando, 1);
{$ENDIF}
    if smf_Procesando.Get(timeOutSems) then
    begin
      invNMedicionesMasUno:= 1 / (nMediciones + 1);
      for i:= 0 to high(pesosRelsSobreTs) do
      begin
        datosNodo:= TDatosNodo(conjuntoDeEjecucion[i]);
        datosNodo.velocidad:= (datosNodo.velocidad * nMediciones + pesosRelsSobreTs[i]) * invNMedicionesMasUno;
        despachador.getNodo(datosNodo.idNodo).velocidad:= datosNodo.velocidad;
      end;
      nMediciones:= nMediciones + 1;
      despachador.nodosDisponibles.Sort(sortFichaNodoByVelocidad);
      smf_Procesando.Release;
    end;
    smf_Procesando.Free;
  end;
end;

procedure TTemporizadorUniOperacionPromedio.eliminarMedicion(iNodo: Integer);
var
  i: Integer;
  newPesosRelsSobreTs: TDAofNReal;
begin
  SetLength(newPesosRelsSobreTs, length(pesosRelsSobreTs) - 1);
  for i:= 0 to iNodo - 1 do
    newPesosRelsSobreTs[i]:= pesosRelsSobreTs[i];
  for i:= iNodo + 1 to high(pesosRelsSobreTs) do
    newPesosRelsSobreTs[i - 1]:= pesosRelsSobreTs[i];
  SetLength(pesosRelsSobreTs, 0);
  pesosRelsSobreTs:= newPesosRelsSobreTs;
end;

//=================================================
//Métodos de TTemporizadorUniOperacionPromedioMovil
//-------------------------------------------------

Constructor TTemporizadorUniOperacionPromedioMovil.Create(conjuntoDeEjecucion: TConjuntoDeEjecucion; despachador: TDespachador; nMuestras: Integer);
var
  i: Integer;
begin
  inherited Create(conjuntoDeEjecucion, despachador);
  iDatoAReemplazar:= 0;
  self.nMuestras:= nMuestras;
  invNMuestras:= 1 / nMuestras;
  self.tamanioBuff:= nMuestras + 1;
  SetLength(pesosRelsSobreTs, conjuntoDeEjecucion.Count);
  for i:= 0 to High(pesosRelsSobreTs) do
    SetLength(pesosRelsSobreTs[i], tamanioBuff);
end;

procedure TTemporizadorUniOperacionPromedioMovil.addMedicion(idNodo: Cardinal; pesoRelSobreT: NReal);
begin
  pesosRelsSobreTs[conjuntoDeEjecucion.getINodo(idNodo)][iDatoAReemplazar]:= pesoRelSobreT;
end;

procedure TTemporizadorUniOperacionPromedioMovil.actualizarVelocidades;
var
  i: Integer;
  invNMedicionesMasUno: NReal;
  datosNodo: TDatosNodo;
  smf_Procesando: TMutex;
begin
  iUltimoDato:= iDatoAReemplazar;
  iDatoAReemplazar:= iDatoAReemplazar + 1;
  if iDatoAReemplazar = tamanioBuff then
    iDatoAReemplazar:= 0;

{$IFDEF WINDOWS}
  smf_Procesando:= TMutex.Create(despachador.nom_smf_Procesando);
{$ELSE}
  smf_Procesando:= TMutex.Create(despachador.nom_smf_Procesando, 1);
{$ENDIF}
  if smf_Procesando.Get(timeOutSems) then
  begin
    if nMediciones < nMuestras then//Si no llegue al número de muestras deseado hago el promedio normal
    begin
      invNMedicionesMasUno:= 1 / (nMediciones + 1);
      for i:= 0 to high(pesosRelsSobreTs) do
      begin
        datosNodo:= TDatosNodo(conjuntoDeEjecucion[i]);
        datosNodo.velocidad:= (datosNodo.velocidad * nMediciones + pesosRelsSobreTs[i][iUltimoDato]) * invNMedicionesMasUno;
        despachador.getNodo(datosNodo.idNodo).velocidad:= datosNodo.velocidad;
      end;
    end
    else //Hago el promedio movil, saco el valor mas viejo y agrego el mas nuevo
    begin
      for i:= 0 to high(pesosRelsSobreTs) do
      begin
        datosNodo:= TDatosNodo(conjuntoDeEjecucion[i]);
        datosNodo.velocidad:= (datosNodo.velocidad * nMuestras + pesosRelsSobreTs[i][iUltimoDato] - pesosRelsSobreTs[i][iDatoAReemplazar]) * invNMuestras;
        despachador.getNodo(datosNodo.idNodo).velocidad:= datosNodo.velocidad;
      end;
    end;
    nMediciones:= nMediciones + 1;
    despachador.nodosDisponibles.Sort(sortFichaNodoByVelocidad);
    smf_Procesando.Release;
  end;
  smf_Procesando.Free;
end;

procedure TTemporizadorUniOperacionPromedioMovil.eliminarMedicion(iNodo: Integer);
var
  i: Integer;
  newPesosRelsSobreTs: TMatOfNReal;
begin
  SetLength(newPesosRelsSobreTs, length(pesosRelsSobreTs) - 1);
  for i:= 0 to iNodo - 1 do
    newPesosRelsSobreTs[i]:= pesosRelsSobreTs[i];
  for i:= iNodo + 1 to high(pesosRelsSobreTs) do
    newPesosRelsSobreTs[i - 1]:= pesosRelsSobreTs[i];
  SetLength(pesosRelsSobreTs, 0);
  pesosRelsSobreTs:= newPesosRelsSobreTs;
end;

end.

