unit uTareas;

{$mode delphi}

interface

uses
  {$IFDEF LINUX}

  {$ELSE}
   windows,
  {$ENDIF}

  Classes, SysUtils, xmatdefs, unettopos, uglobsharedmem, unettopostypes,
  uconstantes_nettopos, ubuffrw, uConstantesConector, uNodosDeCalculo, dateUtils;

type

  { TTarea }
  TTarea = class
  private


    codigoMsg_: integer;    //*Codigo del mensaje para despachar y crear la tarea en los clientes
    freeBufferDatos_: boolean;    //*Indica si le liberar o no el buffer de datos al destruir la tarea

  public

    _nodo: TNodoCalculo;

    idTarea: cardinal;       //*Identificador de la tarea
    asignada: boolean;       //*Indica si la tarea esta asignada a algun nodo
    _resuelta: boolean;       //*Indica si la tarea esta resuelta

    dtDespacho: TDateTime;   //*Fecha y hora de despacho
    dtResolucion: TDateTime; //*Fecha y hora de resolucion

    tambuffDatos_: cardinal; //*Tamano en bytes del buffer de datos
    bufferDatos_: pointer;     //*Buffer de datos

    tambuffResultados_: cardinal; //*Tamano del buffer de resultados
    bufferResultados_: pointer;     //*Buffer de resultados

    resolverEnLinea_: Boolean;
    procesarEnLinea_: Boolean;


    constructor Crear(codigoMsg: integer; bufferDatos: pointer;
      tambuffDatos: cardinal; resolverEnLinea: Boolean;
      procesarEnLinea: Boolean; freeBufferDatos: boolean);

    constructor CrearDesdeMSG (idCom: Integer; codMsgRespuesta: Integer;
                              resolverEnLinea: Boolean;
                              procesarEnLinea: Boolean;
                              freeBufferDatos: boolean);

    //asigna la tarea a un nodo
    procedure asignar(nodo: TNodoCalculo);


    //manda a realizar la tarea, dependera del codigo del mensaje que procedimiento se
    //ejecutan sobre los datos de la tarea.
    function despacharTarea:Cardinal;

    procedure resuelta;
    procedure guardarResultados (p: pointer; nBytes: Integer);

    procedure resolverTareaEnLinea;virtual;
    procedure resolverTareaFinDelPaso;virtual;

    procedure procesarResultadosEnLinea;virtual;
    procedure procesarResultadosFinDelPaso;virtual;

    function comunicarResultados:Cardinal;

    procedure Destruir;

  end;

  { TListaDeTareas }

  TListaDeTareas=class(TList)
  private
    function GetItems(i: Integer): TTarea;
    procedure SetItems(i: Integer; const AValue: TTarea);

  public

    dt_Ini: TDateTime;
    dt_Fin: TDateTime;
    nSecsEnResolver: NReal;

    constructor Create;
    function agregarTarea(t: TTarea):integer;
    procedure quitarTarea(idTarea:Cardinal);
    function obtenerTarea(idTarea:Cardinal; var t:TTarea):Boolean;

    function getPrimerTareaNOasignada(var t:TTarea): Boolean;
    function getPrimerTareasAsignadaNoResuelta(var t:TTarea): Boolean;

    function tareasResueltas: Boolean;

    //Busca la primer tarea sin asignar, la asigna y la despacha.
    //Sino busca la primer tarea asignada no resuelta, re asigna y despacha.

    procedure despachar (nodo: TNodoCalculo);overload;
    //Despacha n tareas.... n=min{nNodos, nTareas}
    procedure despachar (lstNodos: TListaDeNodosCalculo);overload;

    property Items[i:Integer]:TTarea read GetItems write SetItems;
    procedure Delete(Index: Integer);

    procedure Destruir;
  end;
var
  idTareaGlobal: Integer = 0;

implementation

{ TTarea }

constructor TTarea.Crear(codigoMsg: integer; bufferDatos: pointer;
  tambuffDatos: cardinal; resolverEnLinea: Boolean; procesarEnLinea: Boolean;
  freeBufferDatos: boolean);
begin
  self.idTarea:=idTareaGlobal;

  Inc(idTareaGlobal);

  freeBufferDatos_ := freeBufferDatos;
  codigoMsg_ := codigoMsg;
  tambuffDatos_ := tambuffDatos;
  bufferDatos_ := bufferDatos;
  asignada := False;
  _resuelta := False;

  self.resolverEnLinea_:= resolverEnLinea;
  self.procesarEnLinea_:= procesarEnLinea;


end;

constructor TTarea.CrearDesdeMSG(idCom: Integer; codMsgRespuesta: Integer;
  resolverEnLinea: Boolean; procesarEnLinea: Boolean; freeBufferDatos: boolean);
var
 fc:TFichaComunicado;
begin
   if leerFichaComunicado (idCom, @fc) > 0 then
    begin
      self.codigoMsg_:=codMsgRespuesta;
      self.idTarea:=fc.idTarea;
      self._nodo := TNodoCalculo.Crear (0, fc.idNodoOrigen, 0, fc.idOrigen, 0, false, '', 0);
      asignada := true;
      _resuelta := False;
      self.resolverEnLinea_:=resolverEnLinea;
      self.procesarEnLinea_:=procesarEnLinea;
      self.freeBufferDatos_:=freeBufferDatos;
      if fc.nBytesDatos=0 then
        levantarDatosComunicado(idCom, nil, 0)
      else
        if resolverEnLinea_ then
         begin
           self.bufferDatos_:= fc.pdatos;
           self.tambuffDatos_:= fc.nBytesDatos;
           self.resolverTareaEnLinea;
           self._resuelta:=true;
           self.comunicarResultados;
           levantarDatosComunicado(idCom, nil, 0);
           self.bufferDatos_:= nil;
           self.tambuffDatos_:= 0;
         end
        else
          begin
            levantarDatosComunicado(idCom, self.bufferDatos_, fc.nBytesDatos);
          end;
    end;
end;

procedure TTarea.asignar(nodo: TNodoCalculo);
begin

 self._nodo := nodo;
 self.asignada:=true;

end;

function TTarea.despacharTarea:Cardinal;
var
  fc:TFichaComunicado;
begin

  fc.idNodoOrigen := pm^.idNodoLocal;
  fc.idOrigen:=idAplicYo;
  fc.idNodoDestino:=self._nodo._idnodo;
  fc.idDestino:=_nodo._idaplic;
  fc.codigoMsg:=self.codigoMsg_;
  fc.idTarea:=self.idTarea;
  fc.nBytesDatos:=self.tambuffDatos_;

  if self.bufferDatos_ = nil then
    result:= comunicar(@fc, nil, timeOutComsCte)
  else
    result:= comunicar(@fc, self.bufferDatos_, round (timeOutComsCte+self.tambuffDatos_*timeOutComsPorByte));

   self.dtDespacho:= now();



end;



procedure TTarea.resuelta;
begin
  self._resuelta:= true;
  self.dtResolucion:=now;
end;


procedure TTarea.guardarResultados(p: pointer; nBytes: Integer);
begin
 Getmem(self.bufferResultados_, nBytes);
 Move(p, self.bufferResultados_, nBytes);
 self.tambuffResultados_:=nBytes;
end;

procedure TTarea.resolverTareaEnLinea;
begin

end;


procedure TTarea.resolverTareaFinDelPaso;
begin

end;

procedure TTarea.procesarResultadosEnLinea;
begin

end;

procedure TTarea.procesarResultadosFinDelPaso;
begin

end;

function TTarea.comunicarResultados: Cardinal;
var
  fc:TFichaComunicado;
begin

  fc.idNodoOrigen := pm^.idNodoLocal;
  fc.idOrigen:=idAplicYo;
  fc.idNodoDestino:=_nodo._idnodo;
  fc.idDestino:=_nodo._idaplic;
  fc.codigoMsg:=self.codigoMsg_;
  fc.idTarea:=self.idTarea;
  fc.nBytesDatos:=self.tambuffResultados_;

  if self.bufferResultados_ = nil then
    result:= comunicar(@fc, nil, timeOutComsCte)
  else
    result:= comunicar(@fc, self.bufferResultados_, round (timeOutComsCte+self.tambuffResultados_*timeOutComsPorByte));

   self.dtResolucion:= now();



end;


procedure TTarea.Destruir;
begin
 begin
   if freeBufferDatos_ then
     if bufferDatos_ <> nil then
     begin
       Dispose(bufferDatos_);
     end;

   if bufferResultados_ <> nil then
     begin
       Dispose(bufferResultados_);
     end;
   self.Free;

 end;
end;


{ TListaDeTareas }

function TListaDeTareas.GetItems(i: Integer): TTarea;
begin
  result := inherited Items[i];
end;

procedure TListaDeTareas.SetItems(i: Integer; const AValue: TTarea);
begin
 //no se usa...
end;

constructor TListaDeTareas.Create;
begin
  inherited Create;
  dt_Ini := Now();
  nSecsEnResolver:=0;
end;


function TListaDeTareas.agregarTarea(t: TTarea):integer;
var
 idTarea:Integer;
begin
 result := Add(t);
end;

procedure TListaDeTareas.quitarTarea(idTarea: Cardinal);
var
 i:Integer;
begin
 for i:= 0 to Count-1 do
  if (Items[i].idTarea = idTarea) then
    begin
     self.Delete(i);
     break;
    end;
end;

function TListaDeTareas.obtenerTarea(idTarea: Cardinal; var t: TTarea): Boolean;
var
 i:Integer;
begin
 t:=nil;
 result := false;
 for i:= 0 to Count-1 do
  begin
   if (Items[i].idTarea = idTarea) then
    begin
     t:=Items[i];
     result:= true;
     break;
    end;
  end;
end;

function TListaDeTareas.getPrimerTareaNOasignada(var t: TTarea): Boolean;
var
  i: Integer;
begin
 result:= false;
 for i:= 0 to Count-1 do
  if not self.Items[i].asignada then
   begin
    t := self.Items[i];
    result:= true;
    break;
   end;

end;

function TListaDeTareas.getPrimerTareasAsignadaNoResuelta(var t: TTarea
  ): Boolean;
var
  i: Integer;
begin
 result:= false;
 for i:= 0 to Count-1 do
  if self.Items[i].asignada and not self.Items[i]._resuelta then
   begin
    t := self.Items[i];
    result:= true;
   end;

end;

function TListaDeTareas.tareasResueltas: Boolean;
var
  i: Integer;

begin
  result:=true;
  for i:= 0 to self.Count -1 do
   if not GetItems(i)._resuelta then
    begin
     result:=false;
     break;
     exit;
    end;

  dt_Fin := now();
  nSecsEnResolver:= SecondsBetween(dt_Ini, dt_Fin);


end;

procedure TListaDeTareas.despachar(nodo: TNodoCalculo);
var
  t: TTarea;
begin

  if getPrimerTareaNOasignada(t) then
   begin
    t.asignar(nodo);
    t.despacharTarea;
   end
  else
   if getPrimerTareasAsignadaNoResuelta(t) then
    begin
     t.asignar(nodo);
     t.despacharTarea;
    end;

end;

procedure TListaDeTareas.despachar(lstNodos: TListaDeNodosCalculo);
var
  i: Integer;
  nTareas:Integer;
  nnodos: Integer;
  tope: Integer;
begin

  nTareas:=self.Count;
  nnodos:=lstNodos.Count;

  if nTareas >= nnodos then
   tope:=nnodos
  else
    tope:=nTareas;

  for i := 0 to tope-1 do
   begin
    despachar(lstNodos.Get(i));
   end;

end;

procedure TListaDeTareas.Delete(Index: Integer);
begin
 TTarea(Items[Index]).Destruir;
 inherited Delete(Index);
end;

procedure TListaDeTareas.Destruir;
var
i:Integer;
begin
 if Count > 0 then
  for i := 0 to Count-1 do
   Items[i].Destruir;

 self.Destroy;
end;


end.

