package fr.eisti.arbre;

import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

/**
 * class Arbre, ABR de valeurs. Valeurs de type int ou Voiture.
 * 
 * @see Valeur
 * 
 * @author Thibault Longret
 * @version 1.0
 *
 */
public class Arbre implements Iterable<Valeur>
{
	/**
	 * valeur du noeud courant
	 */
	private Valeur valeur;
	
	/**
	 * un ABR fils gacuhe. <br/>
	 * Initialisé à null !
	 */
	private Arbre filsGauche;
	
	/**
	 * un ABR fils droit. <br/>
	 * Initialisé à null !
	 */
	private Arbre filsDroit;
	
	/**
	 * liste des valeurs de l'ABR
	 */
	private List<Valeur> listV = new ArrayList<Valeur>();
	
	/**
	 * Constructeur de la class Arbre <br/>
	 * Initialisation à partir d'une valeur donnée en paramètre
	 * @param va_ la valeur que l'on veut mettre à la racine
	 */
	public Arbre(Valeur va_)
	{
		try{valeur = va_;listV.add(va_);filsGauche = null;filsDroit = null;}
		catch(NullPointerException e)
		{
			System.out.print("Erreur de valeur\n");
			e.printStackTrace();
		}
	}
	
	public boolean aFilsDroit()
	{
		return filsGauche != null;
	}
	
	public boolean aFilsGauche()
	{
		return filsGauche != null;
	}
	
	public boolean estFeuille()
	{
		return !aFilsDroit() && !aFilsGauche();
	}
	
	/**
	 * Méthode permettant d'ajouter une valeur dans l'ABR
	 * @param va_ la valeur a ajouter dans l'arbre
	 * @return true si l'ajout à pu se faire correctement
	 * @throws NullPointerException si la valeur à insérer n'est pas correcte<br/>
	 * L'ajout ne se fera donc pas !
	 */
	public boolean ajouter(Valeur va_)
	{
		int s;
		try
		{
			s = va_.compareTo(valeur);
			listV.add(va_);
		}
		catch(NullPointerException e)
		{
			System.out.print("Erreur de valeur\n");
			e.printStackTrace();
			return false;
		}
		if(s == 0)
			return false;
		if(s > 0)
		{
			if(this.aFilsDroit())
				getFilsDroit().ajouter(va_);
			else
				filsDroit = new Arbre(va_);
		}
		else if(s < 0)
		{
			if(this.aFilsGauche())
				getFilsGauche().ajouter(va_);
			else
				filsGauche = new Arbre(va_);
		}
		return true;
	}
	
	public boolean contains(Valeur va_)
	{
		try
		{
			int s = valeur.compareTo(va_);
			if(s == 0)
				return true;
			else if(s < 0)
			{
				if(estFeuille())
					return false;
				else
					getFilsGauche().contains(va_);
			}
			else
			{
				if(estFeuille())
					return false;
				else
					getFilsDroit().contains(va_);
			}
		}
		catch(NullPointerException e)
		{
			System.out.print("Erreur de valeur\n");
			e.printStackTrace();
			return false;
		}
		return false;
	}
	
	public void sauver(String pathName) throws SauvegardeArbreException
	{
		try
		{
			FileOutputStream fos = new FileOutputStream(new File(pathName));
			ObjectOutputStream bos = new ObjectOutputStream(fos);
			bos.writeObject(this);
		}
		catch(Exception e){throw new SauvegardeArbreException(e);}
	}
	
	public boolean ajouter(Arbre arbre)
	{
		return false;
	}
	
	public boolean extraire(Arbre arbre, Valeur seuil)
	{
		return false;
	}
	
	public IterateurOrdonneArbre iterator() 
	{
		return new IterateurOrdonneArbre(this);	
	}

	public Valeur getValeur() {return valeur;}
	public Arbre getFilsGauche() {return filsGauche;}
	public Arbre getFilsDroit() {return filsDroit;}
	public List<Valeur> getListeVal(){return listV;}
}
