package GenRGenS.ratexpr;
import java.util.*;
import java.io.*;

/**La classe EtatCompose derive de Etat. Un EtatCompose est un Etat qui sert dans 
 * l'algorithme de déterminisation a connaitre l'equivalence entre un etat dans 
 * l'automate deterministe et l'ensemble des etats qu'il représente dans l'automate 
 * non deterministe*/
class EtatCompose extends Etat {
	
	// _numEtats represente l'ensemble des numeros des etats de l'automate non 
	// deterministe qui sont reunis dans cet EtatCompose.
	private Set _numEtats;
	
	public EtatCompose() {
		this(0,false,false);
	}
	
	public EtatCompose(int num) {
		this(num,false,false);
	}
	
	//Constructeur sans equivalence avec un ensemble d'etats
	public EtatCompose(int num,boolean i,boolean t) {
		super(num,i,t);
		_numEtats = new HashSet();
	}
	
	//Constructeur avec equivalence avec un ensemble d'etats
	public EtatCompose(int num,Set s) throws BadArgumentException {
		
		this(num,false,false,s);
		
		if (s!=null) { 
			//s est un ensemble d'etats. L'etat compose est donc terminal
			//si et seulement si un des etats qu'il représente est terminal.
			boolean terminalEtatCompose = false;
		
			for(Iterator it = s.iterator();it.hasNext() && !terminalEtatCompose;) {
				Etat e = (Etat) (it.next());

				if (e.isTerminal())
					terminalEtatCompose = true;
			}
		
			_terminal = terminalEtatCompose;
		}
	}
	
	/** initNumEtats permet d'initialiser _numEtats a partir d'un ensemble d'etats
	 *  @param s est un ensemble d'etats
	 *  @exception BadArgumentException est levee si un des elements de s n'est pas 
	 *   un etat. */
	private void initNumEtats(Set s) throws BadArgumentException {
		_numEtats = new HashSet();
		
		if (s != null) {
			for(Iterator it = s.iterator();it.hasNext();) {
				Object o = it.next();
				
				if (o instanceof Etat)
					_numEtats.add(((Etat) o).getNum());
				else
					throw (new BadArgumentException("EtatCompose.initNumEtats"));
			}
		}
	}
	
	public EtatCompose(int num,boolean i,boolean t,Set s) throws BadArgumentException {
		super(num,i,t);
		initNumEtats(s);
	}
	
	/** Cette méthode permet de convertir en chaine de caracteres l'etat compose 
	 *  et l'ensemble des etats qu'il represente. */
	public String toStringCompose() {
		return super.toString()+"<->"+_numEtats.toString();
	}	
	
	/** méthode de test d'equivalence des etats representes par deux etats composes.
	 *  @param etat est l'etat compose auquel on compare l'objet courant.
	 *  @return renvoie true si et seulement si les ensembles d'etats representes
	 *  par les deux etats composes sont de meme taille et contiennent les memes elements.*/
	public boolean equivaut(EtatCompose etat) {
		if (etat == null || _numEtats.size() != etat.getNumEtats().size())
			return false;
		
		for(Iterator it = etat.getNumEtats().iterator();it.hasNext();) {
			Integer num = (Integer) it.next();
			
			if (! _numEtats.contains(num))
				return false;
		}
		
		return true;
	}
	
	
	/** méthode de test d'equivalence entre un etat compose et une collection d'etats composes.
	 *  @param s est l'ensemble des etats composes auquels on compare l'objet courant.
	 *  @return renvoie true si et seulement si un des etats composes de s est 
	 *  equivalent a l'objet courant.*/
	public boolean equivaut(Collection s) throws BadArgumentException {
		if (s == null)
			return false;
		
		for(Iterator it = s.iterator();it.hasNext();) {
			Object o = it.next();
			EtatCompose EC = null;
			if (o instanceof EtatCompose)
				EC = (EtatCompose) o;
			else
				throw (new BadArgumentException("EtatCompose.equivaut(Collection)"));
			
			if (equivaut(EC))
				return true;
		}
		
		return false;
	}
	
	/** méthode de recherche dans une collection d'un etat compose equivalent 
	 *  a l'etat courant.
	 *  @param s est l'ensemble des etats composes dans lequel on cherche un etat compose equivalent.
	 *  @return renvoie un etat compose de s s'il est equivalent a l'objet courant.
	 *  null sinon.*/
	public EtatCompose trouveEquivalent(Collection s) throws BadArgumentException {
		if (s == null)
			return null;
		
		for(Iterator it = s.iterator();it.hasNext();) {
			Object o = it.next();
			EtatCompose EC = null;
			if (o instanceof EtatCompose)
				EC = (EtatCompose) o;
			else
				throw (new BadArgumentException("EtatCompose.equivaut(Collection)"));
			
			if (equivaut(EC))
				return EC;
		}
		
		return null;
	}
	
	public Set getNumEtats() { return _numEtats; }
	
	public static void main(String[] argv) {
		int numTest = 0;
		try{
		
		PrintStream f = new PrintStream(new FileOutputStream("EtatCompose.test"));
		
		EtatCompose e,e1,e2;
		boolean ok;
		//Test1
		numTest++;
		f.print("Test 1 : Constructeur sans arguments ... ");
		e = new EtatCompose();
		ok = e.getNum().intValue() == 0 
		  && !e.isInitial() && !e.isTerminal() 
		  && e.getNumEtats().isEmpty();
		if (ok)
			f.println("OK");
		else
			f.println("KO");
		
		//Test2
		numTest++;
		f.print("Test 2 : Constructeur à 1 argument ... ");
		e = new EtatCompose(10);
		ok = e.getNum().intValue() == 10 
		  && !e.isInitial() && !e.isTerminal() 
		  && e.getNumEtats().isEmpty();
		if (ok)
			f.println("OK");
		else
			f.println("KO");
		
		//Test3
		numTest++;
		f.print("Test 3 : Constructeur à 3 arguments ... ");
		e = new EtatCompose(5,true,true);
		ok = e.getNum().intValue() == 5 
		  && e.isInitial() && e.isTerminal() 
		  && e.getNumEtats().isEmpty();
		if (ok)
			f.println("OK");
		else
			f.println("KO");
		
		//Test4
		numTest++;
		f.print("Test 4 : Constructeur à 2 arguments ... ");
		Set s = new HashSet();
		Etat etat = new Etat(10,false,true);
		s.add(etat);
		e = new EtatCompose(3,s);
		ok = e.getNum().intValue() == 3 
		  && !e.isInitial() && (etat.isTerminal() == e.isTerminal())
		  && e.getNumEtats().contains(etat.getNum());
		if (ok)
			f.println("OK");
		else
			f.println("KO");
		s = null;
		etat = null;
		
		//Test5
		numTest++;
		f.print("Test 5 : Constructeur à 4 arguments ... ");
		s = new HashSet();
		etat = new Etat(10,false,true);
		s.add(etat);
		e = new EtatCompose(3,true,false,s);
		ok = e.getNum().intValue() == 3 
		  && e.isInitial() && !e.isTerminal()
		  && e.getNumEtats().contains(etat.getNum());
		if (ok)
			f.println("OK");
		else
			f.println("KO");
		s = null;
		etat = null;
		
		//Test6
		numTest++;
		f.print("Test 6 : Constructeur à 4 arguments (s == null) ... ");
		e = new EtatCompose(3,true,true,null);
		ok = e.getNum().intValue() == 3 
		  && e.isInitial() && e.isTerminal()
		  && e.getNumEtats().isEmpty();
		if (ok)
			f.println("OK");
		else
			f.println("KO");
		
		//Test7
		numTest++;
		f.print("Test 7 : Constructeur à 4 arguments (s n'est pas un ensemble d'Etat) ... ");
		s = new HashSet();
		Integer i = new Integer(1);
		s.add(etat);
		try {
			e = new EtatCompose(3,true,false,s);
		
			f.println("KO : insertion d'un Integer");
		}catch (BadArgumentException exc) { f.println("OK"); }
		s = null;
		i = null;
		
		
		
		}catch (FileNotFoundException e) {System.err.println(e);}
		 catch (BadArgumentException e) {System.err.println("Test "+numTest+" "+e);}
	}
}