unit uTareas;

interface

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

type
  TEstadoTarea = (Esperando_Despacho, En_Ejecucion, Terminada, Fallada);
  //Transiciones de estados de las tareas
  //ED-->EE enviarPedido responde <> 0
  //EE-->T recibo respuesta
  //EE-->ED vence el timeOut para la tarea y no recibí respuesta
  //ED-->F vence el timeOutGlobal para la lista de tareas
  //EE-->F vence el timeOutGlobal para la lista de tareas

  TFichaTarea = class
    public
      //Datos conocidos por las aplicaciones
      nomServicio: String;
      timeOutMSecs: Cardinal;
      comunicado: TFichaComunicado;
      parametrosEntrada: TBuffWriter;
      resultados: TBuffReader;

      estado: TEstadoTarea;
      tiempoCom: NReal;  //Tiempo que se tardo en enviar la orden de ejecutar la tarea en msecs
      tiempoEjec: NReal; //Tiempo que tardo el nodo en procesar la tarea en msecs
      //Si la tarea esta en el estado Sin_Enviar es indeterminado
      //Si la tarea esta en el estado En_Ejecucion o Terminada es el id del nodo
      //al que se le pidio la ultima ejecución
      idNodoEjecutor: Cardinal;
      forzarNodoEjecutor: boolean;//si es true indica que idNodoEjecutor no debe cambiar
      debeEjecutarse: boolean;    //indica que si la tarea no se ejecuto al finalizar
                                  //timeOut global la ejecución no puede continuar
                                  //si es false y la tarea falló la ejecución continua
                                  //sin que la tarea se haya ejecutado

      //Datos de manejo del despachador
      dtIniCom: Int64; //El momento en que se envía el pedido de ejecución
      dtIniEjec:Int64; //el momento en que se confirma la rececpción del pedido
      dtVencimiento: Int64;  //El momento en que se envía el pedido de ejecución
                             //mas el timeOut de la tarea

      usarTareaParaMedirVelocidad: Boolean;
      pesoRelativo: NReal;        //El peso que tiene la tarea en la lista de tareas
                                  //a ejecutar

      //Crea una ficha de tarea para ser ejecutada por cualquier nodo
      //Si debeEjecutarse es true y la tarea no logra ejecutarse en el tiempo
      //que tiene asignada su lista de tareas el despachador lanza una excepcion
      Constructor Create(nomServicio: String; codigoMsg: Integer;
                         parametrosEntrada: TBuffWriter; lParam: Integer;
                         timeOutMSecs: Cardinal;
                         debeEjecutarse: boolean); overload;
      //Crea una ficha de tarea para ser ejecutada por el nodo con id nodoEjecutor
      //Si debeEjecutarse es true y la tarea no logra ejecutarse en el tiempo
      //que tiene asignada su lista de tareas el despachador lanza una excepcion
      //Si forzarNodoEjecutor es true el único nodo que puede ejecutar la tarea
      //es nodoEjecutor, si es false primero se intenta con nodoEjecutor y si
      //falla se intenta con otro
      Constructor Create(nomServicio: String; codigoMsg: Integer;
                         parametrosEntrada: TBuffWriter; lParam: Integer;
                         timeOutMSecs: Cardinal;
                         debeEjecutarse: boolean;
                         nodoEjecutor: Cardinal; forzarNodoEjecutor: boolean); overload;
      procedure setPesoRelativo(pesoRelativo: NReal; usarTareaParaMedirVelocidad: boolean);
      procedure Free;
      procedure dumpToText(var f: TextFile; strIndentacion: String);
  end;


implementation

var
  cntTareas: Cardinal;

function nextIdTarea: Cardinal;
begin
  cntTareas:= cntTareas + 1;
  result:= cntTareas;
end;

//======================
//Métodos de TFichaTarea
//----------------------

Constructor TFichaTarea.Create(nomServicio: String; codigoMsg: Integer;
                   parametrosEntrada: TBuffWriter; lParam: Integer;
                   timeOutMSecs: Cardinal; debeEjecutarse: boolean);
begin
  inherited Create;
  self.nomServicio:= nomServicio;
  self.parametrosEntrada:= parametrosEntrada;
  self.timeOutMSecs:= timeOutMSecs;
  self.debeEjecutarse:= debeEjecutarse;
  comunicado.idTarea:= nextIdTarea;
  comunicado.codigoMsg:= codigoMsg;
  comunicado.lParam:= lParam;
  usarTareaParaMedirVelocidad:= false;
  pesoRelativo:= 0;
  if parametrosEntrada <> NIL then
  begin
    comunicado.nBytesDatos:= parametrosEntrada.tamBuff;
    comunicado.pdatos:= PLArrOfBytes(parametrosEntrada.pBuff);
  end
  else
  begin
    comunicado.nBytesDatos:= 0;
    comunicado.pdatos:= NIL;
  end;
  forzarNodoEjecutor:= false;
  idNodoEjecutor:= 0;
  estado:= Esperando_Despacho;
end;

Constructor TFichaTarea.Create(nomServicio: String; codigoMsg: Integer;
                   parametrosEntrada: TBuffWriter; lParam: Integer;
                   timeOutMSecs: Cardinal; debeEjecutarse: boolean;
                   nodoEjecutor: Cardinal; forzarNodoEjecutor: boolean);
begin
  inherited Create;
  self.nomServicio:= nomServicio;
  self.parametrosEntrada:= parametrosEntrada;
  self.timeOutMSecs:= timeOutMSecs;
  self.debeEjecutarse:= debeEjecutarse;
  comunicado.idTarea:= nextIdTarea;
  comunicado.codigoMsg:= codigoMsg;
  comunicado.lParam:= lParam;
  usarTareaParaMedirVelocidad:= false;
  pesoRelativo:= 0;
  if parametrosEntrada <> NIL then
  begin
    comunicado.nBytesDatos:= parametrosEntrada.tamBuff;
    comunicado.pdatos:= PLArrOfBytes(parametrosEntrada.pBuff);
  end
  else
  begin
    comunicado.nBytesDatos:= 0;
    comunicado.pdatos:= NIL;
  end;
  self.forzarNodoEjecutor:= forzarNodoEjecutor;
  if nodoEjecutor <> 0 then
    self.idNodoEjecutor:= nodoEjecutor
  else
    self.idNodoEjecutor:= getIdNodoLocal;
  estado:= Esperando_Despacho;
end;

procedure TFichaTarea.setPesoRelativo(pesoRelativo: NReal; usarTareaParaMedirVelocidad: boolean);
begin
  self.usarTareaParaMedirVelocidad:= usarTareaParaMedirVelocidad;
  self.pesoRelativo:= pesoRelativo;
end;

procedure TFichaTarea.Free;
begin
  if parametrosEntrada <> NIL then
    parametrosEntrada.Free;
  if resultados <> NIL then
    resultados.Free;
  inherited Free;
end;

procedure dumpComunicadoToText(var f: TextFile; comunicado: TFichaComunicado; strIndentacion: String);
begin
  Writeln(f, strIndentacion, 'idNodoOrigen= ', comunicado.idNodoOrigen);
  Writeln(f, strIndentacion, 'idOrigen= ', comunicado.idOrigen);
  Writeln(f, strIndentacion, 'idNodoDestino= ', comunicado.idNodoDestino);
  Writeln(f, strIndentacion, 'idDestino= ', comunicado.idDestino);
  Writeln(f, strIndentacion, 'codigoMsg= ', comunicado.codigoMsg);
  Writeln(f, strIndentacion, 'nBytesDatos= ', comunicado.nBytesDatos);
  Writeln(f, strIndentacion, 'lParam= ', comunicado.lParam);
  Writeln(f, strIndentacion, 'idTarea= ', comunicado.idTarea);
end;

function estadoTareaToString(estado: TEstadoTarea) : String;
begin
  case estado of
    Esperando_Despacho  : result:= 'Esperando_Despacho';
    En_Ejecucion        : result:= 'En_Ejecucion';
    Terminada           : result:= 'Terminada';
  end;
end;

procedure TFichaTarea.dumpToText(var f: TextFile; strIndentacion: String);
begin
  Writeln(f, strIndentacion, 'nomServicio= ', nomServicio);
  Writeln(f, strIndentacion, 'timeOutMSecs= ', timeOutMSecs);
  dumpComunicadoToText(f, comunicado, strIndentacion);
  Writeln(f, strIndentacion, 'estado= ', estadoTareaToString(estado));
  Writeln(f, strIndentacion, 'tiempoCom= ', tiempoCom);
  Writeln(f, strIndentacion, 'tiempoEjec= ', tiempoEjec);
  Writeln(f, strIndentacion, 'debeEjecutarse= ', debeEjecutarse);
  Writeln(f, strIndentacion, 'forzarNodoEjecutor= ', forzarNodoEjecutor);
  Writeln(f, strIndentacion, 'idNodoEjecutor= ', idNodoEjecutor);
  Writeln(f, strIndentacion, 'dtIniCom= ', dtIniCom);
  Writeln(f, strIndentacion, 'dtIniEjec= ', dtIniEjec);
  Writeln(f, strIndentacion, 'dtVencimiento= ', dtVencimiento);
end;

initialization
  cntTareas:= 0;

end.
