package ws.prova.util;

/**
 * Prova re-integration: this module comes from previous Mandarax versions.
 * @author <A HREF="mailto:a.kozlenkov@city.ac.uk">Alex Kozlenkov</A>
 * @version 1.5 <07 Jul 2004>
 * Prova re-integration modifications
 * @author <A HREF="mailto:a.kozlenkov@city.ac.uk">Alex Kozlenkov</A>
 * @version 2.0 <25 March 2007>
 */

import org.mandarax.kernel.*;
import ws.prova.reference.DefaultLogicFactory;
import ws.prova.reference.IProvaKnowledgeBase;
import ws.prova.*;
import ws.prova.calc.CalcPredicate;
import ws.prova.sql.SQLExtendedPredicate;

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

public class DefaultLogicFactorySupport {

    static private LogicFactory lfactory =
            DefaultLogicFactory.getDefaultFactory();
//	        new DefaultLogicFactory();
//			LogicFactory.getDefaultFactory();

    public DefaultLogicFactorySupport() {
    }

    /**
     * Create a constant term.
     *
     * @param obj  the object
     * @param type the type
     * @return the constant term created
     */
    static public ConstantTerm cons(Object obj, Class type) {
        return lfactory.createConstantTerm(obj, type);
    }

    /**
     * Create a complex term.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param function the function
     * @param objs     objects (will be interpreted as terms)
     * @return the complex term created
     */
    static public ComplexTerm cplx(Function function, Object[] objs) {
        Class[] structure = function.getStructure();

        if (structure.length != objs.length) {
            throw new IllegalArgumentException("Not the right number of terms for this function, the number is "
                    + objs.length + ", but must be " + structure.length);
        }

        Term[] terms = new Term[structure.length];

        for (int i = 0; i < structure.length; i++) {
            terms[i] = toTerm(objs[i], structure[i]);
        }

        return lfactory.createComplexTerm(function, terms);
    }

    /**
     * Create a complex term with one (sub)term.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param function the function
     * @param obj      an object
     * @return the complex term created
     */
    static public ComplexTerm cplx(Function function, Object obj) {
        Class[] structure = function.getStructure();

        if (structure.length != 1) {
            throw new IllegalArgumentException("Not the right number of terms for this function, the number is 1, but must be "
                    + structure.length);
        }

        Term[] terms = {toTerm(obj, structure[0])};

        return lfactory.createComplexTerm(function, terms);
    }

    /**
     * Create a complex term with two (sub)terms.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param function the function
     * @param obj1     an object
     * @param obj2     an object
     * @return the complex term created
     */
    static public ComplexTerm cplx(Function function, Object obj1, Object obj2) {
        Class[] structure = function.getStructure();

        if (structure.length != 2) {
            throw new IllegalArgumentException("Not the right number of terms for this function, the number is 2, but must be "
                    + structure.length);
        }

        Term[] terms = {toTerm(obj1, structure[0]),
                        toTerm(obj2, structure[1])};

        return lfactory.createComplexTerm(function, terms);
    }

    /**
     * Create a complex term with three (sub)terms.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param function the function
     * @param obj1     an object
     * @param obj2     an object
     * @param obj3     an object
     * @return the complex term created
     */
    static public ComplexTerm cplx(Function function, Object obj1, Object obj2,
                                   Object obj3) {
        Class[] structure = function.getStructure();

        if (structure.length != 3) {
            throw new IllegalArgumentException("Not the right number of terms for this function, the number is 3, but must be "
                    + structure.length);
        }

        Term[] terms = {toTerm(obj1, structure[0]),
                        toTerm(obj2, structure[1]),
                        toTerm(obj3, structure[2])};

        return lfactory.createComplexTerm(function, terms);
    }

    /**
     * Create a complex term with four (sub)terms.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param function the function
     * @param obj1     an object
     * @param obj2     an object
     * @param obj3     an object
     * @param obj4     an object
     * @return the complex term created
     */
    static public ComplexTerm cplx(Function function, Object obj1, Object obj2,
                                   Object obj3, Object obj4) {
        Class[] structure = function.getStructure();

        if (structure.length != 4) {
            throw new IllegalArgumentException("Not the right number of terms for this function, the number is 4, but must be "
                    + structure.length);
        }

        Term[] terms = {toTerm(obj1, structure[0]),
                        toTerm(obj2, structure[1]),
                        toTerm(obj3, structure[2]),
                        toTerm(obj4, structure[3])};

        return lfactory.createComplexTerm(function, terms);
    }

    /**
     * Create a fact.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param objs      objects (will be interpreted as terms)
     * @return the fact created
     */
    static public Fact fact(Predicate predicate, Object[] objs) {
        Class[] structure = predicate.getStructure();

        if (structure.length != objs.length) {
            throw new IllegalArgumentException("Not the right number of terms for this predicate, the number is "
                    + objs.length + ", but must be " + structure.length);
        }

        Term[] terms = new Term[structure.length];

        for (int i = 0; i < structure.length; i++) {
            terms[i] = toTerm(objs[i], structure[i]);
        }

        return lfactory.createFact(predicate, terms);
    }

    /**
     * Create a fact with one term.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param obj       an object
     * @return the fact created
     */
    static public Fact fact(Predicate predicate, Object obj) {
        Class[] structure = predicate.getStructure();

        if (structure.length != 1) {
            throw new IllegalArgumentException("Not the right number of terms for this predicate, the number is 1, but must be "
                    + structure.length);
        }

        Term[] terms = {toTerm(obj, structure[0])};

        return lfactory.createFact(predicate, terms);
    }

    /**
     * Create a fact with two terms.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param obj1      an object
     * @param obj2      an object
     * @return the fact created
     */
    static public Fact fact(Predicate predicate, Object obj1, Object obj2) {
        Class[] structure = predicate.getStructure();

        if (structure.length != 2) {
            throw new IllegalArgumentException("Not the right number of terms for this predicate, the number is 2, but must be "
                    + structure.length);
        }

        Term[] terms = {toTerm(obj1, structure[0]),
                        toTerm(obj2, structure[1])};

        return lfactory.createFact(predicate, terms);
    }

    /**
     * Create a fact with three terms.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param obj1      an object
     * @param obj2      an object
     * @param obj3      an object
     * @return the fact created
     */
    static public Fact fact(Predicate predicate, Object obj1, Object obj2, Object obj3) {
        Class[] structure = predicate.getStructure();

        if (structure.length != 3) {
            throw new IllegalArgumentException("Not the right number of terms for this predicate, the number is 3, but must be "
                    + structure.length);
        }

        Term[] terms = {toTerm(obj1, structure[0]),
                        toTerm(obj2, structure[1]),
                        toTerm(obj3, structure[2])};

        return lfactory.createFact(predicate, terms);
    }

    /**
     * Create a fact with four terms.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param obj1      an object
     * @param obj2      an object
     * @param obj3      an object
     * @param obj4      an object
     * @return the fact created
     */
    static public Fact fact(Predicate predicate, Object obj1, Object obj2, Object obj3, Object obj4) {
        Class[] structure = predicate.getStructure();

        if (structure.length != 4) {
            throw new IllegalArgumentException("Not the right number of terms for this predicate, the number is 4, but must be "
                    + structure.length);
        }

        Term[] terms = {toTerm(obj1, structure[0]),
                        toTerm(obj2, structure[1]),
                        toTerm(obj3, structure[2]),
                        toTerm(obj4, structure[3])};

        return lfactory.createFact(predicate, terms);
    }

    /**
     * Create a fact with five terms.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param obj1      an object
     * @param obj2      an object
     * @param obj3      an object
     * @param obj4      an object
     * @param obj5      an object
     * @return the fact created
     */
    static public Fact fact(Predicate predicate, Object obj1, Object obj2, Object obj3, Object obj4, Object obj5) {
        Class[] structure = predicate.getStructure();

        if (structure.length != 5) {
            throw new IllegalArgumentException("Not the right number of terms for this predicate, the number is 5, but must be "
                    + structure.length);
        }

        Term[] terms = {toTerm(obj1, structure[0]),
                        toTerm(obj2, structure[1]),
                        toTerm(obj3, structure[2]),
                        toTerm(obj4, structure[3]),
                        toTerm(obj5, structure[4])};

        return lfactory.createFact(predicate, terms);
    }

    /**
     * Create a prerequisite.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param objs      objects (will be interpreted as terms)
     * @return the prerequisite created
     */
    static public Prerequisite prereq(Predicate predicate, Object[] objs) {

        return prereq(predicate, objs, false);
    }

    /**
     * Create a prerequisite with one term.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param obj       an object
     * @return the prerequisite created
     */
    static public Prerequisite prereq(Predicate predicate, Object obj) {

        return prereq(predicate, obj, false);
    }

    /**
     * Create a prerequisite with two terms.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param obj1      an object
     * @param obj2      an object
     * @return the prerequisite created
     */
    static public Prerequisite prereq(Predicate predicate, Object obj1, Object obj2) {

        return prereq(predicate, obj1, obj2, false);
    }

    /**
     * Create a prerequisite with three terms.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param obj1      an object
     * @param obj2      an object
     * @param obj3      an object
     * @return the prerequisite created
     */
    static public Prerequisite prereq(Predicate predicate, Object obj1, Object obj2, Object obj3) {

        return prereq(predicate, obj1, obj2, obj3, false);
    }

    /**
     * Create a prerequisite with four terms.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param obj1      an object
     * @param obj2      an object
     * @param obj3      an object
     * @param obj4      an object
     * @return the prerequisite created
     */
    static public Prerequisite prereq(Predicate predicate, Object obj1, Object obj2, Object obj3, Object obj4) {

        return prereq(predicate, obj1, obj2, obj3, obj4, false);
    }

    /**
     * Create a prerequisite with five terms.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param obj1      an object
     * @param obj2      an object
     * @param obj3      an object
     * @param obj4      an object
     * @param obj5      an object
     * @return the prerequisite created
     */
    static public Prerequisite prereq(Predicate predicate, Object obj1, Object obj2, Object obj3, Object obj4, Object obj5) {

        return prereq(predicate, obj1, obj2, obj3, obj4, obj5, false);
    }


///

    /**
     * Create a prerequisite.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param objs      objects (will be interpreted as terms)
     * @param negatedAF whether the prerequisite is negated (using negation as failure)
     * @return the prerequisite created
     */
    static public Prerequisite prereq(Predicate predicate, Object[] objs, boolean negatedAF) {
        Class[] structure = predicate.getStructure();

        if (structure.length != objs.length) {
            throw new IllegalArgumentException("Not the right number of terms for this predicate, the number is "
                    + objs.length + ", but must be " + structure.length);
        }

        Term[] terms = new Term[structure.length];

        for (int i = 0; i < structure.length; i++) {
            terms[i] = toTerm(objs[i], structure[i]);
        }

        return lfactory.createPrerequisite(predicate, terms, negatedAF);
    }

    /**
     * Create a prerequisite with one term.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param obj       an object
     * @param negatedAF whether the prerequisite is negated (using negation as failure)
     * @return the prerequisite created
     */
    static public Prerequisite prereq(Predicate predicate, Object obj, boolean negatedAF) {
        Class[] structure = predicate.getStructure();

        if (structure.length != 1) {
            throw new IllegalArgumentException("Not the right number of terms for this predicate, the number is 1, but must be "
                    + structure.length);
        }

        Term[] terms = {toTerm(obj, structure[0])};

        return lfactory.createPrerequisite(predicate, terms, negatedAF);
    }

    /**
     * Create a prerequisite with two terms.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param obj1      an object
     * @param obj2      an object
     * @param negatedAF whether the prerequisite is negated (using negation as failure)
     * @return the prerequisite created
     */
    static public Prerequisite prereq(Predicate predicate, Object obj1, Object obj2, boolean negatedAF) {
        Class[] structure = predicate.getStructure();

        if (structure.length != 2) {
            throw new IllegalArgumentException("Not the right number of terms for this predicate, the number is 2, but must be "
                    + structure.length);
        }

        Term[] terms = {toTerm(obj1, structure[0]),
                        toTerm(obj2, structure[1])};

        return lfactory.createPrerequisite(predicate, terms, negatedAF);
    }

    /**
     * Create a prerequisite with three terms.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param obj1      an object
     * @param obj2      an object
     * @param obj3      an object
     * @param negatedAF whether the prerequisite is negated (using negation as failure)
     * @return the prerequisite created
     */
    static public Prerequisite prereq(Predicate predicate, Object obj1, Object obj2, Object obj3, boolean negatedAF) {
        Class[] structure = predicate.getStructure();

        if (structure.length != 3) {
            throw new IllegalArgumentException("Not the right number of terms for this predicate, the number is 3, but must be "
                    + structure.length);
        }

        Term[] terms = {toTerm(obj1, structure[0]),
                        toTerm(obj2, structure[1]),
                        toTerm(obj3, structure[2])};

        return lfactory.createPrerequisite(predicate, terms, negatedAF);
    }

    /**
     * Create a prerequisite with four terms.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param obj1      an object
     * @param obj2      an object
     * @param obj3      an object
     * @param obj4      an object
     * @param negatedAF whether the prerequisite is negated (using negation as failure)
     * @return the prerequisite created
     */
    static public Prerequisite prereq(Predicate predicate, Object obj1, Object obj2, Object obj3, Object obj4, boolean negatedAF) {
        Class[] structure = predicate.getStructure();

        if (structure.length != 4) {
            throw new IllegalArgumentException("Not the right number of terms for this predicate, the number is 4, but must be "
                    + structure.length);
        }

        Term[] terms = {toTerm(obj1, structure[0]),
                        toTerm(obj2, structure[1]),
                        toTerm(obj3, structure[2]),
                        toTerm(obj4, structure[3])};

        return lfactory.createPrerequisite(predicate, terms, negatedAF);
    }

    /**
     * Create a prerequisite with five terms.
     * See <code>toTerm</code> how the object is converted to a term.
     *
     * @param predicate the predicate
     * @param obj1      an object
     * @param obj2      an object
     * @param obj3      an object
     * @param obj4      an object
     * @param obj5      an object
     * @param negatedAF whether the prerequisite is negated (using negation as failure)
     * @return the prerequisite created
     */
    static public Prerequisite prereq(Predicate predicate, Object obj1, Object obj2, Object obj3, Object obj4, Object obj5, boolean negatedAF) {
        Class[] structure = predicate.getStructure();

        if (structure.length != 5) {
            throw new IllegalArgumentException("Not the right number of terms for this predicate, the number is 5, but must be "
                    + structure.length);
        }

        Term[] terms = {toTerm(obj1, structure[0]),
                        toTerm(obj2, structure[1]),
                        toTerm(obj3, structure[2]),
                        toTerm(obj4, structure[3]),
                        toTerm(obj5, structure[4])};

        return lfactory.createPrerequisite(predicate, terms, negatedAF);
    }

    /**
     * Create a rule with two prerequisites.
     * The prerequisites are connected by OR.
     *
     * @param prerequisite1 a prerequisite
     * @param prerequisite2 a prerequisite
     * @param conclusion    the concusion of the rule
     * @return the rule created
     * @deprecated use Prerequisite instead of Fact to build rules
     */
    static public Rule orRule(Fact prerequisite1, Fact prerequisite2, Fact conclusion) {
        Vector body = new Vector();
        body.add(fact2prereq(prerequisite1));
        body.add(fact2prereq(prerequisite2));
        return lfactory.createRule(body, conclusion, true);
    }

    /**
     * Create a rule with three prerequisites.
     * The prerequisites are connected by OR.
     *
     * @param prerequisite1 a prerequisite
     * @param prerequisite2 a prerequisite
     * @param prerequisite3 a prerequisite
     * @param conclusion    the concusion of the rule
     * @return the rule created
     * @deprecated use Prerequisite instead of Fact to build rules
     */
    static public Rule orRule(Fact prerequisite1, Fact prerequisite2, Fact prerequisite3, Fact conclusion) {
        Vector body = new Vector();
        body.add(fact2prereq(prerequisite1));
        body.add(fact2prereq(prerequisite2));
        body.add(fact2prereq(prerequisite3));
        return lfactory.createRule(body, conclusion, true);
    }

    /**
     * Create a rule with four prerequisites.
     * The prerequisites are connected by OR.
     *
     * @param prerequisite1 a prerequisite
     * @param prerequisite2 a prerequisite
     * @param prerequisite3 a prerequisite
     * @param prerequisite4 a prerequisite
     * @param conclusion    the concusion of the rule
     * @return the rule created
     * @deprecated use Prerequisite instead of Fact to build rules
     */
    static public Rule orRule(Fact prerequisite1, Fact prerequisite2, Fact prerequisite3, Fact prerequisite4, Fact conclusion) {
        Vector body = new Vector();
        body.add(fact2prereq(prerequisite1));
        body.add(fact2prereq(prerequisite2));
        body.add(fact2prereq(prerequisite3));
        body.add(fact2prereq(prerequisite4));
        return lfactory.createRule(body, conclusion, true);
    }

    /**
     * Create a rule.
     *
     * @param body       the prerequisites of the rule
     * @param conclusion the concusion of the rule
     * @return the rule created
     */
    static public Rule rule(List body, Fact conclusion) {
        return lfactory.createRule(body, conclusion);
    }

    /**
     * Create a rule and mark the head and rhs literals with their source
     *
     * @param body       the prerequisites of the rule
     * @param conclusion the concusion of the rule
     * @param src        origin of the rule (e.g., a file name)
     * @return the rule created
     */
    static public Rule rule(List body, Fact conclusion, String src) {
        Rule r = lfactory.createRule(body, conclusion);
        r.getHead().setProperty("src", src);
        List rhs = r.getBody();
        for (int i = 0; i < rhs.size(); i++) {
            Fact f = (Fact) rhs.get(i);
            f.setProperty("src", src);
        }
        return r;
    }

   /**
     * Create a rule and mark the head and rhs literals with their source
     * 
     * bindl: the rule contains an oid
     *
     * @param body       the prerequisites of the rule
     * @param conclusion the concusion of the rule
     * @param src        origin of the rule (e.g., a file name)
     * @param oid		 id of the rule
     * @return the rule created
     */
    /*static public Rule rule(List body, Fact conclusion, String src, String oid) {
        Rule r = lfactory.createRule(body, conclusion);
        r.getHead().setProperty("src", src);
        List rhs = r.getBody();
        for (int i = 0; i < rhs.size(); i++) {
            Fact f = (Fact) rhs.get(i);
            f.setProperty("src", src);
        }
        r.setProperty("oid", oid);
        System.out.println("oid: "+r.getProperty("oid"));
        return r;
    }*/

    /**
     * Create a rule with no prerequisites.
     *
     * @param conclusion the concusion of the rule
     * @return the rule created
     */
    static public Rule rule(Fact conclusion) {
        Vector body = new Vector();
        return lfactory.createRule(body, conclusion);
    }

    /**
     * Create a rule with one prerequisite.
     *
     * @param prerequisite a prerequisite
     * @param conclusion   the concusion of the rule
     * @return the rule created
     * @deprecated use Prerequisite instead of Fact to build rules
     */
    static public Rule rule(Fact prerequisite, Fact conclusion) {
        Vector body = new Vector();
        body.add(fact2prereq(prerequisite));
        return lfactory.createRule(body, conclusion);
    }

    /**
     * Create a rule with two prerequisites.
     *
     * @param prerequisite1 a prerequisite
     * @param prerequisite2 a prerequisite
     * @param conclusion    the concusion of the rule
     * @return the rule created
     * @deprecated use Prerequisite instead of Fact to build rules
     */
    static public Rule rule(Fact prerequisite1, Fact prerequisite2, Fact conclusion) {
        Vector body = new Vector();
        body.add(fact2prereq(prerequisite1));
        body.add(fact2prereq(prerequisite2));
        return lfactory.createRule(body, conclusion);
    }

    /**
     * Create a rule with three prerequisites.
     *
     * @param prerequisite1 a prerequisite
     * @param prerequisite2 a prerequisite
     * @param prerequisite3 a prerequisite
     * @param conclusion    the concusion of the rule
     * @return the rule created
     * @deprecated use Prerequisite instead of Fact to build rules
     */
    static public Rule rule(Fact prerequisite1, Fact prerequisite2, Fact prerequisite3, Fact conclusion) {
        Vector body = new Vector();
        body.add(fact2prereq(prerequisite1));
        body.add(fact2prereq(prerequisite2));
        body.add(fact2prereq(prerequisite3));
        return lfactory.createRule(body, conclusion);
    }

    /**
     * Create a rule with four prerequisites.
     *
     * @param prerequisite1 a prerequisite
     * @param prerequisite2 a prerequisite
     * @param prerequisite3 a prerequisite
     * @param prerequisite4 a prerequisite
     * @param conclusion    the concusion of the rule
     * @return the rule created
     * @deprecated use Prerequisite instead of Fact to build rules
     */
    static public Rule rule(Fact prerequisite1, Fact prerequisite2, Fact prerequisite3, Fact prerequisite4, Fact conclusion) {
        Vector body = new Vector();
        body.add(fact2prereq(prerequisite1));
        body.add(fact2prereq(prerequisite2));
        body.add(fact2prereq(prerequisite3));
        body.add(fact2prereq(prerequisite4));
        return lfactory.createRule(body, conclusion);
    }


    /**
     * Create a rule with two prerequisites.
     * The prerequisites are connected by OR.
     *
     * @param prerequisite1 a prerequisite
     * @param prerequisite2 a prerequisite
     * @param conclusion    the concusion of the rule
     * @return the rule created
     */
    static public Rule orRule(Prerequisite prerequisite1, Prerequisite prerequisite2, Fact conclusion) {
        Vector body = new Vector();
        body.add(prerequisite1);
        body.add(prerequisite2);
        return lfactory.createRule(body, conclusion, true);
    }

    /**
     * Create a rule with three prerequisites.
     * The prerequisites are connected by OR.
     *
     * @param prerequisite1 a prerequisite
     * @param prerequisite2 a prerequisite
     * @param prerequisite3 a prerequisite
     * @param conclusion    the concusion of the rule
     * @return the rule created
     */
    static public Rule orRule(Prerequisite prerequisite1, Prerequisite prerequisite2, Prerequisite prerequisite3, Fact conclusion) {
        Vector body = new Vector();
        body.add(prerequisite1);
        body.add(prerequisite2);
        body.add(prerequisite3);
        return lfactory.createRule(body, conclusion, true);
    }

    /**
     * Create a rule with four prerequisites.
     * The prerequisites are connected by OR.
     *
     * @param prerequisite1 a prerequisite
     * @param prerequisite2 a prerequisite
     * @param prerequisite3 a prerequisite
     * @param prerequisite4 a prerequisite
     * @param conclusion    the concusion of the rule
     * @return the rule created
     */
    static public Rule orRule(Prerequisite prerequisite1, Prerequisite prerequisite2, Prerequisite prerequisite3, Prerequisite prerequisite4, Fact conclusion) {
        Vector body = new Vector();
        body.add(prerequisite1);
        body.add(prerequisite2);
        body.add(prerequisite3);
        body.add(prerequisite4);
        return lfactory.createRule(body, conclusion, true);
    }

    /**
     * Create a rule with one prerequisite.
     *
     * @param prerequisite a prerequisite
     * @param conclusion   the concusion of the rule
     * @return the rule created
     */
    static public Rule rule(Prerequisite prerequisite, Fact conclusion) {
        Vector body = new Vector();
        body.add(prerequisite);
        return lfactory.createRule(body, conclusion);
    }

    /**
     * Create a rule with two prerequisites.
     *
     * @param prerequisite1 a prerequisite
     * @param prerequisite2 a prerequisite
     * @param conclusion    the concusion of the rule
     * @return the rule created
     */
    static public Rule rule(Prerequisite prerequisite1, Prerequisite prerequisite2, Fact conclusion) {
        Vector body = new Vector();
        body.add(prerequisite1);
        body.add(prerequisite2);
        return lfactory.createRule(body, conclusion);
    }

    /**
     * Create a rule with three prerequisites.
     *
     * @param prerequisite1 a prerequisite
     * @param prerequisite2 a prerequisite
     * @param prerequisite3 a prerequisite
     * @param conclusion    the concusion of the rule
     * @return the rule created
     */
    static public Rule rule(Prerequisite prerequisite1, Prerequisite prerequisite2, Prerequisite prerequisite3, Fact conclusion) {
        Vector body = new Vector();
        body.add(prerequisite1);
        body.add(prerequisite2);
        body.add(prerequisite3);
        return lfactory.createRule(body, conclusion);
    }

    /**
     * Create a rule with four prerequisites.
     *
     * @param prerequisite1 a prerequisite
     * @param prerequisite2 a prerequisite
     * @param prerequisite3 a prerequisite
     * @param prerequisite4 a prerequisite
     * @param conclusion    the concusion of the rule
     * @return the rule created
     */
    static public Rule rule(Prerequisite prerequisite1, Prerequisite prerequisite2, Prerequisite prerequisite3, Prerequisite prerequisite4, Fact conclusion) {
        Vector body = new Vector();
        body.add(prerequisite1);
        body.add(prerequisite2);
        body.add(prerequisite3);
        body.add(prerequisite4);
        return lfactory.createRule(body, conclusion);
    }


    /**
     * Convenient method to interprete objects as terms.
     * The following rules apply:
     * <ol>
     * <li> if the object is a term, keep it as it is
     * <li> if the object is an instance of clazz, create a constant term wrapping the object
     * <li> if the object is a string (an the previous does not apply), create a variable using the object as a name
     * <li> otherwise throw an illegal argument exception;
     * </ol>
     *
     * @param obj   the object to be interpreted as a term
     * @param clazz the type of the term
     * @return a term
     */
    static private Term toTerm(Object obj, Class clazz) {
        if (obj == null) {
            throw new IllegalArgumentException("Cannot build term from null");
        }

        if (obj instanceof Term) {
            return (Term) obj;
        }
        // remark: this was a bug in 1.6 : if (clazz==obj.getClass())
        if (clazz.isAssignableFrom(obj.getClass())) {
            return lfactory.createConstantTerm(obj);
        }

        if (obj instanceof String) {
            return lfactory.createVariableTerm((String) obj, clazz);
        }

        throw new IllegalArgumentException("Cannot build term from " + obj);
    }

    /**
     * Convenient method to create a variable.
     *
     * @param name  a var name
     * @param clazz a type
     * @return a term
     */
    static public Term variable(String name, Class clazz) {
        return lfactory.createVariableTerm(name, clazz);
    }

    /**
     * Convenient method to create a string type variable.
     *
     * @param name a var name
     * @return a term
     */
    static public Term variable(String name) {
        return variable(name, String.class);
    }

    /**
     * Create a query with one fact.
     *
     * @param fact a fact
     * @param name the name of the query
     * @return the query created
     */
    static public Query query(Fact fact, String name) {
        Fact[] facts = {fact};
        return query(facts, name);
    }

    /**
     * Create a query with two facts.
     *
     * @param fact1 a fact
     * @param fact2 a fact
     * @param name  the name of the query
     * @return the query created
     */
    static public Query query(Fact fact1, Fact fact2, String name) {
        Fact[] facts = {fact1, fact2};
        return query(facts, name);
    }

    /**
     * Create a query with three facts.
     *
     * @param fact1 a fact
     * @param fact2 a fact
     * @param fact3 a fact
     * @param name  the name of the query
     * @return the query created
     */
    static public Query query(Fact fact1, Fact fact2, Fact fact3, String name) {
        Fact[] facts = {fact1, fact2, fact3};
        return query(facts, name);
    }

    /**
     * Create a query with N facts.
     *
     * @param facts array of facts
     * @param name  the name of the query
     * @return the query created
     */
    static public Query query(Fact[] facts, String name) {
        return lfactory.createQuery(facts, name);
    }

    /**
     * Convert a fact to a prerequisite.
     *
     * @param fact a fact
     * @return a prerequisite
     */
    static public Prerequisite fact2prereq(Fact fact) {
        Predicate p = fact.getPredicate();
        Term[] terms = fact.getTerms();
        return prereq(p, terms);
    }

    /**
     * Create a prerequiste using the cut predicate.
     *
     * @return a prerequisite
     */
    static public Prerequisite cut() {
        return lfactory.createCut();
    }

    final static SimplePredicate derive = HelperPredicates.derive();
    final SimplePredicate holds = HelperPredicates.holds();
    final SimplePredicate demo = HelperPredicates.demo();
    final Predicate diff = HelperPredicates.diff();
    final static Predicate adapt = HelperPredicates.adapt();
    final Predicate accumulate = HelperPredicates.accumulate();
    final Predicate accumulate2 = HelperPredicates.accumulate2();
    final static Predicate acc = HelperPredicates.acc();
    final Predicate acc2 = HelperPredicates.acc2();
    final static Predicate invoke = HelperPredicates.invoke();
    final public static SimplePredicate fail = HelperPredicates.fail();
    final public static SimplePredicate restore_exhandler = HelperPredicates.restore_exhandler();
    final SimplePredicate consult = HelperPredicates.consult();
    final SimplePredicate temporal_rule = HelperPredicates.temporal_rule();
    final SimplePredicate temporal_rule_eoc = HelperPredicates.temporal_rule_eoc();
    final SimplePredicate temporal_rule_build = HelperPredicates.temporal_rule_build();
    final SimplePredicate append = HelperPredicates.append();
    public static Function flist = HelperPredicates.list();
    final SimplePredicate derivation = HelperPredicates.derivation();
    final SimplePredicate conversation = HelperPredicates.conversation();
    final SimplePredicate conv_id = HelperPredicates.conv_id();
    final SimplePredicate actions = HelperPredicates.actions();
    final SimplePredicate actions2 = HelperPredicates.actions2();
    final SimplePredicate temporal_rule_remove = HelperPredicates.temporal_rule_remove();
    final static SimplePredicate state = HelperPredicates.state();
    final SimplePredicate solve_first = HelperPredicates.solve_first();
    final SimplePredicate solve = HelperPredicates.solve();
    final SimplePredicate eval = HelperPredicates.eval();

    /**
     * Create the standard facts and rules constituting
     * the Prova built-in rule base.
     */
    public void initStandardKB( reagent prova, Calc calc, IProvaKnowledgeBase kb, String agent ) {
        SQLExtendedPredicate sql = prova.sql;
        CalcPredicate bcalc = prova.bcalc;
		 Messenger messenger = prova.getMessenger();

		  //		testListTranslation();

//		populate_conversations();

        Rule rule;

        // diff(rlist,rlist,rlist)
        rule = rule(cut(),
                fact(diff, RListUtils.rlist("X"), RListUtils.rlist(RList.class, "[X|Xs]"), RListUtils.rlist("Xs")));
        kb.add(rule);
        rule = rule(prereq(diff, RListUtils.rlist("X"), RListUtils.rlist("Xs"), RListUtils.rlist("Ys")),
                fact(diff, RListUtils.rlist("X"), RListUtils.rlist(RList.class, "[Y|Xs]"),
                        RListUtils.rlist(RList.class, "[Y|Ys]")));
        kb.add(rule);

        // adapt(rlist,rlist)
        rule = rule(cut(),
                fact(adapt, RListUtils.emptyRListTerm, RListUtils.emptyRListTerm));
        kb.add(rule);
        rule = rule(prereq(diff, RListUtils.rlist("X"), RListUtils.rlist("Ys"), RListUtils.rlist("Zs")),
                cut(),
                prereq(adapt, RListUtils.rlist("Xs"), RListUtils.rlist("Zs")),
                fact(adapt, RListUtils.rlist(RList.class, "[X|Xs]"), RListUtils.rlist("Ys")));
        kb.add(rule);
        rule = rule(fact(adapt, RListUtils.emptyRListTerm, RListUtils.rlist("_")));
        kb.add(rule);

        // findall - initialise accumulation process
        rule = rule(
                prereq(kb.pcalc(),
                        RListUtils.rlist("[%0,subtype,Acc,%1]",
                                new Object[]{calc,List.class})),
                cut(),
                // Create an Accumulator
//				prereq(kb.pcalc(),rlist("[%0,create,Accumulator.Acc]",new Object[]{calc})),
                prereq(kb.pcalc(),
                        RListUtils.rlist("[%0,construct,\"ws.prova.Accumulator\",Acc,[]]",
                                new Object[]{calc})),
                // and use it to accumulate the results of Goal
                // BUT fail if there are no results
//				prereq(acc2,rlist("[Accumulator.Acc,[G|Gs],[P|Ps]]")),
//				fact(acc,rlist("[Accumulator.Acc,[G|Gs],[P|Ps]]"))
                prereq(acc2, RListUtils.rlist("[Acc,[G|Gs],WhatToAccumulate]")),
                fact(acc, RListUtils.rlist("[WhatToAccumulate,[G|Gs],Acc]")));
        kb.add(rule);

        rule = rule(cut(),
                // Create an Accumulator
                prereq(kb.pcalc(),
                        RListUtils.rlist("[%0,construct,\"ws.prova.Accumulator\",Accumulator.Acc,[]]",
                                new Object[]{calc})),
                // and use it to accumulate the results of Goal
                // BUT fail if there are no results
                prereq(acc2, RListUtils.rlist("[Accumulator.Acc,[G|Gs],WhatToAccumulate]")),
//		      prereq(HelperPredicates.fcalc(), RListUtils.rlist("[Accumulator.Acc,toList,List]")),
//                prereq(kb.pcalc(), RListUtils.rlist("[Accumulator.Acc,toList,List]")),
                prereq(HelperPredicates.sfcalc(), RListUtils.rlist("[ws.prova.RListUtils,list2RList,List,Accumulator.Acc]")),
                fact(acc, RListUtils.rlist("[WhatToAccumulate,[G|Gs],List]")));
//		prereq(HelperPredicates.fcalc(), RListUtils.rlist("[Accumulator.Acc,toList,ws.prova.RList.List]")),
//		fact(acc, RListUtils.rlist("[WhatToAccumulate,[G|Gs],ws.prova.RList.List]")));
        kb.add(rule);

        // acc2 - accumulate Goal results in Pattern
        rule = rule(// Find a new Goal result
                prereq(derive, variable("G", Object.class), RListUtils.rlist("[G|Gs]")),
//                prereq(demo, RListUtils.rlist("[[G|Gs]]")),
                prereq(kb.pcalc(), RListUtils.rlist("[Accumulator.Acc,accumulate,WhatToAccumulate]")),
                fact(acc2, RListUtils.rlist("[Accumulator.Acc,[G|Gs],WhatToAccumulate]")));
        kb.add(rule);
        rule = rule(// Just make sure the predicate always succeeds (possibly with an empty Accumulator)
                fact(acc2, RListUtils.rlist("[Accumulator.Acc,[G|Gs],WhatToAccumulate]")));
        kb.add(rule);

        // accumulate - initialise accumulation process
        rule = rule(cut(),
                // Create an Accumulator
                prereq(kb.pcalc(),
                        RListUtils.rlist("[%0,create,Accumulator.Acc]", new Object[]{calc})),
                // and use it to accumulate the results of Goal
                // BUT fail if there are no results
                prereq(accumulate2, RListUtils.rlist("[Accumulator.Acc|Goal]")),
                fact(accumulate, RListUtils.rlist("[Accumulator.Acc|Goal]")));
        kb.add(rule);

        // accumulate2 - accumulate Goal results
        rule = rule(// Find a new Goal result
                prereq(demo, RListUtils.rlist("[RList.Goal]")),
                // and accumulate it in Accumulator.Acc
                // AND fail in order to proceed to other solutions
                prereq(kb.pcalc(), RListUtils.rlist("[Accumulator.Acc,accumulate,RList.Goal]")),
                fact(accumulate2, RListUtils.rlist("[Accumulator.Acc|Goal]")));
        kb.add(rule);
        rule = rule(// Just make sure the predicate always succeeds (possibly with an empty Accumulator)
                fact(accumulate2, RListUtils.rlist("[Accumulator.Acc|Goal]")));
        kb.add(rule);

        // identity iam predicate
        kb.add(fact(kb.poly("iam", derive), "iam",
                RListUtils.rlist("[iam,%0]", new Object[]{agent})));
        // equals predicate
//		kb.add(fact(state, RListUtils.rlist("[spec,equals,X,X]")));

        // demo - a recursive proof meta-programming
        // . 'cut' is very useful in the rules below]
        // @todo many rules can be made polymorphic
        rule = rule(cut(),
                fact(demo, RListUtils.emptyRListTerm));
        kb.add(rule);
        // One table database wrapper rule
        rule = rule(cut(),
                prereq(sql, RListUtils.rlist("X")),
                prereq(demo, RListUtils.rlist("Xs")),
                fact(demo, RListUtils.rlist("[[sql_select|X]|Xs]")));
        kb.add(rule);
        // calc predicate rule
        rule = rule(cut(),
                prereq(kb.pcalc(), RListUtils.rlist("X")),
                prereq(demo, RListUtils.rlist("Xs")),
                fact(demo, RListUtils.rlist("[[pcalc|X]|Xs]")));
        kb.add(rule);
        // static calc predicate rule
        rule = rule(cut(),
                prereq(HelperPredicates.scalc(), RListUtils.rlist("X")),
                prereq(demo, RListUtils.rlist("Xs")),
                fact(demo, RListUtils.rlist("[[scalc|X]|Xs]")));
        kb.add(rule);
        // fcalc predicate rule
        rule = rule(cut(),
                prereq(HelperPredicates.fcalc(), RListUtils.rlist("X")),
                prereq(demo, RListUtils.rlist("Xs")),
                fact(demo, RListUtils.rlist("[[fcalc|X]|Xs]")));
        kb.add(rule);
        // sfcalc predicate rule
        rule = rule(cut(),
                prereq(HelperPredicates.sfcalc(), RListUtils.rlist("X")),
                prereq(demo, RListUtils.rlist("Xs")),
                fact(demo, RListUtils.rlist("[[sfcalc|X]|Xs]")));
        kb.add(rule);
        // accumulator rule
        rule = rule(cut(),
                prereq(accumulate, RListUtils.rlist("[Accumulator.Acc|Goal]")),
                prereq(demo, RListUtils.rlist("Xs")),
                fact(demo, RListUtils.rlist("[[accumulate,Accumulator.Acc|Goal]|Xs]")));
        kb.add(rule);
        // acc rule for specified pattern
        rule = rule(cut(),
                prereq(acc, RListUtils.rlist("[[P|Ps],[G|Gs],Acc]")),
                prereq(demo, RListUtils.rlist("Xs")),
                fact(demo, RListUtils.rlist("[[findall,Acc,[G|Gs],[P|Ps]]|Xs]")));
        kb.add(rule);
        // acc rule for empty pattern: the goal becomes the accumulated pattern
        rule = rule(cut(),
                prereq(acc, RListUtils.rlist("[[G|Gs],[G|Gs],Acc]")),
                prereq(demo, RListUtils.rlist("Xs")),
                fact(demo, RListUtils.rlist("[[findall,Acc,[G|Gs]]|Xs]")));
        kb.add(rule);
        // . the first concept in the queue is a state fact
        rule = rule(cut(),
                prereq(state, RListUtils.rlist("[spec|X]")),
                prereq(demo, RListUtils.rlist("Xs")),
                fact(demo, RListUtils.rlist(RList.class, "[[spec|X]|Xs]")));
        kb.add(rule);
        rule = rule(cut(),
                prereq(state, RListUtils.rlist("[meta|X]")),
                prereq(demo, RListUtils.rlist("Xs")),
                fact(demo, RListUtils.rlist(RList.class, "[[meta|X]|Xs]")));
        kb.add(rule);
        // . adaptor rule
        rule = rule(cut(),
                prereq(adapt, RListUtils.rlist("X"), RListUtils.rlist("Y")),
                prereq(demo, RListUtils.rlist("Xs")),
                fact(demo, RListUtils.rlist(RList.class, "[[adapt,X,Y]|Xs]")));
        kb.add(rule);
        /**/
        // . the first concept in the queue is an append fact
//		try {
//			this.consultSync(
//			    "demo([append(R1,R2,R)|Xs]):-"+
//			        "!,"+
//			        "append(R1,R2,R),"+
//			        "demo(Xs).",new Object[]{});
//		} catch( Exception e ) {
//			e.printStackTrace();
//		}
        // . the first concept in the queue is an append fact
//		rule = rule(
//		        cut(),
//		        prereq(append, RListUtils.rlist("R1"), RListUtils.rlist("R2"), RListUtils.rlist("R")),
//		        prereq(demo, RListUtils.rlist("Xs")),
//		        fact(demo, RListUtils.rlist(RList.class, "[[append,R1,R2,R]|Xs]")));
//		kb.add(rule);
        /**/
        // . the first concept in the queue is a Java method call;
        // .   Objs are exec parameters: target object, target method, followed by its arguments
        rule = rule(cut(),
                prereq(invoke, calc, RListUtils.rlist("Objs")),
                prereq(demo, RListUtils.rlist("Xs")),
                fact(demo, RListUtils.rlist("[[exec|Objs]|Xs]")));
        kb.add(rule);
        // . the first concept in the queue is a negated state fact
        // .. Clause A
        rule = rule(prereq(demo, RListUtils.rlist("Ls")),
                cut(),
                // fail
                prereq(fail, new Object[0]),
//			prereq(kb.pcalc(), RListUtils.rlist("[%0,fail]", new Object[] {calc})),
//				prereq(state,rlist("[x]")),
                fact(demo, RListUtils.rlist("[[neg|Ls]|Xs]")));
        kb.add(rule);
        // .. Clause B
        rule = rule(cut(),
                prereq(demo, RListUtils.rlist("Xs")),
                fact(demo, RListUtils.rlist("[[neg|_]|Xs]")));
        kb.add(rule);
        // . using the derivation rules in Mandarax format
        rule = rule(// predicate 'derive' is polymorphic: the engine selects the appropriate facts based on 'P';
                // it is assumed that for each event, 'P' is the first list element in the event structure
                prereq(derive, variable("P", Object.class), RListUtils.rlist("[P|Ps]")),
                prereq(demo, RListUtils.rlist("Xs")),
                fact(demo, RListUtils.rlist("[[P|Ps]|Xs]")));
        kb.add(rule);
        // . the first concept in the queue is replaced by the rhs of some derivation rule
        rule = rule(// predicate 'derivation' is polymorphic: the engine selects the appropriate facts based on 'P';
                // it is assumed that for each event, 'P' is the first list element in the event structure
                prereq(derivation, variable("P", Object.class), RListUtils.rlist("[[P|Ps]]"),
                        RListUtils.rlist("State"), RListUtils.rlist("Cond")),
                prereq(holds, RListUtils.rlist("State")),
                prereq(demo, RListUtils.rlist("Cond")),
                prereq(demo, RListUtils.rlist("Xs")),
                fact(demo, RListUtils.rlist("[[P|Ps]|Xs]")));
        kb.add(rule);

        try {
            prova.consultSync(// . the first concept in the queue is an append fact
//			    "demo([append(R1,R2,R)|Xs]):-"+
//			        "!,"+
//			        "append(R1,R2,R),"+
//			        "demo(Xs)."+
                    "true():-!." +
//					"findall(G,L):-findall(G,G,L)." +
                    "sendMsg(X|Xs):-sendMsg(X|Xs)." +
                    "assert([X|Xs]):-assert([X|Xs])." +
                    "print(X):-print(X)." +
                    "println(X):-println(X)." +
//			        "consult(X):-consult(X)." +
                    "retract(X):-retract(X)." +
                    "retractall(X):-retractall(X)." +
                    "unconsult(X):-retractall(X)." +
                    "reconsult(X):-retractall(X),consult(X)." +
                    "equals(X,X):-!." +
                    "concat(X,Y):-concat(X,Y)." +
                    "type(X,Y):-type(X,Y)." +
                    "subtype(X,Y):-subtype(X,Y)." +
                    "bound(X):-bound(X)." +
                    "free(X):-free(X)." +
                    "element(X,L):-element(X,L)." +
                    "element(I,X,L):-element(I,X,L)." +
                    "consult(In):-" +
                    "_0.consult(In)."
//			        , "", new Object[]{calc});
                    +

//			this.consultSync(
//				// append
//		        "append([],L,L)."+
//		        "append([X1|L1],L2,[X1|L3]):-"+
//			        "append(L1,L2,L3).", new Object[]{});

//			this.consultSync(

                    //			    "demo([append(R1,R2,R)|Xs]):-"+
//			        "!,"+
//			        "append(R1,R2,R),"+
//			        "demo(Xs)."+
//			    "equals(X,X)."+
//		        "consult(In):-"+
//			        "_0.consult(In)."+
//				// append
//		        "append([],L,L)."+
//		        "append([X1|L1],L2,[X1|L3]):-"+
//			        "append(L1,L2,L3)."+
                    // build temporal rule
                    "temporal_rule_build([[Command,[id,TID],Agent,Perf,[X2|X2s]|Cond]|Actions]," +
                    "[[Command,[id,TID],Agent,Perf,[X2|X2s]]|Actions],Cond).", "", new Object[]{calc});
//			this.consultSync(
//			        "actions2([TID,Agent,Perf|Msg],Protocol,State,Cond):-"+
//			        "  _1.store_temptid(-1),"+
//			        "  conversation()", new Object[]{calc,this,new Integer(-1)});
//		} catch (Exception e) {
//			e.printStackTrace();
//		}
        // actions
        rule = rule(// Initialise temporal ruleid to -1 (if it is processed with a temporal rule)
                prereq(kb.pcalc(), RListUtils.rlist("[%0,store_temptid,-1]", new Object[]{this})),
                // predicate 'conversation' is polymorphic: the engine selects the appropriate facts based on 'Perf';
                // it is assumed that for each event, 'Perf' is the second list element in the event structure
                prereq(conversation, cons("rcvMsg", Object.class),
//		        prereq(conversation, variable("Perf", Object.class),
                        RListUtils.rlist("[TID,Protocol,Agent,Perf|Msg]"), RListUtils.emptyRListTerm,
                        RListUtils.rlist("State"), RListUtils.rlist("Cond")),
                prereq(demo, RListUtils.rlist("Cond")),
                prereq(holds, RListUtils.rlist("State")),
                fact(actions2, RListUtils.rlist("[TID,Agent,Perf|Msg]"),
                        variable("Protocol", Object.class), RListUtils.rlist("State"), RListUtils.rlist("Cond")));
        kb.add(rule);

        prova.consultSync(
                // . actions based on self-destructing temporal rules
                // . They should take precedence over rules corresponding to conversations
                // .     due to the requirement that the inform action list should be unique
                "'@actions'(TID,[[id,TID],Agent,end_of_transmission|Extra],Protocol,[],[]) :- "+
                "   _1.store_tid(TID),"+
                "   '@temporal_rule_eoc'(RuleID,TID,[Command,[id,TID],Protocol,Agent,Perf|Extra]),"+
//                "   bound(TID1),"+
//                "   equals(TID,TID1),"+
                "   _0.remove_temporal_rule(RuleID,TID,[[id,TID],Agent,end_of_transmission|Extra])."+
                ""
+                "'@actions'(TID,[[id,TID],Agent,Perf|Extra],Protocol,[],[]) :- "+
                "   _1.store_tid(TID),"+
                "   '@temporal_rule'(RuleID,TID,[Command,[id,TID],Protocol,Agent,Perf|Extra]),"+
                "   fail()."
+               "'@actions'(TID,[[id,TID],Agent,Perf|Extra],Protocol,[],[]) :- "+
//                "   _1.store_tid(TID),"+
                "   RuleID=_2.get_temptid(),"+
                "   '@temporal_rule_remove'([RuleID,TID,Protocol,Agent,Perf|Extra])."
+               "'@temporal_rule_remove'([RuleID,TID,Protocol,Agent,Perf|Extra]) :-"+
				"   '@temporal_rule_eoc'(RuleID,TID,[rcvMsg,[id,TID],Protocol,Agent,Perf|Extra]),"+
				"   _0.remove_temporal_rule(RuleID,TID,[[id,TID],Agent,end_of_transmission|Extra])."
                // . Clause B: general case
+               "'@actions'(TID,[[id,TID]|Content],Protocol,RList.State,RList.Cond]) :- "+
                "   _1.store_tid(TID),"+
                "   '@actions2'([TID|Content],Protocol,RList.State,RList.Cond)."
                ,
                "",new Object[]{messenger,calc,prova});
        // actions based on rules stored in 'conversation'
        // . Clause A: inform messages should produce only one result
//		rule = rule(prereq(actions2, RListUtils.rlist("[TID,Agent,inform|Content]"),
//		        variable("Protocol", Object.class), RListUtils.rlist("State"),
//		        RListUtils.rlist("Cond")),
//		        cut(),
////				prereq(conv_id,variable("TID",Object.class),rlist("Actions2"),rlist("Actions")),
//		        fact(actions, variable("TID", Object.class),
//		                RListUtils.rlist("[[id,TID],Agent,inform|Content]"),
//		                variable("Protocol", Object.class), RListUtils.rlist("State"), RListUtils.rlist("Cond")));
//		kb.add(rule);
            /*
        // . Clause B: general case
        rule = rule(prereq(bcalc, RListUtils.rlist("[%0,%1,TID]", new Object[]{calc, new Integer(5)})),
                prereq(actions2, RListUtils.rlist("[TID|Content]"), variable("Protocol", Object.class),
                        RListUtils.rlist("State"), RListUtils.rlist("Cond")),
//				prereq(conv_id,variable("TID",Object.class),rlist("Actions2"),rlist("Actions")),
                fact(actions, variable("TID", Object.class),
                        RListUtils.rlist("[[id,TID]|Content]"), variable("Protocol", Object.class),
                        RListUtils.rlist("State"), RListUtils.rlist("Cond")));
        kb.add(rule);
        */
        {
            List rhs = new ArrayList();
            rhs.add(prereq(bcalc, RListUtils.rlist("[%0,%1,TID]", new Object[]{calc, new Integer(5)})));
            rhs.add(prereq(derive, variable("P", Object.class), RListUtils.rlist("[P|Ps]")));
            rhs.add(prereq(kb.pcalc(),
                    RListUtils.rlist("[%0,solve,[solve_first,[P|Ps]|Xs],\"=\"]", new Object[]{this})));
            rhs.add(cut());
            rhs.add(prereq(fail, new Object[0]));
            rule = rule(rhs, fact(solve_first, RListUtils.rlist("[[id,TID],Agent,solve_first,[P|Ps]|Xs]")));
            kb.add(rule);
        }
        {
            List rhs = new ArrayList();
            // Special solve rule when the original query does not contain variables:
            //    only first solution is sought for in this case
            rhs.add(prereq(bcalc, RListUtils.rlist("[%0,%1,TID]", new Object[]{calc, new Integer(5)})));
            rhs.add(prereq(derive, variable("P", Object.class), RListUtils.rlist("[P|Ps]")));
            rhs.add(prereq(kb.pcalc(),
                    RListUtils.rlist("[%0,solve,[\"solve\",[P|Ps]|Xs],\"=\",TID]", new Object[]{this})));
            rhs.add(cut());
            rhs.add(prereq(fail, new Object[0]));
            rule = rule(rhs, fact(solve_first, RListUtils.rlist("[[id,TID],Agent,solve,[P|Ps]|Xs]")));
            kb.add(rule);
        }
        // General solve rule
        rule = rule(//				prereq(kb.pcalc(),rlist("[%0,println,[P|Ps]]",new Object[]{calc})),
                prereq(bcalc, RListUtils.rlist("[%0,%1,TID]", new Object[]{calc, new Integer(5)})),
                prereq(derive, variable("P", Object.class), RListUtils.rlist("[P|Ps]")),
                prereq(kb.pcalc(),
                        RListUtils.rlist("[%0,solve,[\"solve\",[P|Ps]|Xs],\"=\",TID]", new Object[]{this})),
                prereq(fail, new Object[0]),
                fact(solve, RListUtils.rlist("[[id,TID],Agent,solve,[P|Ps]|Xs]")));
        kb.add(rule);
        // General solve rule
        rule = rule(//				prereq(kb.pcalc(),rlist("[%0,println,[P|Ps]]",new Object[]{calc})),
                prereq(bcalc, RListUtils.rlist("[%0,%1,TID]", new Object[]{calc, new Integer(5)})),
                prereq(derive, variable("P", Object.class), RListUtils.rlist("[P|Ps]")),
                prereq(kb.pcalc(),
                        RListUtils.rlist("[%0,solve,[\"solve_noprint\",[P|Ps]|Xs],\"=\"]", new Object[]{this})),
                prereq(fail, new Object[0]),
                fact(solve, RListUtils.rlist("[[id,TID],Agent,query,[P|Ps]|Xs]")));
        kb.add(rule);
        // General eval rule
        rule = rule(cut(),
                prereq(bcalc, RListUtils.rlist("[%0,%1,TID]", new Object[]{calc, new Integer(5)})),
                prereq(derive, variable("P", Object.class), RListUtils.rlist("[P|Ps]")),
//				prereq(kb.pcalc(),rlist("[%0,solve,[\"solve\",[P|Ps]],\"=\"]",new Object[]{this})),
                prereq(fail, new Object[0]),
//			prereq(kb.pcalc(), RListUtils.rlist("[%0,fail]", new Object[] {calc})),
                fact(eval, RListUtils.rlist("[[id,TID],Agent,eval,[P|Ps]]")));
        kb.add(rule);
    } catch (Exception e) {
        e.printStackTrace();
    }
    }
}
