/*******************************************************************************
 * GenRGenS v.1.0, Generation of Random Genomic Sequences                      *
 * Copyright (C) 2001  Alain Denise/Yann Ponty                                 *
 *                                                                             *
 * This program is free software; you can redistribute it and/or               *
 * modify it under the terms of the GNU General Public License                 *
 * as published by the Free Software Foundation; either version 2              *
 * of the License, or (at your option) any later version.                      *
 *                                                                             *
 * This program is distributed in the hope that it will be useful,             *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of              *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               *
 * GNU General Public License for more details.                                *
 *                                                                             *
 * You should have received a copy of the GNU General Public License           *
 * along with this program; if not, write to the Free Software                 *
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA. *
 *******************************************************************************/

package GenRGenS.grammar;

/*****************************************************************************
*              NormalContextFreeGrammarProductionUnion         
*
******************************************************************************/

import java.util.*;;

/** 
 * A class for the context-free grammar productions that are unions
 * @author Fr&eacute;d&eacute;ric Sarron
 * @version 1.0
 */

public class NormalContextFreeGrammarProductionUnion
		extends NormalContextFreeGrammarProduction
{

		protected int[] alternative;

		/**
		 * Construit une instance de <code>NormalContextFreeGrammarProductionUnion</code>, classe
		 * modelisant les règles des la grammaire de type Union (N -> N1|N2|...).
		 * @param source L'index du non-terminal partie gauche de la règle.
		 * @param choix Un tableau contenant l'ensemble des index des parties droites 
		 * possibles pour la règle.
		 */
		NormalContextFreeGrammarProductionUnion(int source,int[] choix)
		{	
				super(source);
				setRHS(choix);
		};
		
		/**
		 * Vérifie qu'un ensemble de symboles candidat à être la partie droite de la règle est
		 * bien uniquement composé de non-terminaux, comme le spécifie la forme normale utilisée.
		 * @param t Un tableau d'index de symboles
		 * @return false si il existe un terminal parmis les index proposés, true sinon.
		 */
		private boolean valeursOK(int[] t)
		{
				boolean isOK=true;
				for (int i=0;i<t.length;i++)
						if (t[i]<0)
								{ isOK = false; break; };
				return (isOK);
		};

		
		/**
		 * Renvoie la partie droite de la règle.
		 * @return Un tableau contenant les index des non-terminaux partie droite de la règle.
		 */
		public int[] getRHS()
		{
				return(alternative);
		};

		/**
		 * Affecte à la règle un nouvel ensemble de non-terminaux en partie droite
		 * @param rhs Un tableau contenant les index des nouveaux non-terminaux partie droite de la règle.
		 * @throws IllegalArgumentException Quand l'index d'un terminal est trouvé dans le tableau.
		 */
		public void setRHS(int[] rhs)
		{
				if (valeursOK(rhs))
						alternative=rhs;
				else
						throw(new IllegalArgumentException("NormalContextFreeGrammarProductionUnion(int[]) all integers in array must be positive integers"));
		};

		/**
		 * Cette methode a pour but de rereferencer les nonTerminaux
		 * dans les LHS et RHS, suite a suppression de certains
		 * auxiliaires dans des algorithmes au niveau grammaire.
		 * @param assignement Ce tableau d'entier fait correspondre
		 * a chaque auxiliaire un nouvel index auquel il faut le substituer 
		 */
		void modifyReferences(int[] assignement)
		{
				int assign;
				if ((assign=assignement[lhs])>=0)
						lhs = assignement[lhs];
				for (int i=0;i<alternative.length;i++)
						if ((assign=assignement[alternative[i]])>=0)
								alternative[i]=assign;
		};
		
		
		/** 
		 * Retourne true ssi chaque NT de la RHS est
		 * - element de "countables" (les  NT qui sont denombrables
		 *       au moment de l'appel)
		 * - ou bien une production terminale (element de "termProds")			 
		 */
		boolean isNowCountable(Vector countables, Vector termProds)
		{
				Integer testing;
				for (int indexRHS=0;indexRHS<alternative.length;indexRHS++)
						if ( ! 
								 (countables.contains(testing = 
																			new Integer(alternative[indexRHS]))
									||
									(termProds.contains(testing))))
								return(false);
				return(true);
		};

		
		/**
		 * Cette règle ne dérive-t-elle que le mot epsilon ?
		 * @return true sir la règle ne dérive qu'epsilon, false sinon.
		 */
		public boolean isEpsilonProduction()
		{
				return(false);
		};
		
		/** 
		 * Teste si, dans une grammaire, il existe un auxiliaire droit qui dérive epsilon.
		 * @return true ssi un auxiliaire de la RHS derive epsilon, false sinon.
		 */
		public boolean canProduceEpsilon(NormalContextFreeGrammarProduction[] p)
		{
				for (int indexRHS=0;indexRHS<alternative.length;indexRHS++)
						if (p[alternative[indexRHS]].isEpsilonProduction())
								return(true);
				return(false);
		};

		/**
		 * Renvoie une représentation littérale de cette instance de classe en mode "debug".
		 */
		String toStringDebug()
		{
				String temp =  
						lhs+" -> "+alternative[0];
				for (int i=1;i<alternative.length;i++)
						temp += " | "+alternative[i];
				return(temp);
		}

		/**
		 * Renvoie une représentation littérale de cette instance de classe en mode "debug".
		 * @param ncfg La grammaire dans laquelle seront cherchées les représentations littérales 
		 * des symboles.
		 * @return Renvoie une instance de <code>String</code> décrivant cette règle.
		 */
		public String toString(NormalContextFreeGrammar ncfg)
		{
				String temp =  
						ncfg.CFGsymbolName(lhs)+" -> "+
						ncfg.CFGsymbolName(alternative[0]);
				for (int i=1;i<alternative.length;i++)
						temp += " | "+ncfg.CFGsymbolName(alternative[i]);
				return(temp);
		};

}
