unit uMonitores;

{$IFDEF FPC}
  {$MODE Delphi}
{$ENDIF}

interface

uses
  xMatDefs, Classes, uCosa, ufichasLPD, uVarDefs,
  SysUtils, Math, uConstantesSimSEE, uSalasDeJuego, uEventosOptSim;

type
  TEventoProc = record
    evento: TEventoOptSim;
    refProc: integer;
  end;

  TDAOfEventoProc = array of TEventoProc;

  TClasesDeMonitores = class of TMonitores;

  TProc = procedure of object;

  TMonitores = class;

  TProcWrapper = class
  public
    monitor: TMonitores;
    proc: TProc;
    constructor Create(monitor: TMonitores; xproc: TProc);
    //el procedimiento equals ya existe y tiene otra delcaración de función
    function esIgualA(otroProc: TProcWrapper): boolean;
  end;

  TMonitores = class
  protected
  public
    function resolverRefProc(refProc: integer): TProcWrapper; virtual; abstract;
    class function darRefProc(nombreProc: string; evento: TEventoOptSim): integer;
      virtual; abstract;
    procedure Free; virtual;
  end;

function sortTDAOfEventoProcByProc(original: TDAOfEventoProc): TDAOfEventoProc;
procedure FreeAndNil(var mon: TMonitores);

implementation

//------------------------
// Métodos de TProcWrapper
//========================

constructor TProcWrapper.Create(monitor: TMonitores; xproc: TProc);
begin
  Self.monitor := monitor;
  proc := xproc;
end;

function TProcWrapper.esIgualA(otroProc: TProcWrapper): boolean;
var
  procaux: TProc;
  //      http://info.borland.com/techpubs/delphi/delphi5/oplg/datatype.html
  //      Por comparación de tipos procedurales buscar
  //      "To compare the procedural value of"
begin
  procaux := otroProc.proc;
  Result := (monitor = (otroProc.monitor)) and (@proc = @procaux);
end;

//----------------------
// Métodos de TMonitores
//======================

procedure TMonitores.Free;
begin
  inherited Free;
end;

function sortTDAOfEventoProcByProc(original: TDAOfEventoProc): TDAOfEventoProc;
var
  res: TDAOfEventoProc;
  iterOrig, iterOrig_, iterRes, minRefProc, posMinRefProc, aux: integer;
  insertado: array of boolean;
begin
  SetLength(res, length(original));
  SetLength(insertado, length(original));
  for iterRes := 0 to High(insertado) do
    insertado[iterRes] := False;

  for iterRes := 0 to high(original) do
  begin
    //Busco el primer no insertado y asumo que es el minimo que queda sin insertar
    iterOrig := -1;
    for aux := 0 to high(insertado) do
      if not insertado[aux] then
      begin
        iterOrig := aux;
        break;
      end;
    if iterOrig = -1 then
      raise Exception.Create(
        'uMonitores- SortTDAOfEventoByProc - no encontró uno insertado.');
    minRefProc := original[iterOrig].refProc;
    posMinRefProc := iterOrig;

    //Reviso contra el resto

    for iterOrig_ := iterOrig + 1 to high(original) do
    begin
      if not insertado[iterOrig_] and (original[iterOrig_].refProc < minRefProc) then
      begin
        minRefProc := original[iterOrig_].refProc;
        posMinRefProc := iterOrig_;
      end;
    end;
    res[iterRes] := original[posMinRefProc];
    insertado[posMinRefProc] := True;
  end;

  Result := res;
end;

procedure FreeAndNil(var mon: TMonitores);
var
  aux: TMonitores;
begin
  aux := mon;
  mon := nil;
  aux.Free;
end;

end.

