SimpleNLG-EnFr-master/src/main/java/simplenlg/framework/NLGFactory.java
/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations
 * under the License.
 *
 * The Original Code is "Simplenlg".
 *
 * The Initial Developer of the Original Code is Ehud Reiter, Albert Gatt and Dave Westwater.
 * Portions created by Ehud Reiter, Albert Gatt and Dave Westwater are Copyright (C) 2010-11 The University of Aberdeen. All Rights Reserved.
 *
 * Contributor(s): Ehud Reiter, Albert Gatt, Dave Wewstwater, Roman Kutlak, Margaret Mitchell, Pierre-Luc Vaudry.
 */
package simplenlg.framework;

import java.util.Arrays;
import java.util.List;

import simplenlg.features.Feature;
import simplenlg.features.Gender;
import simplenlg.features.InternalFeature;
import simplenlg.features.LexicalFeature;
import simplenlg.features.NumberAgreement;
import simplenlg.features.Person;
import simplenlg.lexicon.Lexicon;
import simplenlg.phrasespec.AdjPhraseSpec;
import simplenlg.phrasespec.AdvPhraseSpec;
import simplenlg.phrasespec.NPPhraseSpec;
import simplenlg.phrasespec.PPPhraseSpec;
import simplenlg.phrasespec.SPhraseSpec;
import simplenlg.phrasespec.VPPhraseSpec;

/**
 * <p>
 * This class contains methods for creating syntactic phrases. These methods
 * should be used instead of directly invoking new on SPhraseSpec, etc.
 * 
 * The phrase factory should be linked to s lexicon if possible (although it
 * will work without one)
 * </p>
 * 
 * 
 * @author D. Westwater, University of Aberdeen.
 * @version 4.0
 * 
 */
public class NLGFactory {

	/***
	 * CODING COMMENTS The original version of phraseFactory created a crude
	 * realisation of the phrase in the BASE_FORM feature. This was just for
	 * debugging purposes (note BASE_FORM on a WordElement is meaningful), I've
	 * zapped this as it was makig things too complex
	 * 
	 * This version of phraseFactory replicates WordElements (instead of reusing
	 * them). I think this is because elemente are linked to their parent
	 * phrases, via the parent data member. May be good to check if this is
	 * actually necessary
	 * 
	 * The explicit list of pronouns below should be replaced by a reference to
	 * the lexicon
	 * 
	 * Things to sort out at some point...
	 * 
	 */
	/** The lexicon to be used with this factory. */
	private Lexicon lexicon;

	/** The list of English pronouns. */
	@SuppressWarnings("nls")
	private static final List<String> PRONOUNS = Arrays.asList("I", "you",
			"he", "she", "it", "me", "you", "him", "her", "it", "myself",
			"yourself", "himself", "herself", "itself", "mine", "yours", "his",
			"hers", "its", "we", "you", "they", "they", "they", "us", "you",
			"them", "them", "them", "ourselves", "yourselves", "themselves",
			"themselves", "themselves", "ours", "yours", "theirs", "theirs",
			"theirs", "there");

	/** The list of first-person English pronouns. */
	@SuppressWarnings("nls")
	private static final List<String> FIRST_PRONOUNS = Arrays.asList("I", "me",
			"myself", "we", "us", "ourselves", "mine", "my", "ours", "our");

	/** The list of second person English pronouns. */
	@SuppressWarnings("nls")
	private static final List<String> SECOND_PRONOUNS = Arrays.asList("you",
			"yourself", "yourselves", "yours", "your");

	/** The list of reflexive English pronouns. */
	@SuppressWarnings("nls")
	private static final List<String> REFLEXIVE_PRONOUNS = Arrays.asList(
			"myself", "yourself", "himself", "herself", "itself", "ourselves",
			"yourselves", "themselves");

	/** The list of masculine English pronouns. */
	@SuppressWarnings("nls")
	private static final List<String> MASCULINE_PRONOUNS = Arrays.asList("he",
			"him", "himself", "his");

	/** The list of feminine English pronouns. */
	@SuppressWarnings("nls")
	private static final List<String> FEMININE_PRONOUNS = Arrays.asList("she",
			"her", "herself", "hers");

	/** The list of possessive English pronouns. */
	@SuppressWarnings("nls")
	private static final List<String> POSSESSIVE_PRONOUNS = Arrays.asList(
			"mine", "ours", "yours", "his", "hers", "its", "theirs", "my",
			"our", "your", "her", "their");

	/** The list of plural English pronouns. */
	@SuppressWarnings("nls")
	private static final List<String> PLURAL_PRONOUNS = Arrays
			.asList("we", "us", "ourselves", "ours", "our", "they", "them",
					"theirs", "their");

	/** The list of English pronouns that can be singular or plural. */
	@SuppressWarnings("nls")
	private static final List<String> EITHER_NUMBER_PRONOUNS = Arrays
			.asList("there");

	/** The list of expletive English pronouns. */
	@SuppressWarnings("nls")
	private static final List<String> EXPLETIVE_PRONOUNS = Arrays
			.asList("there");

	/** regex for determining if a string is a single word or not **/
//	private static final String WORD_REGEX = "\\w*";
	// modified by vaudrypl (Unicode letter categories)
	private static final String WORD_REGEX = "(\\p{Lu}|\\p{Ll}|\\p{Lt}|\\p{Lm}|\\p{Lo})*";

	/**
	 * Creates a new phrase factory with default associated lexicon.
	 */
	public NLGFactory() {
		this(null);
	}

	/**
	 * Creates a new phrase factory with the associated lexicon.
	 * Changed by vaudrypl :
	 * Passing null will result in the default lexicon being attributed.
	 * 
	 * @param newLexicon
	 *            the <code>Lexicon</code> to be used with this factory.
	 */
	public NLGFactory(Lexicon newLexicon) {
		setLexicon(newLexicon);
	}

	/**
	 * Sets the lexicon to be used by this factory.
	 * 
	 * Changed by vaudrypl :
	 * Passing a parameter of
	 * <code>null</code> will not remove any existing lexicon from the factory,
	 * but will put the default lexicon instead.
	 * 
	 * @param newLexicon
	 *            the new <code>Lexicon</code> to be used.
	 */
	public void setLexicon(Lexicon newLexicon) {
		if (newLexicon == null) {
			newLexicon = Lexicon.getDefaultLexicon();
		}
		this.lexicon = newLexicon;
	}

	/**
	 * Gets the lexicon used by this factory.
	 * 
	 * @author vaudrypl
	 */
	public Lexicon getLexicon() {
		return this.lexicon;
	}

	/**
	 * Gets the language used by this factory.
	 * 
	 * @author vaudrypl
	 */
	public Language getLanguage() {
		return this.lexicon.getLanguage();
	}

	/**
	 * Creates a new element representing a word. If the word passed is already
	 * an <code>NLGElement</code> then that is returned unchanged. If a
	 * <code>String</code> is passed as the word then the factory will look up
	 * the <code>Lexicon</code> if one exists and use the details found to
	 * create a new <code>WordElement</code>.
	 * 
	 * @param word
	 *            the base word for the new element. This can be a
	 *            <code>NLGElement</code>, which is returned unchanged, or a
	 *            <code>String</code>, which is used to construct a new
	 *            <code>WordElement</code>.
	 * @param category
	 *            the <code>LexicalCategory</code> for the word.
	 * 
	 * @return an <code>NLGElement</code> representing the word.
	 */
	public NLGElement createWord(Object word, LexicalCategory category) {
		NLGElement wordElement = null;
		if (word instanceof NLGElement) {
			wordElement = (NLGElement) word;

		} else if (word instanceof String && this.lexicon != null) {
			// AG: change: should create a WordElement, not an InflectedWordElement
			// wordElement = new InflectedWordElement(
			// (String) word, category);
			// if (this.lexicon != null) {
			// doLexiconLookUp(category, (String) word, wordElement);
			// }
			//wordElement = lexicon.getWord((String) word, category);
			wordElement = lexicon.lookupWord((String) word, category);
			// vaudrypl added condition on language
			if ( getLanguage() == Language.ENGLISH && PRONOUNS.contains(word)) {
				setPronounFeatures(wordElement, (String) word);
			}
		}

		return wordElement;
	}

	/**
	 * A helper method to set the features on newly created pronoun words.
	 * 
	 * @param wordElement
	 *            the created element representing the pronoun.
	 * @param word
	 *            the base word for the pronoun.
	 */
	private void setPronounFeatures(NLGElement wordElement, String word) {
		wordElement.setCategory(LexicalCategory.PRONOUN);
		if (FIRST_PRONOUNS.contains(word)) {
			wordElement.setFeature(Feature.PERSON, Person.FIRST);
		} else if (SECOND_PRONOUNS.contains(word)) {
			wordElement.setFeature(Feature.PERSON, Person.SECOND);

			if ("yourself".equalsIgnoreCase(word)) { //$NON-NLS-1$
				wordElement.setPlural(false);
			} else if ("yourselves".equalsIgnoreCase(word)) { //$NON-NLS-1$
				wordElement.setPlural(true);
			} else {
				wordElement.setFeature(Feature.NUMBER, NumberAgreement.BOTH);
			}
		} else {
			wordElement.setFeature(Feature.PERSON, Person.THIRD);
		}
		if (REFLEXIVE_PRONOUNS.contains(word)) {
			wordElement.setFeature(LexicalFeature.REFLEXIVE, true);
		} else {
			wordElement.setFeature(LexicalFeature.REFLEXIVE, false);
		}
		if (MASCULINE_PRONOUNS.contains(word)) {
			wordElement.setFeature(LexicalFeature.GENDER, Gender.MASCULINE);
		} else if (FEMININE_PRONOUNS.contains(word)) {
			wordElement.setFeature(LexicalFeature.GENDER, Gender.FEMININE);
		} else {
			wordElement.setFeature(LexicalFeature.GENDER, Gender.NEUTER);
		}

		if (POSSESSIVE_PRONOUNS.contains(word)) {
			wordElement.setFeature(Feature.POSSESSIVE, true);
		} else {
			wordElement.setFeature(Feature.POSSESSIVE, false);
		}

		if (PLURAL_PRONOUNS.contains(word) && !SECOND_PRONOUNS.contains(word)) {
			wordElement.setPlural(true);
		} else if (!EITHER_NUMBER_PRONOUNS.contains(word)) {
			wordElement.setPlural(false);
		}

		if (EXPLETIVE_PRONOUNS.contains(word)) {
			wordElement.setFeature(InternalFeature.NON_MORPH, true);
			wordElement.setFeature(LexicalFeature.EXPLETIVE_SUBJECT, true);
		}
	}

	/**
	 * A helper method to look up the lexicon for the given word.
	 * 
	 * @param category
	 *            the <code>LexicalCategory</code> of the word.
	 * @param word
	 *            the base form of the word.
	 * @param wordElement
	 *            the created element representing the word.
	 */
	private void doLexiconLookUp(LexicalCategory category, String word,
			NLGElement wordElement) {
		WordElement baseWord = null;

		if (LexicalCategory.NOUN.equals(category)
				&& this.lexicon.hasWord(word, LexicalCategory.PRONOUN)) {
			baseWord = this.lexicon.lookupWord(word, LexicalCategory.PRONOUN);

			if (baseWord != null) {
				wordElement.setFeature(InternalFeature.BASE_WORD, baseWord);
				wordElement.setCategory(LexicalCategory.PRONOUN);
				if (!PRONOUNS.contains(word)) {
					wordElement.setFeature(InternalFeature.NON_MORPH, true);
				}
			}
		} else {
			baseWord = this.lexicon.lookupWord(word, category);
			wordElement.setFeature(InternalFeature.BASE_WORD, baseWord);
		}
	}

	/**
	 * Creates a blank preposition phrase with no preposition or complements.
	 * 
	 * @return a <code>PPPhraseSpec</code> representing this phrase.
	 */
	public PPPhraseSpec createPrepositionPhrase() {
		return createPrepositionPhrase(null, null);
	}

	/**
	 * Creates a preposition phrase with the given preposition.
	 * 
	 * @param preposition
	 *            the preposition to be used.
	 * @return a <code>PPPhraseSpec</code> representing this phrase.
	 */
	public PPPhraseSpec createPrepositionPhrase(Object preposition) {
		return createPrepositionPhrase(preposition, null);
	}

	/**
	 * Creates a preposition phrase with the given preposition and complement.
	 * An <code>NLGElement</code> representing the preposition is added as the
	 * head feature of this phrase while the complement is added as a normal
	 * phrase complement.
	 * 
	 * @param preposition
	 *            the preposition to be used.
	 * @param complement
	 *            the complement of the phrase.
	 * @return a <code>PPPhraseSpec</code> representing this phrase.
	 */
	public PPPhraseSpec createPrepositionPhrase(Object preposition,
			Object complement) {

		PPPhraseSpec phraseElement = new PPPhraseSpec(this);

//		NLGElement prepositionalElement = createNLGElement(preposition,
//				LexicalCategory.PREPOSITION);
//		setPhraseHead(phraseElement, prepositionalElement);
		phraseElement.setPreposition(preposition);

		if (complement != null) {
			// changed by vaudrypl
//			phraseElement.setObject(complement);
			setComplement(phraseElement, complement);
		}
		return phraseElement;
	}

	/**
	 * A helper method for setting the complement of a phrase.
	 * 
	 * @param phraseElement
	 *            the created element representing this phrase.
	 * @param complement
	 *            the complement to be added.
	 */
	private void setComplement(PhraseElement phraseElement, Object complement) {
		NLGElement complementElement = createNLGElement(complement);
		phraseElement.addComplement(complementElement);
	}

	/**
	 * this method creates an NLGElement from an object If object is null,
	 * return null If the object is already an NLGElement, it is returned
	 * unchanged Exception: if it is an InflectedWordElement, return underlying
	 * WordElement If it is a String which matches a lexicon entry or pronoun,
	 * the relevant WordElement is returned If it is a different String, a
	 * wordElement is created if the string is a single word Otherwise a
	 * StringElement is returned Otherwise throw an exception
	 * 
	 * @param element
	 *            - object to look up
	 * @param category
	 *            - default lexical category of object
	 * @return NLGelement
	 */
	public NLGElement createNLGElement(Object element, LexicalCategory category) {
		if (element == null)
			return null;

		// InflectedWordElement - return underlying word
		else if (element instanceof InflectedWordElement) {
			InflectedWordElement inflElement = (InflectedWordElement) element;
			NLGElement returnedWord = inflElement.getBaseWord();
//			for (String featureName : inflElement.getAllFeatureNames()) {
//				Object featureValue = inflElement.getFeature(featureName);
//				returnedWord.setFeature(featureName, featureValue);
//			}
			return returnedWord;
		}
		
		// StringElement - look up in lexicon if it is a word
		// otherwise return element
		else if (element instanceof StringElement) {
			if (stringIsWord(((StringElement) element).getRealisation(), category))
				return createWord(((StringElement) element).getRealisation(), category);
			else
				return (StringElement) element;
		}

		// other NLGElement - return element
		else if (element instanceof NLGElement)
			return (NLGElement) element;

		// String - look up in lexicon if a word, otherwise return StringElement
		else if (element instanceof String) {
			if (stringIsWord((String) element, category))
				return createWord(element, category);
			else
				return new StringElement((String) element);
		}

		throw new IllegalArgumentException(element.toString()
				+ " is not a valid type");
	}

	/** 
	 * @param string
	 * @param category
	 * @return true if string is a word
	 */
	private boolean stringIsWord(String string, LexicalCategory category) {
		return lexicon != null
				&& (lexicon.hasWord(string, category)
						|| PRONOUNS.contains(string) ||
						(string.matches(WORD_REGEX)));
	}

	/**
	 * create an NLGElement from the element, no default lexical category
	 * 
	 * @param element
	 * @return NLGelement
	 */
	public NLGElement createNLGElement(Object element) {
		return createNLGElement(element, LexicalCategory.ANY);
	}

	/**
	 * Creates a blank noun phrase with no subject or specifier.
	 * 
	 * @return a <code>NPPhraseSpec</code> representing this phrase.
	 */
	public NPPhraseSpec createNounPhrase() {
		return createNounPhrase(null, null);
	}

	/**
	 * Creates a noun phrase with the given subject but no specifier.
	 * 
	 * @param noun
	 *            the subject of the phrase.
	 * @return a <code>NPPhraseSpec</code> representing this phrase.
	 */
	public NPPhraseSpec createNounPhrase(Object noun) {
		// changed by vaudrypl
		return createNounPhrase(null, noun);
	}

	/**
	 * Creates a noun phrase with the given specifier and subject.
	 * 
	 * @param specifier
	 *            the specifier or determiner for the noun phrase.
	 * @param noun
	 *            the subject of the phrase.
	 * @return a <code>NPPhraseSpec</code> representing this phrase.
	 */
	public NPPhraseSpec createNounPhrase(Object specifier, Object noun) {
		if (noun instanceof NPPhraseSpec) {
			// changed by vaudrypl
			return new NPPhraseSpec((NPPhraseSpec)noun);
			//return (NPPhraseSpec) noun;
		}

		NPPhraseSpec phraseElement = new NPPhraseSpec(this);
		
		// Added by vaudrypl to check if the 'noun' is in fact a known pronoun
		// found in the lexicon; relevant only for String or StringElement.
		// It wasn't necessary in the English only version, because pronoun features
		// weren't found in the lexicon, but in setPronounFeatures(...)
		String nounString = null;
		if (noun instanceof String) nounString = (String) noun;
		else if (noun instanceof StringElement) {
			nounString = ((StringElement) noun).getRealisation();
		}
		NLGElement nounElement;
		if ( nounString != null && lexicon.hasWord(nounString, LexicalCategory.PRONOUN) ) {
			nounElement = createNLGElement(noun, LexicalCategory.PRONOUN);
		}
		else nounElement = createNLGElement(noun, LexicalCategory.NOUN);
		
		setPhraseHead(phraseElement, nounElement);

		if (specifier != null)
			phraseElement.setSpecifier(specifier);		
		
		return phraseElement;
	}

	/**
	 * A helper method to set the head feature of the phrase.
	 * 
	 * @param phraseElement
	 *            the phrase element.
	 * @param headElement
	 *            the head element.
	 */
	private void setPhraseHead(PhraseElement phraseElement,
			NLGElement headElement) {
		if (headElement != null) {
			phraseElement.setHead(headElement);
			headElement.setParent(phraseElement);
		}
	}

	/**
	 * Creates a blank adjective phrase with no base adjective set.
	 * 
	 * @return a <code>AdjPhraseSpec</code> representing this phrase.
	 */
	public AdjPhraseSpec createAdjectivePhrase() {
		return createAdjectivePhrase(null);
	}

	/**
	 * Creates an adjective phrase wrapping the given adjective.
	 * 
	 * @param adjective
	 *            the main adjective for this phrase.
	 * @return a <code>AdjPhraseSpec</code> representing this phrase.
	 */
	public AdjPhraseSpec createAdjectivePhrase(Object adjective) {
		AdjPhraseSpec phraseElement = new AdjPhraseSpec(this);

		NLGElement adjectiveElement = createNLGElement(adjective,
				LexicalCategory.ADJECTIVE);
		setPhraseHead(phraseElement, adjectiveElement);

		return phraseElement;
	}

	/**
	 * Creates a blank verb phrase with no main verb.
	 * 
	 * @return a <code>VPPhraseSpec</code> representing this phrase.
	 */
	public VPPhraseSpec createVerbPhrase() {
		return createVerbPhrase(null);
	}

	/**
	 * Creates a verb phrase wrapping the main verb given. If a
	 * <code>String</code> is passed in then some parsing is done to see if the
	 * verb contains a particle, for example <em>fall down</em>. The first word
	 * is taken to be the verb while all other words are assumed to form the
	 * particle.
	 * 
	 * @param verb
	 *            the verb to be wrapped.
	 * @return a <code>VPPhraseSpec</code> representing this phrase.
	 */
	public VPPhraseSpec createVerbPhrase(Object verb) {
		VPPhraseSpec phraseElement = new VPPhraseSpec(this);		
		phraseElement.setVerb(verb);
		setPhraseHead(phraseElement, phraseElement.getVerb());
		return phraseElement;
	}

	/**
	 * Creates a blank adverb phrase that has no adverb.
	 * 
	 * @return a <code>AdvPhraseSpec</code> representing this phrase.
	 */
	public AdvPhraseSpec createAdverbPhrase() {
		return createAdverbPhrase(null);
	}

	/**
	 * Creates an adverb phrase wrapping the given adverb.
	 * 
	 * @param adverb
	 *            the adverb for this phrase.
	 * @return a <code>AdvPhraseSpec</code> representing this phrase.
	 */
	public AdvPhraseSpec createAdverbPhrase(String adverb) {
		AdvPhraseSpec phraseElement = new AdvPhraseSpec(this);

		NLGElement adverbElement = createNLGElement(adverb,
				LexicalCategory.ADVERB);
		setPhraseHead(phraseElement, adverbElement);
		return phraseElement;
	}

	/**
	 * Creates a blank clause with no subject, verb or objects.
	 * 
	 * @return a <code>SPhraseSpec</code> representing this phrase.
	 */
	public SPhraseSpec createClause() {
		return createClause(null, null, null);
	}

	/**
	 * Creates a clause with the given subject and verb but no objects.
	 * 
	 * @param subject
	 *            the subject for the clause as a <code>NLGElement</code> or
	 *            <code>String</code>. This forms a noun phrase.
	 * @param verb
	 *            the verb for the clause as a <code>NLGElement</code> or
	 *            <code>String</code>. This forms a verb phrase.
	 * @return a <code>SPhraseSpec</code> representing this phrase.
	 */
	public SPhraseSpec createClause(Object subject, Object verb) {
		return createClause(subject, verb, null);
	}

	/**
	 * Creates a clause with the given subject, verb and direct object but no
	 * indirect object.
	 * 
	 * @param subject
	 *            the subject for the clause as a <code>NLGElement</code> or
	 *            <code>String</code>. This forms a noun phrase.
	 * @param verb
	 *            the verb for the clause as a <code>NLGElement</code> or
	 *            <code>String</code>. This forms a verb phrase.
	 * @param directObject
	 *            the direct object for the clause as a <code>NLGElement</code>
	 *            or <code>String</code>. This forms a complement for the
	 *            clause.
	 * @return a <code>SPhraseSpec</code> representing this phrase.
	 */
	public SPhraseSpec createClause(Object subject, Object verb,
			Object directObject) {

		SPhraseSpec phraseElement = new SPhraseSpec(this);

		// vaudrypl added conditional call to setVerbPhrase()
		if (verb instanceof VPPhraseSpec) {
			phraseElement.setVerbPhrase((VPPhraseSpec)verb);
		} else if (verb != null) {
			phraseElement.setVerb(verb);
		}

		if (subject != null)
			phraseElement.setSubject(subject);

		if (directObject != null) {
			phraseElement.setObject(directObject);
		}

		return phraseElement;
	}

	/*	*//**
	 * A helper method to set the verb phrase for a clause.
	 * 
	 * @param baseForm
	 *            the base form of the clause.
	 * @param verbPhrase
	 *            the verb phrase to be used in the clause.
	 * @param phraseElement
	 *            the current representation of the clause.
	 */
	/*
	 * private void setVerbPhrase(StringBuffer baseForm, NLGElement verbPhrase,
	 * PhraseElement phraseElement) { if (baseForm.length() > 0) {
	 * baseForm.append(' '); }
	 * baseForm.append(verbPhrase.getFeatureAsString(Feature.BASE_FORM));
	 * phraseElement.setFeature(Feature.VERB_PHRASE, verbPhrase);
	 * verbPhrase.setParent(phraseElement);
	 * verbPhrase.setFeature(Feature.DISCOURSE_FUNCTION,
	 * DiscourseFunction.VERB_PHRASE); if
	 * (phraseElement.hasFeature(Feature.GENDER)) {
	 * verbPhrase.setFeature(Feature.GENDER, phraseElement
	 * .getFeature(Feature.GENDER)); } if
	 * (phraseElement.hasFeature(Feature.NUMBER)) {
	 * verbPhrase.setFeature(Feature.NUMBER, phraseElement
	 * .getFeature(Feature.NUMBER)); } if
	 * (phraseElement.hasFeature(Feature.PERSON)) {
	 * verbPhrase.setFeature(Feature.PERSON, phraseElement
	 * .getFeature(Feature.PERSON)); } }
	 *//**
	 * A helper method to add the direct object to the clause.
	 * 
	 * @param baseForm
	 *            the base form for the clause.
	 * @param directObject
	 *            the direct object to be added.
	 * @param phraseElement
	 *            the current representation of this clause.
	 * @param function
	 *            the discourse function for this object.
	 */
	/*
	 * private void setObject(StringBuffer baseForm, Object object,
	 * PhraseElement phraseElement, DiscourseFunction function) { if
	 * (baseForm.length() > 0) { baseForm.append(' '); } if (object instanceof
	 * NLGElement) { phraseElement.addComplement((NLGElement) object);
	 * baseForm.append(((NLGElement) object)
	 * .getFeatureAsString(Feature.BASE_FORM));
	 * 
	 * ((NLGElement) object).setFeature(Feature.DISCOURSE_FUNCTION, function);
	 * 
	 * if (((NLGElement) object).hasFeature(Feature.NUMBER)) {
	 * phraseElement.setFeature(Feature.NUMBER, ((NLGElement) object)
	 * .getFeature(Feature.NUMBER)); } } else if (object instanceof String) {
	 * NLGElement complementElement = createNounPhrase(object);
	 * phraseElement.addComplement(complementElement);
	 * complementElement.setFeature(Feature.DISCOURSE_FUNCTION, function);
	 * baseForm.append((String) object); } }
	 */
	/*	*//**
	 * A helper method that sets the subjects on a clause.
	 * 
	 * @param phraseElement
	 *            the element representing the clause.
	 * @param subjectPhrase
	 *            the subject phrase for the clause.
	 * @param baseForm
	 *            the base form for the clause.
	 */
	/*
	 * private void setPhraseSubjects(PhraseElement phraseElement, NLGElement
	 * subjectPhrase, StringBuffer baseForm) {
	 * subjectPhrase.setParent(phraseElement); List<NLGElement> allSubjects =
	 * new ArrayList<NLGElement>(); allSubjects.add(subjectPhrase);
	 * phraseElement.setFeature(Feature.SUBJECTS, allSubjects);
	 * baseForm.append(subjectPhrase.getFeatureAsString(Feature.BASE_FORM));
	 * subjectPhrase.setFeature(Feature.DISCOURSE_FUNCTION,
	 * DiscourseFunction.SUBJECT);
	 * 
	 * if (subjectPhrase.hasFeature(Feature.GENDER)) {
	 * phraseElement.setFeature(Feature.GENDER, subjectPhrase
	 * .getFeature(Feature.GENDER)); } if
	 * (subjectPhrase.hasFeature(Feature.NUMBER)) {
	 * phraseElement.setFeature(Feature.NUMBER, subjectPhrase
	 * .getFeature(Feature.NUMBER));
	 * 
	 * } if (subjectPhrase.hasFeature(Feature.PERSON)) {
	 * phraseElement.setFeature(Feature.PERSON, subjectPhrase
	 * .getFeature(Feature.PERSON)); } }
	 */
	/**
	 * Creates a blank canned text phrase with no text.
	 * 
	 * @return a <code>PhraseElement</code> representing this phrase.
	 */
	public NLGElement createStringElement() {
		return createStringElement(null);
	}

	/**
	 * Creates a canned text phrase with the given text.
	 * 
	 * @param text
	 *            the canned text.
	 * @return a <code>PhraseElement</code> representing this phrase.
	 */
	// return type changed from NLGElement by vaudrypl
	public StringElement createStringElement(String text) {
		return new StringElement(text);
	}

	/**
	 * Creates a new (empty) coordinated phrase
	 * 
	 * @return empty <code>CoordinatedPhraseElement</code>
	 */
	public CoordinatedPhraseElement createCoordinatedPhrase() {
		return new CoordinatedPhraseElement(this);
	}

	/**
	 * Creates a new coordinated phrase with two elements (initially)
	 * 
	 * @param coord1
	 *            - first phrase to be coordinated
	 * @param coord2
	 *            = second phrase to be coordinated
	 * @return <code>CoordinatedPhraseElement</code> for the two given elements
	 */
	public CoordinatedPhraseElement createCoordinatedPhrase(Object coord1,
			Object coord2) {
		return new CoordinatedPhraseElement(this, coord1, coord2);
	}

	/***********************************************************************************
	 * Document level stuff
	 ***********************************************************************************/

	/**
	 * Creates a new document element with no title.
	 * 
	 * @return a <code>DocumentElement</code>
	 */
	public DocumentElement createDocument() {
		return createDocument(null);
	}

	/**
	 * Creates a new document element with the given title.
	 * 
	 * @param title
	 *            the title for this element.
	 * @return a <code>DocumentElement</code>.
	 */
	public DocumentElement createDocument(String title) {
		return new DocumentElement(DocumentCategory.DOCUMENT, title, this);
	}

	/**
	 * Creates a new document element with the given title and adds all of the
	 * given components in the list
	 * 
	 * @param title
	 *            the title of this element.
	 * @param components
	 *            a <code>List</code> of <code>NLGElement</code>s that form the
	 *            components of this element.
	 * @return a <code>DocumentElement</code>
	 */
	public DocumentElement createDocument(String title,
			List<DocumentElement> components) {

		DocumentElement document = new DocumentElement(
				DocumentCategory.DOCUMENT, title, this);
		if (components != null) {
			document.addComponents(components);
		}
		return document;
	}

	/**
	 * Creates a new document element with the given title and adds the given
	 * component.
	 * 
	 * @param title
	 *            the title for this element.
	 * @param component
	 *            an <code>NLGElement</code> that becomes the first component of
	 *            this document element.
	 * @return a <code>DocumentElement</code>
	 */
	public DocumentElement createDocument(String title, NLGElement component) {
		DocumentElement element = new DocumentElement(
				DocumentCategory.DOCUMENT, title, this);

		if (component != null) {
			element.addComponent(component);
		}
		return element;
	}

	/**
	 * Creates a new list element with no components.
	 * 
	 * @return a <code>DocumentElement</code> representing the list.
	 */
	public DocumentElement createList() {
		return new DocumentElement(DocumentCategory.LIST, null, this);
	}

	/**
	 * Creates a new list element and adds all of the given components in the
	 * list
	 * 
	 * @param textComponents
	 *            a <code>List</code> of <code>NLGElement</code>s that form the
	 *            components of this element.
	 * @return a <code>DocumentElement</code> representing the list.
	 */
	public DocumentElement createList(List<DocumentElement> textComponents) {
		DocumentElement list = new DocumentElement(DocumentCategory.LIST, null, this);
		list.addComponents(textComponents);
		return list;
	}

	/**
	 * Creates a new section element with the given title and adds the given
	 * component.
	 * 
	 * @param component
	 *            an <code>NLGElement</code> that becomes the first component of
	 *            this document element.
	 * @return a <code>DocumentElement</code> representing the section.
	 */
	public DocumentElement createList(NLGElement component) {
		DocumentElement list = new DocumentElement(DocumentCategory.LIST, null, this);
		list.addComponent(component);
		return list;
	}

	/**
	 * Creates a list item for adding to a list element.
	 * 
	 * @return a <code>DocumentElement</code> representing the list item.
	 */
	public DocumentElement createListItem() {
		return new DocumentElement(DocumentCategory.LIST_ITEM, null, this);
	}

	/**
	 * Creates a list item for adding to a list element. The list item has the
	 * given component.
	 * 
	 * @return a <code>DocumentElement</code> representing the list item.
	 */
	public DocumentElement createListItem(NLGElement component) {
		DocumentElement listItem = new DocumentElement(
				DocumentCategory.LIST_ITEM, null, this);
		listItem.addComponent(component);
		return listItem;
	}

	/**
	 * Creates a new paragraph element with no components.
	 * 
	 * @return a <code>DocumentElement</code> representing this paragraph
	 */
	public DocumentElement createParagraph() {
		return new DocumentElement(DocumentCategory.PARAGRAPH, null, this);
	}

	/**
	 * Creates a new paragraph element and adds all of the given components in
	 * the list
	 * 
	 * @param components
	 *            a <code>List</code> of <code>NLGElement</code>s that form the
	 *            components of this element.
	 * @return a <code>DocumentElement</code> representing this paragraph
	 */
	public DocumentElement createParagraph(List<DocumentElement> components) {
		DocumentElement paragraph = new DocumentElement(
				DocumentCategory.PARAGRAPH, null, this);
		if (components != null) {
			paragraph.addComponents(components);
		}
		return paragraph;
	}

	/**
	 * Creates a new paragraph element and adds the given component
	 * 
	 * @param component
	 *            an <code>NLGElement</code> that becomes the first component of
	 *            this document element.
	 * @return a <code>DocumentElement</code> representing this paragraph
	 */
	public DocumentElement createParagraph(NLGElement component) {
		DocumentElement paragraph = new DocumentElement(
				DocumentCategory.PARAGRAPH, null, this);
		if (component != null) {
			paragraph.addComponent(component);
		}
		return paragraph;
	}

	/**
	 * Creates a new section element.
	 * 
	 * @return a <code>DocumentElement</code> representing the section.
	 */
	public DocumentElement createSection() {
		return new DocumentElement(DocumentCategory.SECTION, null, this);
	}

	/**
	 * Creates a new section element with the given title.
	 * 
	 * @param title
	 *            the title of the section.
	 * @return a <code>DocumentElement</code> representing the section.
	 */
	public DocumentElement createSection(String title) {
		return new DocumentElement(DocumentCategory.SECTION, title, this);
	}

	/**
	 * Creates a new section element with the given title and adds all of the
	 * given components in the list
	 * 
	 * @param title
	 *            the title of this element.
	 * @param components
	 *            a <code>List</code> of <code>NLGElement</code>s that form the
	 *            components of this element.
	 * @return a <code>DocumentElement</code> representing the section.
	 */
	public DocumentElement createSection(String title,
			List<DocumentElement> components) {

		DocumentElement section = new DocumentElement(DocumentCategory.SECTION,
				title, this);
		if (components != null) {
			section.addComponents(components);
		}
		return section;
	}

	/**
	 * Creates a new section element with the given title and adds the given
	 * component.
	 * 
	 * @param title
	 *            the title for this element.
	 * @param component
	 *            an <code>NLGElement</code> that becomes the first component of
	 *            this document element.
	 * @return a <code>DocumentElement</code> representing the section.
	 */
	public DocumentElement createSection(String title, NLGElement component) {
		DocumentElement section = new DocumentElement(DocumentCategory.SECTION,
				title, this);
		if (component != null) {
			section.addComponent(component);
		}
		return section;
	}

	/**
	 * Creates a new sentence element with no components.
	 * 
	 * @return a <code>DocumentElement</code> representing this sentence
	 */
	public DocumentElement createSentence() {
		return new DocumentElement(DocumentCategory.SENTENCE, null, this);
	}

	/**
	 * Creates a new sentence element and adds all of the given components.
	 * 
	 * @param components
	 *            a <code>List</code> of <code>NLGElement</code>s that form the
	 *            components of this element.
	 * @return a <code>DocumentElement</code> representing this sentence
	 */
	public DocumentElement createSentence(List<NLGElement> components) {
		DocumentElement sentence = new DocumentElement(
				DocumentCategory.SENTENCE, null, this);
		sentence.addComponents(components);
		return sentence;
	}

	/**
	 * Creates a new sentence element
	 * 
	 * @param components
	 *            an <code>NLGElement</code> that becomes the first component of
	 *            this document element.
	 * @return a <code>DocumentElement</code> representing this sentence
	 */
	public DocumentElement createSentence(NLGElement components) {
		DocumentElement sentence = new DocumentElement(
				DocumentCategory.SENTENCE, null, this);
		sentence.addComponent(components);
		return sentence;
	}

	/**
	 * Creates a sentence with the given subject and verb. The phrase factory is
	 * used to construct a clause that then forms the components of the
	 * sentence.
	 * 
	 * @param subject
	 *            the subject of the sentence.
	 * @param verb
	 *            the verb of the sentence.
	 * @return a <code>DocumentElement</code> representing this sentence
	 */
	public DocumentElement createSentence(Object subject, Object verb) {
		return createSentence(subject, verb, null);
	}

	/**
	 * Creates a sentence with the given subject, verb and direct object. The
	 * phrase factory is used to construct a clause that then forms the
	 * components of the sentence.
	 * 
	 * @param subject
	 *            the subject of the sentence.
	 * @param verb
	 *            the verb of the sentence.
	 * @param complement
	 *            the object of the sentence.
	 * @return a <code>DocumentElement</code> representing this sentence
	 */
	public DocumentElement createSentence(Object subject, Object verb,
			Object complement) {

		DocumentElement sentence = new DocumentElement(
				DocumentCategory.SENTENCE, null, this);
		sentence.addComponent(createClause(subject, verb, complement));
		return sentence;
	}

	/**
	 * Creates a new sentence with the given canned text. The canned text is
	 * used to form a canned phrase (from the phrase factory) which is then
	 * added as the component to sentence element.
	 * 
	 * @param cannedSentence
	 *            the canned text as a <code>String</code>.
	 * @return a <code>DocumentElement</code> representing this sentence
	 */
	public DocumentElement createSentence(String cannedSentence) {
		DocumentElement sentence = new DocumentElement(
				DocumentCategory.SENTENCE, null, this);

		if (cannedSentence != null) {
			sentence.addComponent(createStringElement(cannedSentence));
		}
		return sentence;
	}
}
