{+doc
+NOMBRE:listas
+CREACION:1.1.90
+AUTORES:rch
+REGISTRO:
+TIPO: Unidad Pascal.
+PROPOSITO:Implementacion del objeto lista y sus servicios
+PROYECTO:rchlib

+REVISION:
+AUTOR:
+DESCRIPCION:
-doc}


unit ulistas;
interface
uses
	Ancestor, SysUtils;

type


	nodoPtr = ^nodo;
	nodo = record
		anterior:nodoPtr;
		item:TBase;
	end;

	TLista = class( TBase )
		NNodos:word;
		ultimo:nodoPtr;
		procedure insertar( x:TBase; var p:nodoPtr);
		procedure append( x:Tbase);

		{ Desencadena el item, pero no lo mata 5/92}
		function quitar(var p:nodoPtr):TBase;

		procedure borrar(var xp:nodoPtr);
		function anterior(p:nodoPtr):nodoPtr;
		function siguiente(p:nodoPtr):nodoPtr;
		function primero:nodoPtr;

		constructor Create;
		procedure Clear;
		procedure Free; virtual;
		function Ord_(p:nodoPtr):word;
		function drO(k:word):nodoPtr;
		function Search( x:TBase):NodoPtr;
		procedure Show; virtual;
		procedure Hide; virtual;
	end;


implementation



constructor TLista.Create;
begin
	inherited Create;
	Clear;
end;

procedure TLista.append( x:TBase);
begin
	insertar(x,ultimo);
end;

function TLista.Search( x:TBase):NodoPtr;
var
	t:NodoPtr;
	buscando: boolean;
begin
	t:=ultimo;
	buscando:= true;

	while buscando and (t <> nil) do
	begin
		if (t^.Item = x) then
			buscando:= false
		else
			t:=anterior(t);
	end;
	if buscando then
		result:= nil
	else
		result:=t;
end;

function TLista.Ord_(p:nodoPtr):word;
var
	t:nodoPtr;
	k:word;
begin
	k:=NNodos;
	if Ultimo = nil then
    result:= 0
	else
	begin
		t:=Ultimo;
		while (t<>p)and(t<>Nil) do
		begin
			t:=t^.anterior;
			dec(k)
		end;
		if t = p then
      result:=k
		else
      result:=0
	end
end;

function TLista.Dro(k:word):nodoPtr;
var
	t:nodoPtr;
	j:word;
begin
	if k>NNodos then
    result:=nil
	else
		begin
			j:=NNodos;
			t:=ultimo;
			while k<> j do
				begin
					dec(j);
					t:=anterior(t)
				end;
			result:=t
		end;
end;



function TLista.Primero:nodoPtr;
var
	t:nodoPtr;
begin
	if ultimo = nil then
    result:=nil {TListaVacia}
	else
	begin
		t:=ultimo;
		while t^.anterior<>nil do t:=t^.anterior;
		Primero:=t
	end
end;

function TLista.siguiente(p:nodoPtr):nodoPtr;
var
	t:nodoPtr;
begin
	if (p = nil)or(ultimo=nil) then
		raise Exception.Create('TLista.siguiente, p fuera de rango ');
	if p = ultimo then siguiente:=Nil
	else
	begin
		t:=ultimo;
		while  t^.anterior <> p do t:=t^.anterior;
		siguiente:=t
	end
end;



function TLista.anterior(p:nodoPtr):nodoPtr;
begin
	anterior :=  p^.anterior
end;


procedure TLista.insertar(x:TBase;var p:nodoPtr);
var
	tp:NodoPtr;
begin
	new(tp);
	tp^.item:=x;
	tp^.anterior:=p;
	inc(NNodos);
	if p = nil then    {Lo agrega al principio de la TLista}
		if ultimo = nil then ultimo:=tp {TLista Vacia}
		else primero^.anterior:=tp
	else
	begin
		if p = ultimo then ultimo:=tp
		else siguiente(p)^.anterior:=tp;
	end;
	p:=tp;
end;


{Ordena la destrucci¢n del objeto correspondiente de la TLista
destruyendo tambi‚n el nodo apuntodo por.}

procedure TLista.borrar(var xp:nodoPtr);
var
	tn,p:nodoPtr;
begin
	p:=xp;

	if (p= nil)or(ultimo=nil) then RunError(201);
	tn:=siguiente(p);
	if tn<> nil then
		tn^.anterior:=anterior(p)
	else
		ultimo:=anterior(p); {borrando el primer elemento}
	xp:=anterior(p);
	p^.Item.Free;
	Dispose(p);
	Dec(NNodos);
	if xp = nil then
		xp:=Primero;
end;



function TLista.quitar(var p:nodoPtr):TBase;
{ Desencadena el item, pero no lo mata 5/92}
var
	tn:nodoPtr;
begin
	if (p= nil)or(ultimo=nil) then RunError(211);
	tn:=siguiente(p);
	if tn<> nil then tn^.anterior:=anterior(p)
	else ultimo:=anterior(p); {borrando el primer elemento}
	tn:=p;
	p:=anterior(p);
	quitar:=tn^.Item;
	Dispose(tn);
	Dec(NNodos);
	if p = nil then p:=Primero;
end;

procedure TLista.Clear;
begin
	while ultimo <> nil do
		quitar(ultimo );
	NNodos:=0;
end;

procedure TLista.Free;
begin
	while ultimo<>nil do
		Borrar(ultimo);
	inherited Free;
end;

procedure TLista.Show;
var
	t:nodoPtr;
begin
	t:=ultimo;
	while t<> nil do
		begin
			t^.item.Show;
			t:=anterior(t)
		end
end;

procedure TLista.Hide;
var
	t:nodoPtr;
begin
	t:=ultimo;
	while t<> nil do
		begin
			t^.item.Hide;
			t:=anterior(t)
		end
end;

end.
