package ws.prova.reference;

/*
 * Copyright (C) 1999-2005 <a href="mailto:mandarax@jbdietrich.com">Jens Dietrich</a>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

import org.mandarax.kernel.*;
import org.mandarax.lib.Cut;

/**
 * Factory object for creating logical entities objects.
 * The classes with the postfix <it>Impl</it> should never be instanciated
 * directly. Instead use instances of this class. To use alternative
 * implementations, subclass this class. <br> To install an instance of this
 * class to be the default factory use the following code:
 * <code>(new DefaultLogicFactory()).install()</code>. If this is done, a
 * reference to the factory can be obtained using
 * <code>LogicFactory.getDefaultFactory()</code>.
 * <br>
 * As from 1.9, queries are supported.
 *
 * @author <A HREF="mailto:mandarax@jbdietrich.com">Jens Dietrich</A>
 * @version 3.3.1 <9 August 2004>
 * @since 1.1
 */
public class DefaultLogicFactory extends LogicFactory {
	private Prerequisite cut = null;
	static LogicFactory defaultFactory = null;

	/**
	 * Constructor.
	 */
	public DefaultLogicFactory() {
		super();
	}

	/**
	 * Get the default factory.
	 *
	 * @return the default factory object
	 */
	public static LogicFactory getDefaultFactory() {
		if (defaultFactory == null) {
			try {

				// try to set the default factory, use reference by name in order
				// to keep this package independent from the reference package !!
				Class clazz =
						Class.forName("ws.prova.reference.DefaultLogicFactory");
				LogicFactory lf = (LogicFactory) clazz.newInstance();

				lf.install();
				defaultFactory = lf;
			} catch (Exception x) {
				System.err.println("cannot install ws.prova.reference.DefaultLogicFactory");
			}
		}

		return defaultFactory;
	}

	/**
	 * Create a new complex term.
	 *
	 * @param anFunction a function
	 * @param terms      an array of terms
	 * @return the created complex term
	 */
	public ComplexTerm createComplexTerm(Function anFunction, Term[] terms) {
		return new ComplexTermImpl(anFunction, terms);
	}

	/**
	 * Create a new constant term.
	 *
	 * @param obj the object that is to be wrapped by the constant term
	 * @return the created constant term
	 */
	public ConstantTerm createConstantTerm(Object obj) {
		return new ConstantTermImpl(obj);
	}

	/**
	 * Create a new constant term.
	 *
	 * @param obj  the wrapped object
	 * @param type the type of the object
	 * @return a new constant term
	 * @throws IllegalArgumentException if object and type are inconsistent,
	 *                                  i.e. if type object is not an instance of type
	 */
	public ConstantTerm createConstantTerm(Object obj, Class type) {
		return new ConstantTermImpl(obj, type);
	}

	/**
	 * Create a new fact.
	 *
	 * @param aPredicate the predicate
	 * @param terms      the terms
	 * @return the created fact
	 */
	public Fact createFact(Predicate aPredicate, Term[] terms) {
		return new FactImpl(aPredicate, terms);
	}

	/**
	 * Create a new prerequisite.
	 *
	 * @param aPredicate a predicate
	 * @param terms      an array of terms
	 * @param negatedAF  whether the prerequisite is negated (as failure)
	 * @return a new prerequisite
	 */
	public Prerequisite createPrerequisite(Predicate aPredicate, Term[] terms, boolean negatedAF) {
		return new PrerequisiteImpl(aPredicate, terms, negatedAF);
	}

	/**
	 * Create a cut prerequisite.
	 *
	 * @return a prerequisite
	 */
	public Prerequisite createCut() {
		// 2.2: Each cut has to be a unique instance
//    	if (cut==null) {
		cut = new PrerequisiteImpl(new Cut(), new Term[]{}, false) {
			/**
			 * Indicates whether the prerequisite is negated (negation as failure)
			 *
			 * @return true if the prerequisite is negated, false otherwise
			 */
			public boolean isNegatedAF() {
				return false;
			}

			/**
			 * Set the negated (as failure) flag.
			 *
			 * @param value true or false
			 */
			public void setNegatedAF(boolean value) {
				// ignored
			}
		};
//    	}
		return cut;
	}

	/**
	 * Create a new rule.
	 *
	 * @param body a list of facts that will become the body of the rule
	 * @param head a fact that will become the head of the rule
	 * @return the created rule
	 */
	public Rule createRule(java.util.List body, Fact head) {
		return new RuleImpl(body, head);
	}

	/**
	 * Create a new rule.
	 *
	 * @param body a list facts becoming the body of the rules
	 * @param head the head of the rule
	 * @param or   indicates whether the prerequisites are connected by OR
	 * @return a new rule
	 */
	public Rule createRule(java.util.List body, Fact head, boolean or) {
		return new RuleImpl(body, head, or);
	}

	/**
	 * Create a new rule with an empty body.
	 *
	 * @param head the fact that will become the head of the rule
	 * @return the created rule
	 */
	public Rule createRule(Fact head) {
		return createRule(new java.util.ArrayList(), head);
	}

	/**
	 * Create a new variable term.
	 *
	 * @param aName the name of the variable
	 * @param aType the type of the variable
	 * @return the created variable term
	 */
	public VariableTerm createVariableTerm(String aName, Class aType) {
		return new VariableTermImpl(aName, aType);
	}

	/**
	 * Create a new query.
	 *
	 * @param fact aFact
	 * @param name the name of the query
	 * @return a new query
	 */
	public Query createQuery(Fact fact, String name) {
		Fact[] facts = {fact};
		return createQuery(facts, name);
	}

	/**
	 * Create a new query.
	 *
	 * @param facts an array of facts
	 * @param name  the name of the query
	 * @return a new query
	 */
	public Query createQuery(Fact[] facts, String name) {
		return new QueryImpl(facts, name);
	}

	/**
	 * Return the implementation class for facts.
	 *
	 * @return a class
	 */
	public Class getFactImplementationClass() {
		return FactImpl.class;
	}

	/**
	 * Return the implementation class for rules.
	 *
	 * @return a class
	 */
	public Class getRuleImplementationClass() {
		return RuleImpl.class;
	}

	/**
	 * Return the implementation class for prerequisites.
	 *
	 * @return a class
	 */
	public Class getPrerequisiteImplementationClass() {
		return PrerequisiteImpl.class;
	}

	/**
	 * Return the implementation class for queries.
	 *
	 * @return a class
	 */
	public Class getQueryImplementationClass() {
		return QueryImpl.class;
	}

	/**
	 * Return the implementation class for constant terms.
	 *
	 * @return a class
	 */
	public Class getConstantTermImplementationClass() {
		return ConstantTermImpl.class;
	}

	/**
	 * Return the implementation class for variable terms.
	 *
	 * @return a class
	 */
	public Class getVariableTermImplementationClass() {
		return VariableTermImpl.class;
	}

	/**
	 * Return the implementation class for complex terms.
	 *
	 * @return a class
	 */
	public Class getComplexTermImplementationClass() {
		return ComplexTermImpl.class;
	}
}
