/*
 * Copyright (C) 1999-2004 <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
 */
package org.mandarax.kernel;


/**
 * Abstract factory object for creating logical entities such as rules, facts and terms.
 * The implementing classes should never be instanciated
 * directly. Instead use instances of this class to create them.
 * Support for obtaining a reference to a default logic factory is provided -
 * use the static method <code>getDefaultFactory()</code> to obtain a reference.
 * Note that be default we try to initialize the default factory with an instance of
 * the subclass <code>org.mandarax.reference.DefaultLogicFactory</code>. The respective
 * refernce is obtained using <code>Class.forName()</code> so that this package does
 * only have a weak dependency to the <code>org.mandarax.reference</code> package.
 * <br>
 * As from 1.9, queries are supported.
 * @see org.mandarax.reference.DefaultLogicFactory
 * @author <A HREF="mailto:mandarax@jbdietrich.com">Jens Dietrich</A>
 * @version 3.3.1 <9 August 2004>
 * @since 1.1
 */
public abstract class LogicFactory extends LObject {

    private static LogicFactory defaultFactory = null;
    /**
     * Constructor.
     */
    public LogicFactory() {
        super ();
    }
    /**
     * Create a new complex term.
     * @return a new complex term
     * @param aFunction a function
     * @param terms an array of terms
     */
    public abstract ComplexTerm createComplexTerm(Function aFunction,
            Term[] terms);
    /**
     * Create a new constant term.
     * @return a new constant term
     * @param obj the wrapped object
     */
    public abstract ConstantTerm createConstantTerm(Object obj);
    /**
     * Create a new constant term.
     * @return a new constant term
     * @param obj the wrapped object
     * @param type the type of the object
     * @throws throws an IllegalArgumentException if object and type are inconsistent,
     * i.e. if type object is not an instance of type
     */
    public abstract ConstantTerm createConstantTerm(Object obj, Class type);
    /**
     * Create a new query.
     * @return a new query
     * @param fact aFact
     * @param name the name of the query
     */
    public abstract Query createQuery(Fact fact,String name); 
    /**
     * Create a new query.
     * @return a new query
     * @param facts an array of facts
     * @param name the name of the query
     */
    public abstract Query createQuery(Fact[] facts,String name);        
    /**
     * Create a new fact.
     * @return a new fact
     * @param aPredicate a predicate
     * @param terms an array of terms
     */
    public abstract Fact createFact(Predicate aPredicate, Term[] terms); 
    /**
     * Create a new prerequisite.
     * @return a new prerequisite
     * @param aPredicate a predicate
     * @param terms an array of terms
     * @param negatedAF whether the prerequisite is negated (as failure)
     */
    public abstract Prerequisite createPrerequisite(Predicate aPredicate, Term[] terms, boolean negatedAF);     
    /**
     * Create a cut prerequisite.
     * @return a prerequisite
     */
    public abstract Prerequisite createCut();
    /**
     * Create a new rule.
     * @return a new rule
     * @param body a list of prerequisites
     * @param head the head of the rule
     */
    public abstract Rule createRule(java.util.List body, Fact head);
    /**
     * Create a new rule.
     * @return a new rule
     * @param body a list of prerequisites
     * @param head the head of the rule
     * @param or indicates whether the prerequisites are connected by OR
     */
    public abstract Rule createRule(java.util.List body, Fact head,boolean or);
    /**
     * Create a new rule with an empty body.
     * @return a new rule
     * @param head a fact that becomes the head of the created rule
     */
    public Rule createRule(Fact head) {
        return createRule (new java.util.ArrayList (), head);
    }
    /**
     * Create a new variable term.
     * @return a new variable term
     * @param aName the name of the term
     * @param aType the type of the term
     */
    public abstract VariableTerm createVariableTerm(String aName,Class aType);
    /**
     * 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 (
                        "org.mandarax.reference.DefaultLogicFactory");
                LogicFactory lf = (LogicFactory) clazz.newInstance ();

                lf.install ();
            } catch(Exception x) {
                System.err.println (
                    "cannot install org.mandarax.reference.DefaultLogicFactory");
            }
        }

        return defaultFactory;
    }
    /**
     * Install the object to become the default factory.
     */
    public void install() {
        defaultFactory = this;
    }
    /**
     * Return the implementation class for facts. 
     * @return a class
     */
    public abstract Class getFactImplementationClass();
	/**
	 * Return the implementation class for rules. 
	 * @return a class
	 */
	public abstract Class getRuleImplementationClass();
	/**
	 * Return the implementation class for prerequisites. 
	 * @return a class
	 */
	public abstract Class getPrerequisiteImplementationClass();
	/**
	 * Return the implementation class for queries. 
	 * @return a class
	 */
	public abstract Class getQueryImplementationClass();
	/**
	 * Return the implementation class for constant terms. 
	 * @return a class
	 */
	public abstract Class getConstantTermImplementationClass();
	/**
	 * Return the implementation class for variable terms. 
	 * @return a class
	 */
	public abstract Class getVariableTermImplementationClass();
	/**
	 * Return the implementation class for complex terms. 
	 * @return a class
	 */
	public abstract Class getComplexTermImplementationClass();
}
