{+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 listas;
interface
uses
	Ancestor, SysUtils;

type


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

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

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

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

		constructor Create;
		procedure Clear;
		procedure Free; override;
		function Ord(p:nodoPtr):word;
		function drO(k:word):nodoPtr;
		function Search( x:TCosa):NodoPtr;
		procedure Show; override;
		procedure Hide; override;
	end;


implementation



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

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

function TLista.Search( x:TCosa):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 Ord:=0
	else
	begin
		t:=Ultimo;
		while (t<>p)and(t<>Nil) do
		begin
			t:=t^.anterior;
			dec(k)
		end;
		if t = p then Ord:=k
		else ord:=0
	end
end;

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



function TLista.Primero:nodoPtr;
var
	t:nodoPtr;
begin
	if ultimo = nil then Primero:=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:TCosa;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):TCosa;
{ Desencadena el item, pero no lo mata 5/92}
var
	tn:nodoPtr;
  pOrig: nodoPtr;
begin
  pOrig:= p;
	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}
	p:=anterior(pOrig);
	quitar:=pOrig^.Item;
	Dispose(pOrig);
	Dec(NNodos);
	if p = nil then p:=Primero;
end;

procedure TLista.Clear;
begin
	while ultimo <> nil do
		quitar(ultimo );
	NNodos:=0;
  ultimo:= nil;
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.
