/*
 * EvolpPrettyPrinterTest.java
 * JUnit based test
 *
 * Copyright (C) 2006 - 2007 Martin Slota
 *
 * 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., 51
 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

/*
 * History:
 * v1.0.0 (2007-05-05):
 * - no version information kept before :P
 */

package lp.struct.util;

import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import lp.struct.LpAtom;
import lp.struct.LpConstant;
import lp.struct.LpLiteral;
import lp.struct.LpPredicate;
import lp.struct.LpRule;
import lp.struct.LpTerm;
import lp.struct.LpVariable;

/**
 * Contains tests of the {@link EvolpPrettyPrinter} class.
 *
 * @author Martin Slota
 * @version 1.0.0
 * @see EvolpPrettyPrinter
 */
public class EvolpPrettyPrinterTest extends LpPrettyPrinterTest {
	/**
	 * A default test case constructor.
	 *
	 * @param testName the name of the test case
	 */
	public EvolpPrettyPrinterTest(String testName) {
		super(testName);
	}
	
	/**
	 * Reinitializes all members ({@link #r}, {@link #pp}, {@link #pp2},
	 * {@link #expContents} and {@link #expContents2}).
	 */
	protected void setUp() {
		r = new Random();
		pp = EvolpPrettyPrinter.getBuffer();
		pp2 = EvolpPrettyPrinter.getBuffer(":-", false);
		expContents = new StringBuilder();
		expContents2 = new StringBuilder();
	}
	
	/**
	 * Tests the {@link EvolpPrettyPrinter} on rules that contain other rules as
	 * an inner term.
	 */
	public void testAppendEvolpRule() {
		LpPredicate predSunny = LpPredicate.getInstance("sunny", 0);
		LpPredicate predDay = LpPredicate.getInstance("day", 0);
		LpPredicate predColor = LpPredicate.getInstance("color", 2);
		LpAtom atomSunny = LpAtom.getInstance(predSunny, null);
		LpAtom atomDay = LpAtom.getInstance(predDay, null);
		
		LpConstant constRed = LpConstant.getInstance("red");
		LpVariable varX = LpVariable.getInstance("X");
		List<LpTerm> args = new ArrayList<LpTerm>();
		args.add(constRed);
		args.add(varX);
		LpAtom atomColor = LpAtom.getInstance(predColor, args);
		
		LpRule factSunny = new LpRule(atomSunny.getPositiveLiteral(), null);
		doTest("sunny.", factSunny);
		
		LpRule factNotSunny = new LpRule(atomSunny.getNegativeLiteral(), null);
		doTest("not sunny.", factNotSunny);
		
		LpRule factColor = new LpRule(atomColor.getPositiveLiteral(), null);
		doTest("color(red, X).", factColor);
		
		Set<LpLiteral> ruleBody = new LinkedHashSet<LpLiteral>();
		ruleBody.add(atomColor.getNegativeLiteral());
		ruleBody.add(atomDay.getPositiveLiteral());
		LpRule ruleSunny = new LpRule(atomSunny.getPositiveLiteral(), ruleBody);
		doTest("sunny <- not color(red, X), day.", ruleSunny);
		
		// the constraint "<- p."
		LpRule constraint = new LpRule(null, ruleBody);
		doTest("<- not color(red, X), day.", constraint);
		
		LpPredicate predAssert1 = LpPredicate.getInstance("assert", 1);
		doAssertTest("assert(sunny <-).", predAssert1, factSunny);
		doAssertTest("assert(not sunny <-).", predAssert1, factNotSunny);
		doAssertTest("assert(sunny <- not color(red, X), day).",
				predAssert1, ruleSunny);
		doAssertTest("assert(<- not color(red, X), day).",
				predAssert1, constraint);
		
		
		LpPredicate predAssert2 = LpPredicate.getInstance("assert", 2);
		LpConstant constJohn = LpConstant.getInstance("john");
		
		doAssertTest("assert(john, sunny <-).",
				predAssert2, constJohn, factSunny);
		doAssertTest("assert(john, not sunny <-).",
				predAssert2, constJohn, factNotSunny);
		doAssertTest("assert(john, sunny <- not color(red, X), day).",
				predAssert2, constJohn, ruleSunny);
		doAssertTest("assert(john, <- not color(red, X), day).",
				predAssert2, constJohn, constraint);
		
		doAssertTest("assert(sunny <-, john).",
				predAssert2, factSunny, constJohn);
		doAssertTest("assert(not sunny <-, john).",
				predAssert2, factNotSunny, constJohn);
		doAssertTest("assert((sunny <- not color(red, X), day), john).",
				predAssert2, ruleSunny, constJohn);
		doAssertTest("assert((<- not color(red, X), day), john).", 
				predAssert2, constraint, constJohn);
	}
	
	/**
	 * Tests whether a fact formed by the predicate symbol {@code pred} with 
	 * {@code argTerms} as its arguments will be appended (or converted to 
	 * string) correctly.
	 *
	 * @param expected the expected string that should be returned/appended
	 * @param pred the predicate symbol of the fact's head literal
	 * @param argTerms arguments of the fact's head literal
	 */
	protected void doAssertTest(String expected, LpPredicate pred, 
			LpTerm ... argTerms) {
		List<LpTerm> args = new ArrayList<LpTerm>();
		for (LpTerm argTerm : argTerms)
			args.add(argTerm);
		LpAtom headAtom = LpAtom.getInstance(pred, args);
		LpRule rule = new LpRule(headAtom.getPositiveLiteral(), null);
		doTest(expected, rule);
	}
}