-- AUTOR: Elvira Mayordomo Cámara
-- PROYECTO: módulo de implementación del
-- TAD resultado del examen del 21-1-02
-- sólo con árboles
-- FICHERO: familiasimperiales2.adb
-- FECHA: 28-11-03

with Ada.text_io, Ada.Strings.Unbounded, ustrings, unchecked_deallocation;
use Ada.text_io, Ada.Strings.Unbounded, ustrings;
package body familiasimperiales2 is

	procedure disponer is new unchecked_deallocation(nodo,arbol);
	
	procedure buscar(a:in arbol; nombre:in
	ustring; resultado:in out arbol) is
	-- Post: resultado=posición de nombre en a
	-- tiempo O(n), donde n es el número de miembros
	aux:arbol; 
	begin
		aux:=a;
		resultado:=null;
		if aux/=null then
			if aux.nombre=nombre then 
				resultado:=aux;
			else
				if aux.primhijo/=null then
					buscar(aux.primhijo,nombre,resultado);
				elsif aux.primhija/=null then
					buscar(aux.primhija,nombre,resultado);
				end if;	
				if aux.sighermano/=null and
				resultado=null then
					buscar(aux.sighermano,nombre,resultado);
				end if;
			end if;
		end if;			
	end buscar;
	
	procedure buscaremperador(f:in out familia) is
	-- Post: devuelve el emperador en
	-- f.emperador
	-- tiempo O(n), donde n es el número de miembros
	-- paso un máximo de dos veces por cada nodo
	aux:arbol;
	begin
		aux:=f.raiz;
		while aux/=null and f.emperador=null loop
			if aux.vivo then
				f.emperador:=aux;
			elsif aux.primhijo/=null then
				aux:=aux.primhijo;
			elsif aux.primhija/=null then
				aux:=aux.primhija;
			elsif aux.sighermano/=null then
				aux:=aux.sighermano;
			else
				aux:=aux.padre;
				while aux/=null and then (aux.sighermano=null) loop
					aux:=aux.padre;
				end loop;
				if aux/=null then aux:=aux.sighermano; end if;
			end if;			
		end loop;
	end buscaremperador;

	procedure buscarregente(f:in out familia) is
	-- Post: devuelve el regente en
	-- f.regente
	-- tiempo O(n), donde n es el número de miembros
	-- paso un máximo de dos veces por cada nodo
	aux:arbol;
	begin
		aux:=f.raiz;
		while aux/=null and f.regente=null loop
			if aux.vivo and aux.anyo<1985 then
				f.regente:=aux;
			elsif aux.primhijo/=null then
				aux:=aux.primhijo;
			elsif aux.primhija/=null then
				aux:=aux.primhija;
			elsif aux.sighermano/=null then
				aux:=aux.sighermano;
			else
				aux:=aux.padre;
				while aux/=null and then (aux.sighermano=null) loop
					aux:=aux.padre;
				end loop;
				if aux/=null then aux:=aux.sighermano; end if;
			end if;			
		end loop;
	end buscarregente;
	
	procedure crearfamilia(nombre:in ustring; anyo:in positive; varon: boolean; vivo:
	boolean; f:out familia) is
	aux:arbol; 
	-- tiempo O(1) 
	begin 
		aux:=new nodo'(nombre,anyo,varon,vivo,null,null,null,null,null,null);
		f.raiz:=aux;
		if vivo then 
			f.emperador:=aux; 
			if anyo<1985 then
				f.regente:=aux;
			else
				f.regente:=null;
			end if;
		else 
			f.emperador:=null; 
			f.regente:=null;	
		end if;
	end crearfamilia;
	
	function lugar(f:familia; n:ustring) return integer is
	-- tiempo O(n), donde n es el número de miembros
	-- paso un máximo de dos veces por cada nodo
	l:integer; aux:arbol;
	begin
		l:=0;
		aux:=f.emperador;
		while aux/=null and then aux.nombre/=n loop
			if aux.vivo then
				l:=l+1;
			end if;	
			if aux.primhijo/=null then
				aux:=aux.primhijo;
			elsif aux.primhija/=null then
				aux:=aux.primhija;
			elsif aux.sighermano/=null then
				aux:=aux.sighermano;
			else
				aux:=aux.padre;
				while aux/=null and then (aux.sighermano=null) loop
					aux:=aux.padre;
				end loop;
				if aux/=null then aux:=aux.sighermano; end if;
			end if;			
		end loop;
		if aux=null then l:=0; else l:=l+1; end if;
		return(l);				
	end lugar;

	procedure anyadirhijo(aux:in out arbol) is
	-- aux acaba de ser creado y necesita ser
	-- enlazado con sus padres y hermanos.
	-- tiempo O(1)
	padre: arbol;
	begin
		padre:=aux.padre;
		if aux.esvaron then 
			aux.sighermano:=padre.primhija;
			if padre.ulthijo/=null then
				padre.ulthijo.sighermano:=aux;
			else
				padre.primhijo:=aux;
			end if;
			padre.ulthijo:=aux;
		else
			if padre.ulthija/=null then
				padre.ulthija.sighermano:=aux;
			else
				padre.primhija:=aux;
			end if;
			padre.ulthija:=aux;
		end if;
	end anyadirhijo;

	procedure nacer(nombrep,nombrem,nombre:in ustring; anyo:in positive; varon:in boolean; f:in out familia) is
	-- tiempo O(n), donde n es el número de miembros
	padre,madre,aux:arbol;
	lpadre,lmadre:integer;
	begin 
		buscar(f.raiz,nombrep,padre);
		buscar(f.raiz,nombrem,madre);
		if padre/=null and madre/=null then
			lpadre:=lugar(f,nombrep);
			lmadre:=lugar(f,nombrem);
			if lmadre<lpadre then
				padre:=madre;
			end if;
		else
			if padre=null then padre:=madre; end if;
		end if;	
		if padre/=null then 	
			aux:=new nodo'(nombre,anyo,varon,true,padre,null,null,null,null,null);
			anyadirhijo(aux);
		end if;		
	end nacer;
	
	procedure morir(nombre:in ustring; f:in out familia) is
	-- tiempo lineal O(n), donde n es el número de miembros
	aux:arbol;
	begin 
		buscar(f.raiz,nombre,aux);
		if aux/=null then
		
		aux.vivo:=false;
		if f.emperador=aux then
			f.emperador:=null; 
			buscaremperador(f); 
		end if;
		if f.regente=aux then 
			f.regente:=null;
			buscarregente(f); 
		end if;
		
		end if;		
	end morir;

	procedure borrarrec(f:in out familia; pos:in arbol) is
		aux,hijo,siguiente:arbol;
	-- No se preocupa de actualizar padres y hermanos de pos
	-- tiempo O(n), donde n es el número de miembros
	begin	
		-- recursivo:hijos
		if pos.primhijo=null then
			hijo:=pos.primhija;
		else	
			hijo:=pos.primhijo;
		end if;
		aux:=pos;
		disponer(aux);
		while hijo/=null loop
			siguiente:=hijo.sighermano;
			borrarrec(f,hijo);
			hijo:=siguiente;
		end loop;				
	end borrarrec;
	
	procedure desligar(aux:in out arbol) is
	-- aux/=null va a ser borrado y necesitamos
	-- desenlazarlo de su padre y hermanos
	-- tiempo O(1)
	herm:arbol;
	begin
		if aux=aux.padre.primhijo then
			if aux=aux.padre.ulthijo then 
				aux.padre.primhijo:=null;
				aux.padre.ulthijo:=null;
			else	
				aux.padre.primhijo:=aux.sighermano;
			end if;
		elsif aux=aux.padre.primhija then
			if aux.padre.ulthijo/=null then 
				aux.padre.ulthijo.sighermano:=aux.sighermano;
			end if;
			aux.padre.primhija:=aux.sighermano;
			if aux=aux.padre.ulthija then 
				aux.padre.ulthija:=null;
			end if;
		else			
			if aux.esvaron then
				herm:=aux.padre.primhijo;	
			else
				herm:=aux.padre.primhija;
			end if;
			while herm.sighermano/=aux loop
				herm:=herm.sighermano;
			end loop;				
			herm.sighermano:=aux.sighermano;	
			if aux.padre.ulthijo=aux then
				aux.padre.ulthijo:=herm;
			elsif aux.padre.ulthija=aux then
				aux.padre.ulthija:=herm;	
			end if;
		end if;	
	end desligar;	

	procedure borrar(nombre:in ustring; f:in out familia) is
	-- tiempo lineal O(n), donde n es el número de miembros
	aux:arbol;
	begin 
		buscar(f.raiz,nombre,aux);
		if aux/=null then
		
		desligar(aux);
		if f.regente.nombre=nombre then 
			f.regente:=null;
		end if;	
		if f.emperador.nombre=nombre then 
			f.emperador:=null;
		end if;	
		borrarrec(f,aux); -- borra aux y sus descendientes
		if f.regente=null then 
			buscarregente(f); 
		end if;	
		if f.emperador=null then 
			buscaremperador(f); 
		end if;	
		
		end if;	
	end borrar;
		
	procedure linea(f:in familia) is
	-- Post: Escribe por pantalla la línea de sucesión
	-- tiempo lineal O(n), donde n es el número de miembros
	aux:arbol;
	begin 
		aux:=f.emperador;
		while aux/=null loop
			if aux.vivo then
				put_line(aux.nombre);
			end if;	
			if aux.primhijo/=null then
				aux:=aux.primhijo;
			elsif aux.primhija/=null then
				aux:=aux.primhija;
			elsif aux.sighermano/=null then
				aux:=aux.sighermano;
			else
				aux:=aux.padre;
				while aux/=null and then (aux.sighermano=null) loop
					aux:=aux.padre;
				end loop;
				if aux/=null then aux:=aux.sighermano; end if;
			end if;			
		end loop;
	end linea;
	
	function esvacia(f:in familia) return boolean is
	begin 
		return(f.emperador=null);
	end esvacia;
	
	function emperador(f:in familia) return ustring is
	-- Pre: not esvacia(f)
	begin 
		return(f.emperador.nombre);
	end;
	
	function regente(f:in familia) return ustring is
	-- Pre: existe un miembro vivo mayor de edad.
	begin 
		return(f.regente.nombre);
	end;
	
end familiasimperiales2;	


syntax highlighted by Code2HTML, v. 0.9.1