package simplenlg.test.german;

import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.List;

import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;

import simplenlg.features.AdjectiveDegree;
import simplenlg.features.Case;
import simplenlg.features.DiscourseFunction;
import simplenlg.features.Form;
import simplenlg.features.Gender;
import simplenlg.features.InterrogativeType;
import simplenlg.features.NumberAgr;
import simplenlg.features.Person;
import simplenlg.features.Position;
import simplenlg.features.Tense;
import simplenlg.framework.NLGFactory;
import simplenlg.lexicon.DBLexicon;
import simplenlg.lexicon.db.XMLAccessor;
import simplenlg.lexicon.lexicalitems.Adjective;
import simplenlg.lexicon.lexicalitems.Constants;
import simplenlg.lexicon.lexicalitems.Noun;
import simplenlg.lexicon.lexicalitems.Preposition;
import simplenlg.lexicon.lexicalitems.Pronoun;
import simplenlg.lexicon.lexicalitems.Verb;
import simplenlg.realiser.AdjPhraseSpec;
import simplenlg.realiser.CoordinateNPPhraseSpec;
import simplenlg.realiser.CoordinateSPhraseSpec;
import simplenlg.realiser.NPPhraseSpec;
import simplenlg.realiser.PPPhraseSpec;
import simplenlg.realiser.Realiser;
import simplenlg.realiser.SPhraseSpec;
import simplenlg.realiser.comparators.WordOrder;

public class RandomTests {

	static String lexiconFile = "res/toy-lexicon.xml";
	
	DBLexicon lex;
	Realiser r;
	NLGFactory factory;
	
	Tense[] allTenses;
	Form[] allForms;
	NumberAgr[] allNums;
	Person[] allPersons;
	Case[] allCases;
	
	Verb sehen, geben;
	Pronoun beide;
	AdjPhraseSpec schoen, teuer;
	NPPhraseSpec mann, frau, kind, name, buch, beamte;
	PPPhraseSpec ubahn;
	SPhraseSpec sentence, matrix, sub1;

	@Before
	public void setUp() throws Exception {
		lex = new DBLexicon(new XMLAccessor(lexiconFile));
		lex.loadData();
		r = new Realiser(lex);
		factory = new NLGFactory(lex);
		
		allTenses  = new Tense[] { Tense.PRESENT, Tense.PAST };
		allForms   = new Form[] { Form.NORMAL, Form.SUBJUNCTIVE };
		allNums    = new NumberAgr[] { NumberAgr.SINGULAR, NumberAgr.PLURAL };
		allPersons = new Person[] { Person.FIRST, Person.SECOND, Person.THIRD };
		allCases   = new Case[] { Case.NOMINATIVE, Case.ACCUSATIVE, Case.GENITIVE, Case.DATIVE };

		resetAll();
	}
	
	void resetAll() {
		mann = factory.createNounPhrase("der", "Mann");
		frau = factory.createNounPhrase("die", "Frau");
		kind = factory.createNounPhrase("das", "Kind");
		name = factory.createNounPhrase("der", "Name");
		buch = factory.createNounPhrase("ein", "Buch");
		ubahn = factory.createPrepositionalPhrase("in", "der", "U-|Bahn", Case.DATIVE);
		beamte = factory.createNounPhrase("der", "Beamte");
		beamte.setGender(Gender.MASCULINE);
		
		beide = Constants.getPronoun("beide");
		
		sehen = lex.getVerb("sehen");
		geben = lex.getVerb("geben");
		
		schoen = factory.createAdjectivePhrase("schön");
		teuer  = factory.createAdjectivePhrase("teuer");
		
		resetSentence();
		resetMatrix();
		resetSubordinate();
	}
	void resetSentence() {
		sentence = new SPhraseSpec(frau, geben, buch);
		sentence.addIndirectObject(mann);
		sentence.setTense(Tense.PAST);
	}
	void resetMatrix() {
		matrix = new SPhraseSpec(frau, sehen);
	}
	void resetSubordinate() {
		sub1 = factory.createSentence(mann, "sein");
		sub1.addModifier(schoen);
	}
	
	@Test
	public void testFactory() {
		NPPhraseSpec[] namen;
		namen = new NPPhraseSpec[] {
				factory.createNounPhrase("der", "Name"),
				factory.createNounPhrase("der Name"),
				// incorrect determiners will be accepted,
				// as the gender is looked up in the lexicon anyway
				factory.createNounPhrase("das Name")

		};

		for (NPPhraseSpec nm : namen) {
			/* IRREGULAR NOUN: der Name */
			nm.setNumber(NumberAgr.SINGULAR);
			nm.setCase(Case.NOMINATIVE);
			assertEquals("der Name", r.realise(nm));
			nm.setCase(Case.ACCUSATIVE);
			assertEquals("den Namen", r.realise(nm));
			nm.setCase(Case.GENITIVE);
			assertEquals("des Namens", r.realise(nm));
			nm.setCase(Case.DATIVE);
			assertEquals("dem Namen", r.realise(nm));
			nm.setNumber(NumberAgr.PLURAL);
			nm.setCase(Case.NOMINATIVE);
			assertEquals("die Namen", r.realise(nm));
			nm.setCase(Case.ACCUSATIVE);
			assertEquals("die Namen", r.realise(nm));
			nm.setCase(Case.GENITIVE);
			assertEquals("der Namen", r.realise(nm));
			nm.setCase(Case.DATIVE);
			assertEquals("den Namen", r.realise(nm));
		}
		
		// testing behavior if word is not in lexicon
		NPPhraseSpec unk = factory.createNounPhrase("die", "Unbekannte");
		// gender will be neuter by default if word is not in lexicon
		assertEquals("das Unbekannte", r.realise(unk));
		unk.setGender(Gender.FEMININE);
		assertEquals("die Unbekannte", r.realise(unk));
		
		NPPhraseSpec pro = factory.createPersonalPronounPhrase(Person.THIRD, NumberAgr.SINGULAR, Gender.FEMININE);
		pro.setCase(Case.NOMINATIVE);
		assertEquals("sie", r.realise(pro));
		pro.setCase(Case.ACCUSATIVE);
		assertEquals("sie", r.realise(pro));
		pro.setCase(Case.DATIVE);
		assertEquals("ihr", r.realise(pro));
		pro.setCase(Case.GENITIVE);
		assertEquals("ihrer", r.realise(pro));
	}
	
	// LEXICAL ITEMS: INFLECTION //
	
	@Test
	public void testNounDeclension() {
		/* MASCULINE NOUN: der Mann */
		mann.setNumber(NumberAgr.SINGULAR);
		mann.setCase(Case.NOMINATIVE);
		assertEquals("der Mann", r.realise(mann));
		mann.setCase(Case.ACCUSATIVE);
		assertEquals("den Mann", r.realise(mann));
		mann.setCase(Case.GENITIVE);
		assertEquals("des Mannes", r.realise(mann));
		mann.setCase(Case.DATIVE);
		assertEquals("dem Mann", r.realise(mann));		
		mann.setNumber(NumberAgr.PLURAL);
		mann.setCase(Case.NOMINATIVE);
		assertEquals("die Männer", r.realise(mann));
		mann.setCase(Case.ACCUSATIVE);
		assertEquals("die Männer", r.realise(mann));
		mann.setCase(Case.GENITIVE);
		assertEquals("der Männer", r.realise(mann));
		mann.setCase(Case.DATIVE);
		assertEquals("den Männern", r.realise(mann));		
	
		/* FEMININE NOUN: die Frau */
		frau.setNumber(NumberAgr.SINGULAR);
		frau.setCase(Case.NOMINATIVE);
		assertEquals("die Frau", r.realise(frau));
		frau.setCase(Case.ACCUSATIVE);
		assertEquals("die Frau", r.realise(frau));
		frau.setCase(Case.GENITIVE);
		assertEquals("der Frau", r.realise(frau));
		frau.setCase(Case.DATIVE);
		assertEquals("der Frau", r.realise(frau));
		frau.setNumber(NumberAgr.PLURAL);
		frau.setCase(Case.NOMINATIVE);
		assertEquals("die Frauen", r.realise(frau));
		frau.setCase(Case.ACCUSATIVE);
		assertEquals("die Frauen", r.realise(frau));
		frau.setCase(Case.GENITIVE);
		assertEquals("der Frauen", r.realise(frau));
		frau.setCase(Case.DATIVE);
		assertEquals("den Frauen", r.realise(frau));
		
		/* NEUTER NOUN: das Kind */
		kind.setNumber(NumberAgr.SINGULAR);
		kind.setCase(Case.NOMINATIVE);
		assertEquals("das Kind", r.realise(kind));
		kind.setCase(Case.ACCUSATIVE);
		assertEquals("das Kind", r.realise(kind));
		kind.setCase(Case.GENITIVE);
		assertEquals("des Kindes", r.realise(kind));
		kind.setCase(Case.DATIVE);
		assertEquals("dem Kind", r.realise(kind));
		kind.setNumber(NumberAgr.PLURAL);
		kind.setCase(Case.NOMINATIVE);
		assertEquals("die Kinder", r.realise(kind));
		kind.setCase(Case.ACCUSATIVE);
		assertEquals("die Kinder", r.realise(kind));
		kind.setCase(Case.GENITIVE);
		assertEquals("der Kinder", r.realise(kind));
		kind.setCase(Case.DATIVE);
		assertEquals("den Kindern", r.realise(kind));
		
		/* IRREGULAR NOUN: der Name */
		name.setNumber(NumberAgr.SINGULAR);
		name.setCase(Case.NOMINATIVE);
		assertEquals("der Name", r.realise(name));
		name.setCase(Case.ACCUSATIVE);
		assertEquals("den Namen", r.realise(name));
		name.setCase(Case.GENITIVE);
		assertEquals("des Namens", r.realise(name));
		name.setCase(Case.DATIVE);
		assertEquals("dem Namen", r.realise(name));
		name.setNumber(NumberAgr.PLURAL);
		name.setCase(Case.NOMINATIVE);
		assertEquals("die Namen", r.realise(name));
		name.setCase(Case.ACCUSATIVE);
		assertEquals("die Namen", r.realise(name));
		name.setCase(Case.GENITIVE);
		assertEquals("der Namen", r.realise(name));
		name.setCase(Case.DATIVE);
		assertEquals("den Namen", r.realise(name));
	}
	
	@Test
	public void testNounDeclension2() {
		/* ADJECTIVE-LIKE FLEXION: der/die Beamte */
		beamte.setNumber(NumberAgr.SINGULAR);
		beamte.setCase(Case.NOMINATIVE);
		assertEquals("der Beamte", r.realise(beamte));
		beamte.setCase(Case.ACCUSATIVE);
		assertEquals("den Beamten", r.realise(beamte));
		beamte.setCase(Case.GENITIVE);
		assertEquals("des Beamten", r.realise(beamte));
		beamte.setCase(Case.DATIVE);
		assertEquals("dem Beamten", r.realise(beamte));		
		beamte.setNumber(NumberAgr.PLURAL);
		beamte.setCase(Case.NOMINATIVE);
		assertEquals("die Beamten", r.realise(beamte));
		beamte.setCase(Case.ACCUSATIVE);
		assertEquals("die Beamten", r.realise(beamte));
		beamte.setCase(Case.GENITIVE);
		assertEquals("der Beamten", r.realise(beamte));
		beamte.setCase(Case.DATIVE);
		assertEquals("den Beamten", r.realise(beamte));		

		beamte.setNumber(NumberAgr.SINGULAR);
		beamte.setSpecifier(Constants.getDeterminer(false));
		beamte.setCase(Case.NOMINATIVE);
		assertEquals("ein Beamter", r.realise(beamte));
		beamte.setCase(Case.ACCUSATIVE);
		assertEquals("einen Beamten", r.realise(beamte));
		beamte.setCase(Case.GENITIVE);
		assertEquals("eines Beamten", r.realise(beamte));
		beamte.setCase(Case.DATIVE);
		assertEquals("einem Beamten", r.realise(beamte));		
		beamte.setGender(Gender.FEMININE);
		beamte.setCase(Case.NOMINATIVE);
		assertEquals("eine Beamte", r.realise(beamte));
		beamte.setCase(Case.ACCUSATIVE);
		assertEquals("eine Beamte", r.realise(beamte));
		beamte.setCase(Case.GENITIVE);
		assertEquals("einer Beamten", r.realise(beamte));
		beamte.setCase(Case.DATIVE);
		assertEquals("einer Beamten", r.realise(beamte));		
		
	}
	
	@Test
	public void testCompounding() {
		name = factory.createNounPhrase("der", "Eigen|name");
		
		name.setNumber(NumberAgr.SINGULAR);
		name.setCase(Case.NOMINATIVE);
		assertEquals("der Eigenname", r.realise(name));
		name.setCase(Case.ACCUSATIVE);
		assertEquals("den Eigennamen", r.realise(name));
		name.setCase(Case.GENITIVE);
		assertEquals("des Eigennamens", r.realise(name));
		name.setCase(Case.DATIVE);
		assertEquals("dem Eigennamen", r.realise(name));
		name.setNumber(NumberAgr.PLURAL);
		name.setCase(Case.NOMINATIVE);
		assertEquals("die Eigennamen", r.realise(name));
		name.setCase(Case.ACCUSATIVE);
		assertEquals("die Eigennamen", r.realise(name));
		name.setCase(Case.GENITIVE);
		assertEquals("der Eigennamen", r.realise(name));
		name.setCase(Case.DATIVE);
		assertEquals("den Eigennamen", r.realise(name));
	}
	
	@Test
	public void testVerbConjugation() {
		// TODO: expand to other verbs
		String[] expectedForms;
		List<String> actualForms;
		
		expectedForms = new String[] {
				"sehe", "siehst", "sieht", "sehen", "seht", "sehen",
				"sah", "sahst", "sah", "sahen", "saht", "sahen",
				"sehe", "sehest", "sehe", "sehen", "sehet", "sehen", 
				"sähe", "sähest", "sähe", "sähen", "sähet", "sähen",
				"sieh", "seht", "sehen Sie", "sehen", "sehend", "gesehen"
		};
		actualForms = new ArrayList<String>();
		for (Form f : allForms) {
			for (Tense t : allTenses) {
				for (NumberAgr n : allNums) {
					for (Person p : allPersons) {
						actualForms.add(sehen.getForm(p, n, t, f));
		}}}}
		actualForms.add(sehen.getImperativeForm(NumberAgr.SINGULAR));
		actualForms.add(sehen.getImperativeForm(NumberAgr.PLURAL));
		actualForms.add(sehen.getHonorificImperativeForm());
		actualForms.add(sehen.getInfinitive());
		actualForms.add(sehen.getPresentParticiple());
		actualForms.add(sehen.getPerfectParticiple());
		assertArrayEquals(expectedForms, actualForms.toArray());

		Verb rasen = new Verb("rasen");
		expectedForms = new String[] {
				"rase", "rast", "rast", "rasen", "rast", "rasen",
				"raste", "rastest", "raste", "rasten", "rastet", "rasten",
				"rase", "rasest", "rase", "rasen", "raset", "rasen", 
				"raste", "rastest", "raste", "rasten", "rastet", "rasten",
				"rase", "rast", "rasen Sie", "rasen", "rasend", "gerast"
		};
		actualForms = new ArrayList<String>();
		for (Form f : allForms) {
			for (Tense t : allTenses) {
				for (NumberAgr n : allNums) {
					for (Person p : allPersons) {
						actualForms.add(rasen.getForm(p, n, t, f));
		}}}}
		actualForms.add(rasen.getImperativeForm(NumberAgr.SINGULAR));
		actualForms.add(rasen.getImperativeForm(NumberAgr.PLURAL));
		actualForms.add(rasen.getHonorificImperativeForm());
		actualForms.add(rasen.getInfinitive());
		actualForms.add(rasen.getPresentParticiple());
		actualForms.add(rasen.getPerfectParticiple());
		assertArrayEquals(expectedForms, actualForms.toArray());

	}
	
	// BASIC SENTENCES //
	
	@Test
	public void testBasicSentenceBuilding() {
		resetAll();
		sentence = factory.createSentence(frau, sehen);
		assertEquals("Basic: Intransitive sentence", "Die Frau sieht.", r.realise(sentence));
		
		resetAll();
		sentence = factory.createSentence(frau, sehen, mann);
		assertEquals("Basic: Transitive sentence", "Die Frau sieht den Mann.",
				r.realise(sentence));
		
		resetAll();
		sentence = factory.createSentence(frau, geben, buch);
		sentence.addIndirectObject(mann);
		assertEquals("Basic: Ditransitive sentence", "Die Frau gibt dem Mann ein Buch.",
				r.realise(sentence));

		resetAll();
		Verb gedenken = new Verb("gedenken"); // not correct, but sufficient for this case
		sentence = factory.createSentence(frau, gedenken);
		sentence.addComplement(DiscourseFunction.GENITIVE_OBJECT, mann);
		assertEquals("Basic: Genitive object", "Die Frau gedenkt des Mannes.",
				r.realise(sentence));
	}
	
	// NP FEATURES //
	
	@Test
	public void testPronouns() {
		resetAll();
		NPPhraseSpec p1 = factory.createPersonalPronounPhrase(Person.FIRST, NumberAgr.SINGULAR);
		SPhraseSpec s1 = factory.createSentence(p1, "singen");
		assertEquals("Ich singe.", r.realise(s1));
		
		s1 = factory.createSentence("ich", "singen");
		assertEquals("Ich singe.", r.realise(s1));
		s1 = factory.createSentence("er", "singen");
		assertEquals("Er singt.", r.realise(s1));
		
		Pronoun pro1 = Constants.getPronoun("diejenige");
		p1 = factory.createPronounPhrase(pro1);
		assertEquals("derjenige", r.realise(p1));
	}
	
	@Test
	public void testRefNP() {
		resetAll();
		NPPhraseSpec ref = factory.createReferentialNounPhrase(beamte, "jener");

		sentence = factory.createSentence(frau, geben, buch);
		sentence.addIndirectObject(ref);
		assertEquals("RefNP: basic reference (masc. sg.)",
				"Die Frau gibt jenem ein Buch.",
				r.realise(sentence));
		beamte.setPlural(true);
		assertEquals("RefNP: reference changed to plural",
				"Die Frau gibt jenen ein Buch.",
				r.realise(sentence));
		beamte.setPlural(false);
		beamte.setGender(Gender.FEMININE);
		assertEquals("RefNP: reference changed to feminine",
				"Die Frau gibt jener ein Buch.",
				r.realise(sentence));

		resetAll();
		ref = factory.createReferentialNounPhrase(kind, "derselbe");
		matrix.addComplement(ref);
		assertEquals("RefNP: basic reference",
				"Die Frau sieht dasselbe.",
				r.realise(matrix));

		resetAll();
		ref = factory.createReferentialNounPhrase(buch, "dasselbe");
		matrix.addModifier(factory.createPrepositionalPhrase("in", ref, Case.ACCUSATIVE));
		assertEquals("RefNP: reference within a PP",
				"Die Frau sieht in dasselbe.",
				r.realise(matrix));		
	}
	
	@Test
	public void testNPGenitiveComplements() {
		resetAll();
		frau.addComplement(mann);
		assertEquals("NP: genitive complement", "die Frau des Mannes", r.realise(frau));
		
		frau.setComplement("");
		frau.setSpecifier(mann);
		assertEquals("NP: genitive complement", "des Mannes Frau", r.realise(frau));

		resetAll();
		NPPhraseSpec peter = new NPPhraseSpec("Peter");
		buch.setSpecifier(peter);
		buch.addComplement(mann);
		assertEquals("NP: genitive complement", "Peters Buch des Mannes", r.realise(buch));
	}

	@Test
	public void testNPRelativeClauses() {
		// TODO: punctuation?!
		resetAll();
		sentence = factory.createSentence(geben);
		sentence.addIndirectObject(mann);
		sentence.addComplement(buch);
		frau.addRelativeClause(sentence, DiscourseFunction.SUBJECT);
		assertEquals("NP: relative clause as subject", 
				"die Frau, die dem Mann ein Buch gibt, ", 
				r.realise(frau));

		resetAll();
		sentence = factory.createSentence(frau, geben, buch);
		mann.addRelativeClause(sentence, DiscourseFunction.INDIRECT_OBJECT);
		assertEquals("NP: relative clause as indir. object", 
				"der Mann, dem die Frau ein Buch gibt, ", 
				r.realise(mann));
		
		resetAll();
		sentence = factory.createSentence(frau, geben, buch);
		mann.setPlural(true);
		mann.addRelativeClause(sentence, DiscourseFunction.INDIRECT_OBJECT);
		assertEquals("NP: relative clause as indir. object w/ plural", 
				"die Männer, denen die Frau ein Buch gibt, ", 
				r.realise(mann));

		resetAll();
		sentence = factory.createSentence(frau, geben);
		sentence.addIndirectObject(mann);
		buch.addRelativeClause(sentence, DiscourseFunction.OBJECT);
		assertEquals("NP: relative clause as object", 
				"ein Buch, das die Frau dem Mann gibt, ", 
				r.realise(buch));
		
		resetAll();
		sentence = factory.createSentence(frau, geben);
		sentence.addIndirectObject(mann);
		buch.addRelativeClause(sentence, DiscourseFunction.OBJECT);
		buch.setPlural(true);
		assertEquals("NP: relative clause as object w/ plural", 
				"einige Bücher, die die Frau dem Mann gibt, ", 
				r.realise(buch));

		resetAll();
		buch.addRelativeClause(matrix, new Preposition("in", Case.ACCUSATIVE));
		assertEquals("NP: relative clause as prep. object", 
				"ein Buch, in das die Frau sieht, ", 
				r.realise(buch));
		
		resetAll();
		buch.addRelativeClause(matrix, new Preposition("in", Case.ACCUSATIVE));
		buch.setPlural(true);
		assertEquals("NP: relative clause as prep. object w/ plural", 
				"einige Bücher, in die die Frau sieht, ", 
				r.realise(buch));
		
		resetAll();
		buch.addRelativeClause(matrix, new Preposition("in", Case.ACCUSATIVE), 
				Constants.PRO_WELCHER);
		assertEquals("NP: relative clause as prep. object, w/ welcher",
				"ein Buch, in welches die Frau sieht, ", 
				r.realise(buch));

		resetAll();
		frau.addAttributiveRelativeClause(sub1, kind);
		assertEquals("NP: relative clause as genitive object", 
				"die Frau, deren Kind schön ist, ", 
				r.realise(frau));
		
		resetAll();
		Verb gedenken = new Verb("gedenken"); // not correct, but sufficient for this case
		sentence = factory.createSentence(frau, gedenken);
		mann.addRelativeClause(sentence, DiscourseFunction.GENITIVE_OBJECT);
		assertEquals("NP: relative clause as genitive object",
				"der Mann, dessen die Frau gedenkt, ",
				r.realise(mann));

		resetAll();
		mann.addRelativeClause(sentence, DiscourseFunction.INDIRECT_OBJECT);
		assertEquals("NP: relative clause in a sentence",
				"Der Mann, dem die Frau ein Buch gab, ist schön.",
				r.realise(sub1));

		resetAll();
		sentence.setComplementiser(new NPPhraseSpec(mann, Constants.PRO_REL),
				DiscourseFunction.INDIRECT_OBJECT);
		sub1.addAttributivePostmodifier(sentence);
		assertEquals("NP: extraposed relative clause",
				"Der Mann ist schön, dem die Frau ein Buch gab.",
				r.realise(sub1));
		mann.setPlural(true);
		assertEquals("NP: extraposed relative clause w/ plural",
				"Die Männer sind schön, denen die Frau ein Buch gab.",
				r.realise(sub1));
	}

	@Test
	public void testNPReusing() {
		resetAll();
		SPhraseSpec s1 = new SPhraseSpec(mann, sehen);
		SPhraseSpec s2 = new SPhraseSpec(frau, sehen, mann);
		SPhraseSpec s3 = new SPhraseSpec(frau, geben, buch);
		s3.addIndirectObject(mann);
		SPhraseSpec s4 = new SPhraseSpec(frau, sehen);
		s4.addModifier(factory.createPrepositionalPhrase("wegen", mann));
		
		assertEquals("Der Mann sieht.", r.realise(s1));
		assertEquals("Die Frau sieht den Mann.", r.realise(s2));
		assertEquals("Die Frau gibt dem Mann ein Buch.", r.realise(s3));
		assertEquals("Die Frau sieht wegen des Mannes.", r.realise(s4));
		
		mann.setPlural(true);
		assertEquals("Die Männer sehen.", r.realise(s1));
		assertEquals("Die Frau sieht die Männer.", r.realise(s2));
		assertEquals("Die Frau gibt den Männern ein Buch.", r.realise(s3));
		assertEquals("Die Frau sieht wegen der Männer.", r.realise(s4));
		mann.setPlural(false);
	}
		
	// ADJECTIVES //
	
	@Test
	public void testAdjectiveInflection() {
		testAdjDegree();
		testAdjectiveInflection1();
		testAdjectiveInflection2();
		testAdjectiveInflection3();
		testAdjectiveInflection4();
	}

	private void testAdjDegree() {
		resetAll();

		schoen.addComplement(mann);
		assertEquals("AdjP with complement, positive degree", "schön wie der Mann", r.realise(schoen));
		
		schoen.setDegree(AdjectiveDegree.COMPARATIVE);
		assertEquals("AdjP with complement, comparative degree", "schöner als der Mann", r.realise(schoen));
		
		schoen.setDegree(AdjectiveDegree.SUPERLATIVE);
		assertEquals("AdjP with complement, superlative degree", "am schönsten wie der Mann", r.realise(schoen));
		
		resetAll();
		
		schoen.setDegree(AdjectiveDegree.SUPERLATIVE);
		mann.addModifier(schoen);
		assertEquals("NP with Adj modifier, superlative degree", "der schönste Mann", r.realise(mann));
	}

	private void testAdjectiveInflection1() {
		String[] expectedForms;
		List<String> actualForms;
		resetAll();
		
		mann.addModifier(schoen);
		frau.addModifier(schoen);
		kind.addModifier(schoen);

		expectedForms = new String[] {
				"der schöne Mann", "den schönen Mann", "des schönen Mannes", "dem schönen Mann",
				"die schönen Männer", "die schönen Männer", "der schönen Männer", "den schönen Männern"
		};
		actualForms = new ArrayList<String>();
		for (NumberAgr n : allNums) {
			mann.setNumber(n);
			for (Case c : allCases) {
				mann.setCase(c);
				actualForms.add(r.realise(mann));
		}}
		assertArrayEquals("adjective with definite det, masc.", expectedForms, actualForms.toArray());
		
		expectedForms = new String[] {
				"die schöne Frau", "die schöne Frau", "der schönen Frau", "der schönen Frau",
		};
		actualForms = new ArrayList<String>();
		for (Case c : allCases) {
			frau.setCase(c);
			actualForms.add(r.realise(frau));
		}
		assertArrayEquals("adjective with definite det, fem.", expectedForms, actualForms.toArray());
		
		expectedForms = new String[] {
				"das schöne Kind", "das schöne Kind", "des schönen Kindes", "dem schönen Kind",
		};
		actualForms = new ArrayList<String>();
		for (Case c : allCases) {
			kind.setCase(c);
			actualForms.add(r.realise(kind));
		}
		assertArrayEquals("adjective with definite det, neut.", expectedForms, actualForms.toArray());
	}

	private void testAdjectiveInflection2() {
		String[] expectedForms;
		List<String> actualForms;
		resetAll();
		
		mann.addModifier(schoen);
		mann.setDeterminer(Constants.getDeterminer(false));
		frau.addModifier(schoen);
		frau.setDeterminer(Constants.getDeterminer(false));
		kind.addModifier(schoen);
		kind.setDeterminer(Constants.getDeterminer(false));

		expectedForms = new String[] {
				"ein schöner Mann", "einen schönen Mann", "eines schönen Mannes", "einem schönen Mann",
				"einige schöne Männer", "einige schöne Männer", "einiger schöner Männer", "einigen schönen Männern"
		};
		actualForms = new ArrayList<String>();
		for (NumberAgr n : allNums) {
			mann.setNumber(n);
			for (Case c : allCases) {
				mann.setCase(c);
				actualForms.add(r.realise(mann));
		}}
		assertArrayEquals("adjective with indefinite det, masc.", expectedForms, actualForms.toArray());
		
		expectedForms = new String[] {
				"eine schöne Frau", "eine schöne Frau", "einer schönen Frau", "einer schönen Frau",
		};
		actualForms = new ArrayList<String>();
		for (Case c : allCases) {
			frau.setCase(c);
			actualForms.add(r.realise(frau));
		}
		assertArrayEquals("adjective with indefinite det, fem.", expectedForms, actualForms.toArray());
		
		expectedForms = new String[] {
				"ein schönes Kind", "ein schönes Kind", "eines schönen Kindes", "einem schönen Kind",
		};
		actualForms = new ArrayList<String>();
		for (Case c : allCases) {
			kind.setCase(c);
			actualForms.add(r.realise(kind));
		}
		assertArrayEquals("adjective with indefinite det, neut.", expectedForms, actualForms.toArray());
	}

	private void testAdjectiveInflection3() {
		String[] expectedForms;
		List<String> actualForms;
		resetAll();

		mann.addModifier(schoen);
		mann.setDeterminer(null);
		frau.addModifier(schoen);
		frau.setDeterminer(null);
		kind.addModifier(schoen);
		kind.setDeterminer(null);

		expectedForms = new String[] {
				"schöner Mann", "schönen Mann", "schönen Mannes", "schönem Mann",
				"schöne Männer", "schöne Männer", "schöner Männer", "schönen Männern"
		};
		actualForms = new ArrayList<String>();
		for (NumberAgr n : allNums) {
			mann.setNumber(n);
			for (Case c : allCases) {
				mann.setCase(c);
				actualForms.add(r.realise(mann));
		}}
		assertArrayEquals("adjective without det, masc.", expectedForms, actualForms.toArray());
		
		expectedForms = new String[] {
				"schöne Frau", "schöne Frau", "schöner Frau", "schöner Frau",
		};
		actualForms = new ArrayList<String>();
		for (Case c : allCases) {
			frau.setCase(c);
			actualForms.add(r.realise(frau));
		}
		assertArrayEquals("adjective without det, fem.", expectedForms, actualForms.toArray());
		
		expectedForms = new String[] {
				"schönes Kind", "schönes Kind", "schönen Kindes", "schönem Kind",
		};
		actualForms = new ArrayList<String>();
		for (Case c : allCases) {
			kind.setCase(c);
			actualForms.add(r.realise(kind));
		}
		assertArrayEquals("adjective without det, neut.", expectedForms, actualForms.toArray());
	}

	private void testAdjectiveInflection4() {
		resetAll();
		
		mann.addModifier(teuer);
		assertEquals("irregular adjective inflection", "der teure Mann", r.realise(mann));
		mann.addModifier(schoen);
		assertEquals("multiple adjective modifiers", "der teure, schöne Mann", r.realise(mann));
	}

	// PRONOUNS  //
	
	@Test
	public void testPronounInflection() {
		// TODO: stand-alones ("meins"), pronoun in modifier position
		String[] expectedForms;
		List<String> actualForms;
		resetAll();

		frau.setDeterminer(Constants.getPossessivePronoun(Person.FIRST, NumberAgr.SINGULAR));

		expectedForms = new String[] {
				"meine Frau", "meine Frau", "meiner Frau", "meiner Frau",
				"meine Frauen", "meine Frauen", "meiner Frauen", "meinen Frauen"
		};
		actualForms = new ArrayList<String>();
		for (NumberAgr n : allNums) {
			frau.setNumber(n);
			for (Case c : allCases) {
				frau.setCase(c);
				actualForms.add(r.realise(frau));
			}
		}
		assertArrayEquals("pronoun in determiner position", expectedForms, actualForms.toArray());
	}
	
	// PRONOUN + ADJECTIVE COMBINATIONS //
	
	@Test
	public void testPronounAdjectiveCombinations() {
		testPACAndere();
		testPACBeide();
		testPACManchAndere();
	}
	
	private void testPACAndere() {
		String[] expectedForms;
		List<String> actualForms;
		resetAll();

		Pronoun andere = Constants.getPronoun("andere"); 
		
		mann.addModifier(andere);
		mann.addModifier(schoen);

		expectedForms = new String[] {
				"der andere schöne Mann", 		"den anderen schönen Mann",
				"des anderen schönen Mannes",	"dem anderen schönen Mann",
				"die anderen schönen Männer",	"die anderen schönen Männer",
				"der anderen schönen Männer",	"den anderen schönen Männern"
		};
		actualForms = new ArrayList<String>();
		for (NumberAgr n : allNums) {
			mann.setNumber(n);
			for (Case c : allCases) {
				mann.setCase(c);
				actualForms.add(r.realise(mann));
			}
		}
		assertArrayEquals("'andere' + adj. w/ definite det.", expectedForms, actualForms.toArray());
		
		mann.setSpecifier(Constants.getDeterminer(false));
		expectedForms = new String[] {
				"ein anderer schöner Mann", 	"einen anderen schönen Mann",
				"eines anderen schönen Mannes",	"einem anderen schönen Mann",
				"einige andere schöne Männer",	"einige andere schöne Männer",
				"einiger anderer schöner Männer", "einigen anderen schönen Männern"
		};
		actualForms = new ArrayList<String>();
		for (NumberAgr n : allNums) {
			mann.setNumber(n);
			for (Case c : allCases) {
				mann.setCase(c);
				actualForms.add(r.realise(mann));
			}
		}
		assertArrayEquals("'andere' + adj. w/ indefinite det.", expectedForms, actualForms.toArray());
		
		mann.setSpecifier(andere);
		mann.setPremodifier(schoen);
		expectedForms = new String[] {
				"anderer schöner Mann", 	"anderen schönen Mann",
				"anderen schönen Mannes",	"anderem schönem Mann",
				"andere schöne Männer",		"andere schöne Männer",
				"anderer schöner Männer", 	"anderen schönen Männern"
		};
		actualForms = new ArrayList<String>();
		for (NumberAgr n : allNums) {
			mann.setNumber(n);
			for (Case c : allCases) {
				mann.setCase(c);
				actualForms.add(r.realise(mann));
			}
		}
		assertArrayEquals("'andere' in specifier position", expectedForms, actualForms.toArray());
	
	}
	
	private void testPACBeide() {
		String[] expectedForms;
		List<String> actualForms;
		resetAll();
		
		mann.setPlural(true);
		mann.addModifier(beide);
		mann.addModifier(schoen);

		expectedForms = new String[] {
				"die beiden schönen Männer",
				"die beiden schönen Männer",
				"der beiden schönen Männer",
				"den beiden schönen Männern"
		};
		actualForms = new ArrayList<String>();
		for (Case c : allCases) {
			mann.setCase(c);
			actualForms.add(r.realise(mann));
		}
		assertArrayEquals("beide + adj. w/ definite det.", expectedForms, actualForms.toArray());
		
		mann.setSpecifier(beide);
		mann.setPremodifier(schoen);
		
		expectedForms = new String[] {
				"beide schönen Männer",
				"beide schönen Männer",
				"beider schönen Männer",
				"beiden schönen Männern"
		};
		actualForms = new ArrayList<String>();
		for (Case c : allCases) {
			mann.setCase(c);
			actualForms.add(r.realise(mann));
		}
		assertArrayEquals("beide + adj. w/o det.", expectedForms, actualForms.toArray());
		
	}
	
	private void testPACManchAndere() {
		String[] expectedForms;
		List<String> actualForms;
		resetAll();

		Pronoun andere = Constants.getPronoun("andere"); 
		Pronoun manch  = Constants.getPronoun("manch");
		
		mann.setSpecifier(manch);
		mann.addModifier(andere);
		mann.addModifier(schoen);

		expectedForms = new String[] {
				"mancher andere schöne Mann", 		"manchen anderen schönen Mann",
				"manches anderen schönen Mannes",	"manchem anderen schönen Mann",
				"manche anderen schönen Männer",	"manche anderen schönen Männer",
				"mancher anderen schönen Männer",	"manchen anderen schönen Männern"
		};
		actualForms = new ArrayList<String>();
		for (NumberAgr n : allNums) {
			mann.setNumber(n);
			for (Case c : allCases) {
				mann.setCase(c);
				actualForms.add(r.realise(mann));
			}
		}
		assertArrayEquals("'manche' (inflected) + 'andere' + adj.", expectedForms, actualForms.toArray());
		
		mann.setSpecifier("manch");
		expectedForms = new String[] {
				"manch anderer schöner Mann", 		"manch anderen schönen Mann",
				"manch anderen schönen Mannes",		"manch anderem schönem Mann",
				"manch andere schöne Männer",		"manch andere schöne Männer",
				"manch anderer schöner Männer",		"manch anderen schönen Männern"
		};
		actualForms = new ArrayList<String>();
		for (NumberAgr n : allNums) {
			mann.setNumber(n);
			for (Case c : allCases) {
				mann.setCase(c);
				actualForms.add(r.realise(mann));
			}
		}
		assertArrayEquals("'manch' (uninflected) + 'andere' + adj.", expectedForms, actualForms.toArray());
	
	}
	

	// PP FEATURES //
	
	@Test
	public void testPP() {
		resetAll();
		PPPhraseSpec pp;
		
		pp = factory.createPrepositionalPhrase("wegen", mann);
		assertEquals("wegen des Mannes", r.realise(pp));
		pp.setContraction(true);
		assertEquals("wegen des Mannes", r.realise(pp));
		
		pp = factory.createPrepositionalPhrase("an", mann, Case.DATIVE);
		assertEquals("am Mann", r.realise(pp));
		pp.setContraction(false);
		assertEquals("an dem Mann", r.realise(pp));

		pp = factory.createPrepositionalPhrase("auf", kind);
		assertEquals("auf das Kind", r.realise(pp));
		pp.setContraction(true);
		assertEquals("aufs Kind", r.realise(pp));
		
		pp = factory.createPrepositionalPhrase("in", buch, Case.DATIVE);
		pp.addPremodifier("mitten");
		assertEquals("mitten in einem Buch", r.realise(pp));
	}
	

	// MISCELLANY //
	
	@Test
	public void testNegation() {
		// TODO: NP negation, VP negation, etc. 
		resetAll();
		
		schoen.setNegated(true);
		assertEquals("nicht schön", r.realise(schoen));
		
		schoen.addComplement(mann);
		schoen.setDegree(AdjectiveDegree.COMPARATIVE);
		assertEquals("nicht schöner als der Mann", r.realise(schoen));
	}
	
	@Test
	public void testExpletiveSubject() {
		SPhraseSpec s1 = factory.createSentence("sein");
		s1.addModifier(schoen);
		assertEquals("Es ist schön.", r.realise(s1));
	}

	@Test
	public void testImperative() {
		resetAll();
		sentence.setForm(Form.IMPERATIVE);
		assertEquals("Gib dem Mann ein Buch!", r.realise(sentence));
		sentence.setImperativeForm(NumberAgr.PLURAL, true);
		assertEquals("Geben Sie dem Mann ein Buch!", r.realise(sentence));
		sentence.setImperativeForm(NumberAgr.PLURAL, false);
		assertEquals("Gebt dem Mann ein Buch!", r.realise(sentence));
		matrix.setForm(Form.IMPERATIVE);
		assertEquals("Sieh!", r.realise(matrix));
	}
	
	// VP FEATURES: POSITION & WORD ORDER //
	
	@Test
	public void testPosition() {
		resetAll();

		sentence.addModifier(Position.DEFAULT, "gestern");
		assertEquals("default position",
				"Die Frau gab dem Mann ein Buch gestern.",
				r.realise(sentence));
		
		resetSentence();
		sentence.addModifier(Position.FRONT, "gestern");
		assertEquals("front position",
				"Gestern gab die Frau dem Mann ein Buch.",
				r.realise(sentence));
		
		resetSentence();
		sentence.addModifier(Position.VORFELD, "gestern");
		assertEquals("vorfeld position",
				"Gestern gab die Frau dem Mann ein Buch.",
				r.realise(sentence));

		resetSentence();
		sentence.addModifier(Position.PRE_SUBJECT, "gestern");
		assertEquals("pre-subject position",
				"Gestern gab die Frau dem Mann ein Buch.",
				r.realise(sentence));

		resetSentence();
		sentence.addModifier(Position.PRE_OBJECT, "gestern");
		assertEquals("pre-object position",
				"Die Frau gab dem Mann gestern ein Buch.",
				r.realise(sentence));

		resetSentence();
		sentence.addModifier(Position.POST_INDIRECT_OBJECT, "gestern");
		assertEquals("post-indirect-object position",
				"Die Frau gab dem Mann gestern ein Buch.",
				r.realise(sentence));

		resetSentence();
		sentence.addModifier(Position.PRE_INDIRECT_OBJECT, "gestern");
		assertEquals("pre-indirect-object position",
				"Die Frau gab gestern dem Mann ein Buch.",
				r.realise(sentence));

		resetSentence();
		sentence.addModifier(Position.POST_SUBJECT, "gestern");
		assertEquals("post-subject position",
				"Die Frau gab gestern dem Mann ein Buch.",
				r.realise(sentence));

		resetSentence();
		sentence.addModifier(Position.POST_OBJECT, "gestern");
		assertEquals("post-subject position",
				"Die Frau gab dem Mann ein Buch gestern.",
				r.realise(sentence));
	}
	
	@Test
	public void testWordOrder() {
		resetAll();
		assertEquals("Die Frau gab dem Mann ein Buch.", 
				r.realise(sentence));
		
		resetSentence();
		sentence.setWordOrder(WordOrder.SIO);
		assertEquals("Die Frau gab dem Mann ein Buch.", 
				r.realise(sentence));

		resetSentence();
		sentence.setWordOrder(WordOrder.SOI);
		assertEquals("Die Frau gab ein Buch dem Mann.", 
				r.realise(sentence));

		resetSentence();
		sentence.setWordOrder(WordOrder.ISO);
		assertEquals("Dem Mann gab die Frau ein Buch.", 
				r.realise(sentence));

		resetSentence();
		sentence.setWordOrder(WordOrder.IOS);
		assertEquals("Dem Mann gab ein Buch die Frau.", 
				r.realise(sentence));

		resetSentence();
		sentence.setWordOrder(WordOrder.OSI);
		assertEquals("Ein Buch gab die Frau dem Mann.", 
				r.realise(sentence));

		resetSentence();
		sentence.setWordOrder(WordOrder.OIS);
		assertEquals("Ein Buch gab dem Mann die Frau.", 
				r.realise(sentence));
	}

	// VP FEATURES: PASSIVE & INTERROGATIVE SENTENCES //
	
	@Test
	public void testPassive() {
		resetAll();
		sentence.setPassive(true);
		assertEquals("Ein Buch wurde dem Mann von der Frau gegeben.",
				r.realise(sentence));
		
		resetSentence();
		sentence.setPassive(true);
		sentence.setWordOrder(WordOrder.IOS);
		assertEquals("Dem Mann wurde ein Buch von der Frau gegeben.",
				r.realise(sentence));
		
		resetSentence();
		sentence.setPassive(true);
		sentence.setPassiveComplementPosition(Position.PRE_SUBJECT);
		sentence.setWordOrder(WordOrder.IOS);
		assertEquals("Dem Mann wurde von der Frau ein Buch gegeben.",
				r.realise(sentence));
		
		resetSentence();
		sentence.setPassive(true);
		sentence.setPassiveComplementPosition(Position.FRONT);
		sentence.setWordOrder(WordOrder.IOS);
		assertEquals("Von der Frau wurde dem Mann ein Buch gegeben.",
				r.realise(sentence));
		
		resetSentence();
		sentence.setPassive(true);
		sentence.setPassiveComplementRealisation(false);
		assertEquals("Ein Buch wurde dem Mann gegeben.",
				r.realise(sentence));
		
		resetMatrix();
		matrix.setPassive(true);
		assertEquals("Es wird von der Frau gesehen.",
				r.realise(matrix));
	}

	@Test
	public void testInterrogatives() {
		resetAll();
		sentence.setInterrogative(InterrogativeType.JA_NEIN);
		assertEquals("Gab die Frau dem Mann ein Buch?",
				r.realise(sentence));
		
		resetSentence();
		sentence.setInterrogative(InterrogativeType.JA_NEIN);
		sentence.setWordOrder(WordOrder.OSI);
		sentence.addModifier(Position.FRONT, "gestern");
		assertEquals("Gab gestern ein Buch die Frau dem Mann?",
				r.realise(sentence));
		
		resetSentence();
		sentence.setInterrogative(InterrogativeType.WER);
		assertEquals("Wer gab dem Mann ein Buch?",
				r.realise(sentence));

		resetSentence();
		sentence.setInterrogative(InterrogativeType.WER, DiscourseFunction.INDIRECT_OBJECT);
		assertEquals("Wem gab die Frau ein Buch?",
				r.realise(sentence));
		
		resetSentence();
		sentence.setInterrogative(InterrogativeType.WER, DiscourseFunction.OBJECT);
		assertEquals("Wen gab die Frau dem Mann?",
				r.realise(sentence));
		
		resetSentence();
		sentence.setInterrogative(InterrogativeType.WARUM);
		assertEquals("Warum gab die Frau dem Mann ein Buch?",
				r.realise(sentence));

		resetSentence();
		sentence.setInterrogative("inwiefern");
		assertEquals("Inwiefern gab die Frau dem Mann ein Buch?",
				r.realise(sentence));
		
		resetMatrix();
		mann.setSpecifier(Constants.getPronoun("welcher"));
		matrix.setInterrogative(mann, DiscourseFunction.OBJECT);
		assertEquals("Welchen Mann sieht die Frau?",
				r.realise(matrix));

		resetAll();
		sentence.setEchoInterrogative("ob");
		assertEquals("Ob die Frau dem Mann ein Buch gab?",
				r.realise(sentence));

		resetSentence();
		sentence.setEchoInterrogative(InterrogativeType.WAS, DiscourseFunction.OBJECT);
		assertEquals("Was die Frau dem Mann gab?",
				r.realise(sentence));
		
		// TODO: elegant way to control interrogative placement...
		resetAll();
		sentence.setIndirectObject(Constants.getInterrogative(InterrogativeType.WER));
		sentence.setSentenceTerminator('?');
		assertEquals("Die Frau gab wem ein Buch?",
				r.realise(sentence));

	}
	
	@Test
	public void testPassiveInterrogatives() {
		// now things get nasty
		resetAll();
		sentence.setInterrogative(InterrogativeType.WARUM);
		sentence.setPassive(true);
		assertEquals("Warum wurde ein Buch dem Mann von der Frau gegeben?",
				r.realise(sentence));

		resetSentence();
		sentence.setInterrogative(InterrogativeType.WER, DiscourseFunction.INDIRECT_OBJECT);
		sentence.setPassive(true);
		assertEquals("Wem wurde ein Buch von der Frau gegeben?",
				r.realise(sentence));

		resetAll();
		sentence = new SPhraseSpec(frau, geben, buch);
		sentence.setTense(Tense.PAST);
		mann.setSpecifier(Constants.getPronoun("welcher"));
		sentence.setInterrogative(mann, DiscourseFunction.INDIRECT_OBJECT);
		sentence.setPassive(true);
		assertEquals("Welchem Mann wurde ein Buch von der Frau gegeben?",
				r.realise(sentence));

		resetAll();
		sentence.setInterrogative(InterrogativeType.WER, DiscourseFunction.OBJECT);
		sentence.setPassive(true);
		assertEquals("Wer wurde dem Mann von der Frau gegeben?",
				r.realise(sentence));

		resetSentence();
		sentence.setInterrogative(InterrogativeType.WER, DiscourseFunction.SUBJECT);
		sentence.setPassive(true);
		assertEquals("Von wem wurde ein Buch dem Mann gegeben?",
				r.realise(sentence));
	}
	
	// VP FEATURES: MODAL VERBS //
	
	@Test
	public void testModalVerbs() {
		resetAll();
		matrix.addComplement(mann);
		matrix.addModal("können");
		assertEquals("Die Frau kann den Mann sehen.", r.realise(matrix));
		
		matrix.addModal("müssen");
		assertEquals("Die Frau muss den Mann sehen können.", r.realise(matrix));
		
		matrix.setPerfect(true);
		assertEquals("Die Frau hat den Mann sehen können müssen.", r.realise(matrix));
		
		matrix.setPerfect(false);
		matrix.setMainVerbPerfect(true);
		assertEquals("Die Frau muss den Mann gesehen haben können.", r.realise(matrix));

		matrix.setPerfect(true);
		assertEquals("Die Frau hat den Mann gesehen haben können müssen.", r.realise(matrix));

		matrix.setModal("müssen");
		matrix.setPerfect(false);
		matrix.setMainVerbPerfect(false);
		assertEquals("Die Frau muss den Mann sehen.", r.realise(matrix));

		matrix.clearModals();
		assertEquals("Die Frau sieht den Mann.", r.realise(matrix));
	}
	
	@Test
	public void testSeparableVerbs() {
		SPhraseSpec s = factory.createSentence(frau, "aus|gehen");
		assertEquals("Die Frau geht aus.", r.realise(s));
		
		s.addModal("wollen");
		assertEquals("Die Frau will ausgehen.", r.realise(s));
		
		s = factory.createSentence(frau, "Gassi gehen");
		assertEquals("Die Frau geht Gassi.", r.realise(s));
		
		s.addModal("wollen");
		assertEquals("Die Frau will Gassi gehen.", r.realise(s));
		
		s = factory.createSentence(frau, "auf die Nerven gehen");
		s.addIndirectObject(mann);
		assertEquals("Die Frau geht dem Mann auf die Nerven.", r.realise(s));
		
		s.addModal("wollen");
		assertEquals("Die Frau will dem Mann auf die Nerven gehen.", r.realise(s));

		s = factory.createSentence(frau, "den Berg hinauf|gehen");
		assertEquals("Die Frau geht den Berg hinauf.", r.realise(s));
		
		s.addModal("wollen");
		assertEquals("Die Frau will den Berg hinaufgehen.", r.realise(s));

	}
	
	@Test
	public void testCoordinates() {
		resetAll();
		NPPhraseSpec coord = frau.coordinate(mann);
		assertEquals("die Frau und der Mann", r.realise(coord));
		
		CoordinateNPPhraseSpec c2 = (CoordinateNPPhraseSpec) coord;
		c2.setConjunction("oder");
		assertEquals("die Frau oder der Mann", r.realise(c2));

		CoordinateNPPhraseSpec c3 = (CoordinateNPPhraseSpec) frau.coordinate(mann, kind);
		assertEquals("die Frau, der Mann und das Kind", r.realise(c3));
	}
	
	// SENTENTIAL MODIFIERS & SUBORDINATES //

	@Test
	public void testSubordinates() {
		resetAll();
		sentence.addSubordinate("obwohl", sub1);
		assertEquals("Die Frau gab dem Mann ein Buch, obwohl der Mann schön ist.",
				r.realise(sentence));
	
		resetAll();
		frau.addSubordinate("dass", sub1); // makes no sense, but imagine "Frau" == "Tatsache"
		assertEquals("die Frau, dass der Mann schön ist, ",
				r.realise(frau));
		
		// Nebengeordnete Konjunktionen
		resetAll();
		CoordinateSPhraseSpec s2 = (CoordinateSPhraseSpec) sentence.coordinate(sub1);
		s2.setConjunction("denn");
		s2.setEnforceComma(true);
		assertEquals("Die Frau gab dem Mann ein Buch, denn der Mann ist schön.",
				r.realise(s2));
	}

	@Test
	public void testSententialModifiers() {
		resetAll();
		matrix.addSubordinate("dass", sub1);
		assertEquals("Die Frau sieht, dass der Mann schön ist.",
				r.realise(matrix));

		resetMatrix();
		matrix.addSubordinate(Position.FRONT, "dass", sub1);
		assertEquals("Dass der Mann schön ist, sieht die Frau.",
				r.realise(matrix));

		resetMatrix();
		matrix.addComplement(sub1);
		assertEquals("Die Frau sieht den Mann schön sein.",
				r.realise(matrix));
	}

	@Test
	public void testTensePerfect() {
		resetAll();
		matrix.addComplement(mann);
		matrix.setPerfect(true);
		assertEquals("Die Frau hat den Mann gesehen.",
				r.realise(matrix));

		resetAll();
		matrix.addComplement(mann);
		matrix.setTense(Tense.PAST);
		assertEquals("Die Frau sah den Mann.",
				r.realise(matrix));
		matrix.setPerfect(true);
		assertEquals("Die Frau hatte den Mann gesehen.",
				r.realise(matrix));

		resetAll();
		matrix.addComplement(mann);
		matrix.setTense(Tense.FUTURE);
		assertEquals("Die Frau wird den Mann sehen.",
				r.realise(matrix));
		matrix.setPerfect(true);
		assertEquals("Die Frau wird den Mann gesehen haben.",
				r.realise(matrix));
		
	}
	
	@Test
	public void testMood() {
		resetAll();
		matrix.addComplement(mann);
		matrix.setForm(Form.SUBJUNCTIVE);
		assertEquals("Die Frau sehe den Mann.",
				r.realise(matrix));
		matrix.setTense(Tense.PAST);
		assertEquals("Die Frau sähe den Mann.",
				r.realise(matrix));
		matrix.setTense(Tense.FUTURE);
		assertEquals("Die Frau werde den Mann sehen.",
				r.realise(matrix));
		matrix.setForm(Form.SUBJUNCTIVE_II);
		assertEquals("Die Frau würde den Mann sehen.",
				r.realise(matrix));

	}
	
	@Test
	public void testSubordinatePlacement() {
		resetAll();
		sentence.addSubordinate("weil", sub1);
		assertEquals("Die Frau gab dem Mann ein Buch, weil der Mann schön ist.",
				r.realise(sentence));
	
		resetAll();
		sentence.addSubordinate("weil", sub1);
		sentence.setPerfect(true);
		assertEquals("Die Frau hatte dem Mann ein Buch gegeben, weil der Mann schön ist.",
				r.realise(sentence));
		
		resetAll();
		sentence.addSubordinate(Position.DEFAULT, "weil", sub1);
		assertEquals("Die Frau gab dem Mann ein Buch, weil der Mann schön ist.",
				r.realise(sentence));

		resetAll();
		sentence.addSubordinate(Position.DEFAULT, "weil", sub1);
		sentence.setPerfect(true);
		assertEquals("Die Frau hatte dem Mann ein Buch, weil der Mann schön ist, gegeben.",
				r.realise(sentence));
		
		resetAll();
		sentence.addSubordinate(Position.FRONT, "weil", sub1);
		assertEquals("Weil der Mann schön ist, gab die Frau dem Mann ein Buch.",
				r.realise(sentence));

		resetAll();
		sentence.addSubordinate(Position.POST_INDIRECT_OBJECT, "weil", sub1);
		assertEquals("Die Frau gab dem Mann, weil der Mann schön ist, ein Buch.",
				r.realise(sentence));

		resetAll();
		sentence.addSubordinate(Position.PRE_INDIRECT_OBJECT, "weil", sub1);
		assertEquals("Die Frau gab, weil der Mann schön ist, dem Mann ein Buch.",
				r.realise(sentence));

}


	/// ///
	@Test
	public void testVariousSentences() {
		NPPhraseSpec trainGrund = factory.createNounPhrase("ein Grundlagen|training");
		NPPhraseSpec trainErhol = factory.createNounPhrase("ein Erholungs|training");
		CoordinateNPPhraseSpec cnp = new CoordinateNPPhraseSpec(trainGrund, trainErhol);
		cnp.setConjunction("oder");
		cnp.raiseSpecifier();
		PPPhraseSpec pp1 = factory.createPrepositionalPhrase("für", cnp);
	
		NPPhraseSpec werte = factory.createNounPhrase("Wert");
		werte.setPlural(true);
		werte.setSpecifier(Constants.getHonorificPronoun(true)); 
		
		SPhraseSpec s1 = factory.createSentence(werte, "sein");
		s1.addModifier(pp1);
		s1.addModifier("optimal");
		//s1.addComplement(DiscourseFunction.PREDICATIVE_COMPLEMENT, "optimal");
	
		assertEquals("Ihre Werte sind für ein Grundlagentraining oder Erholungstraining optimal.",
				r.realise(s1));
	
		NPPhraseSpec tempo = factory.createNounPhrase("Trainings|tempo");
		tempo.setSpecifier("Ihr");
		
		SPhraseSpec sub = factory.createSentence("Sie", "steigern");
		sub.addComplement(tempo);
		sub.addModal("mögen");
		sub.setForm(Form.SUBJUNCTIVE_II);
		sub.addModifier("weiter");
		sub.setComplementiser("wenn");
		
		SPhraseSpec s2 = factory.createSentence("Sie", "tun");
		s2.addModal("sollen");
		s2.setForm(Form.SUBJUNCTIVE_II);
		s2.addComplement("dies");
		s2.addModifier("ruhig");
		
		s2.addModifier(Position.FRONT, sub);
		
		assertEquals("Wenn Sie Ihr Trainingstempo weiter steigern möchten, sollten Sie dies ruhig tun.",
				r.realise(s2));
	}
	
}
