unit uListaTagObjeto;

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

interface

uses
  Classes, SysUtils;

const
  strTag = 'tag';  

type
  TTagObjeto = class
    public
      tag: String;
      objeto: TObject;

      Constructor Create(tag: String; objeto: TObject);
  end;

  TListaTagObjeto = class(TList)
    private
      lastITag: Integer;

      function getIObjeto(objeto: TObject): Integer;
    public
      Constructor Create;
      //Asigna un tag al objeto, agrega a la lista el par <tag, objeto> y retorna
      //el tag
      function addTagObjeto(objeto: TObject): String;
      //busca el objeto especificado, lo elimina y devuelve su tag
      function eliminarTagObjeto(objeto: TObject): String;
      function getObjeto(tag: String): TObject;

      //Asigna el tag de objeto1 a objeto2 y viceversa
      procedure swapObjetos(objeto1, objeto2: TObject);

      procedure FreeConElementos;
  end;


implementation

Constructor TTagObjeto.Create(tag: String; objeto: TObject);
begin
  inherited Create;
  self.tag:= tag;
  Self.objeto:= objeto;
end;

Constructor TListaTagObjeto.Create;
begin
  inherited Create;
  lastITag:= 0;
end;

//Asigna un tag al objeto, agrega a la lista el par <tag, objeto> y retorna
//el tag
function TListaTagObjeto.addTagObjeto(objeto: TObject): String;
var
  tag: String;
begin
  tag:= strTag + IntToStr(lastITag);
  lastITag:= lastITag + 1;
  inherited Add(TTagObjeto.Create(tag, objeto));
  result:= tag;
end;

function TListaTagObjeto.eliminarTagObjeto(objeto: TObject): String;
var
  iObjeto: Integer;
  res: String;
begin
  iObjeto:= getIObjeto(objeto);

  if iObjeto <> -1 then
  begin
    res:= TTagObjeto(Items[iObjeto]).tag;
    TTagObjeto(Items[iObjeto]).Free;
    inherited Delete(iObjeto);
  end
  else
    res:= '';
  result:= res;
end;

function TListaTagObjeto.getObjeto(tag: String): TObject;
var
  i: Integer;
  res: TObject;
begin
  res:= NIL;
  for i:= 0 to Count - 1 do
    if TTagObjeto(Items[i]).tag = tag then
    begin
      res:= TTagObjeto(Items[i]).objeto;
      break;
    end;
  result:= res;
end;

//Asigna el tag de objeto1 a objeto2 y viceversa
procedure TListaTagObjeto.swapObjetos(objeto1, objeto2: TObject);
var
  iObjeto1, iObjeto2: Integer;
begin
  iObjeto1:= getIObjeto(objeto1);
  iObjeto2:= getIObjeto(objeto2);

  //Pueden ser -1 si es un objeto que fue agregado despues de la lectura
  //en ese caso el objeto no tendrá un tag, por lo que no se hace ningún cambio
  if iObjeto1 <> -1 then
    TTagObjeto(Items[iObjeto1]).objeto:= objeto2;
  if iObjeto2 <> -1 then
    TTagObjeto(Items[iObjeto2]).objeto:= objeto1;
end;

procedure TListaTagObjeto.FreeConElementos;
var
  i: Integer;
begin
  for i:= 0 to Count - 1 do
    TTagObjeto(Items[i]).Free;
  inherited Free;
end;

function TListaTagObjeto.getIObjeto(objeto: TObject): Integer;
var
  i, res: Integer;
begin
  res:= -1;
  for i:= 0 to Count - 1 do
    if TTagObjeto(Items[i]).objeto = objeto then
    begin
      res:= i;
      break;
    end;
  result:= res;
end;

end.
