/*
 * 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.meta;


import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.mandarax.kernel.Clause;
import org.mandarax.util.DataSource;
import org.mandarax.util.StaticDataSource;

/**
 * Clause set for symmetric predicates such as <code>equals()</code>.
 * E.g.,in case a equals b, only one of the facts equals(a,b) and equals(b,a) is in the set
 * because it is known (from the semantic of the method) that <code>a.equals(b)</code>
 * yields true if and only if <code>b.equals(a)</code> is yields true.
 * @see org.mandarax.util.AutoFacts
 * @author <A HREF="mailto:mandarax@jbdietrich.com">Jens Dietrich</A>
 * @version 3.3.1 <9 August 2004>
 * @since 1.0
 * @deprecated it is recommended to use the more general class org.mandarax.util.AutoFacts instead
 */
public class JSymmetricClauseSet extends AbstractClauseSet {

    private DataSource argumentSet = null;

    /**
     * Constructor.
     * @param aPredicate a predicate
     * @param argumentSets the collections of objects
     * @throws java.lang.IllegalAccessException Thrown if the method wrapped by the predicate is not public.
     * @throws java.lang.IllegalArgumentException Thrown if the return type of the method wrapped by the predicate is not boolean or if the number of argument sets does not match.
     */
    public JSymmetricClauseSet(JPredicate aPredicate, Collection argumentSet)
            throws NullPointerException, IllegalAccessException,
                   IllegalArgumentException {
        super ();

        initialize (aPredicate, new StaticDataSource (argumentSet));
    }

    /**
     * Constructor.
     * @param aPredicate a predicate
     * @param argumentSets the collections of objects
     * @param isNegated true if the set should be negated, false otherwise
     * @throws java.lang.IllegalAccessException Thrown if the method wrapped by the predicate is not public.
     * @throws java.lang.IllegalArgumentException Thrown if the return type of the method wrapped by the predicate is not boolean or if the number of argument sets does not match.
     */
    public JSymmetricClauseSet(
            JPredicate aPredicate, Collection argumentSet, boolean isNegated)
                throws NullPointerException, IllegalAccessException,
                       IllegalArgumentException {
        super (isNegated);

        initialize (aPredicate, new StaticDataSource (argumentSet));
    }

    /**
     * Constructor.
     * @param aPredicate a predicate
     * @param argumentSets the data sources (kind of dynamic collections)
     * @throws java.lang.IllegalAccessException Thrown if the method wrapped by the predicate is not public.
     * @throws java.lang.IllegalArgumentException Thrown if the return type of the method wrapped by the predicate is not boolean or if the number of argument sets does not match.
     */
    public JSymmetricClauseSet(JPredicate aPredicate, DataSource argumentSet)
            throws NullPointerException, IllegalAccessException,
                   IllegalArgumentException {
        super ();

        initialize (aPredicate, argumentSet);
    }

    /**
     * Constructor.
     * @param aPredicate a predicate
     * @param argumentSets the data sources (kind of dynamic collections)
     * @param isNegated true if the set should be negated, false otherwise
     * @throws java.lang.IllegalAccessException Thrown if the method wrapped by the predicate is not public.
     * @throws java.lang.IllegalArgumentException Thrown if the return type of the method wrapped by the predicate is not boolean or if the number of argument sets does not match.
     */
    public JSymmetricClauseSet(
            JPredicate aPredicate, DataSource argumentSet, boolean isNegated)
                throws NullPointerException, IllegalAccessException,
                       IllegalArgumentException {
        super (isNegated);

        initialize (aPredicate, argumentSet);
    }

    /**
     * Build the collection of facts.
     * @return the collection of facts built
     */
    protected Collection buildFacts() {
        Collection collData = argumentSet.getData ();
        List       data     = null;

        // cast to or build a list since looping with an index is easier here
        if(collData instanceof List) {
            data = (List) collData;
        } else {
            Vector v = new Vector (collData.size ());

            for(Iterator it = collData.iterator (); it.hasNext (); ) {
                v.add (it.next ());
            }

            data = v;
        }

        int      n    = data.size ();
        Clause   f    = null;
        Vector   coll = new Vector (n * (n + 1) / 2);
        Object[] par  = new Object[1];

        for(int i = 0; i < data.size (); i++) {
            for(int j = 0; j <= i; j++) {
                par[0] = data.get (j);
                f      = buildFact (data.get (i), par);

                if(f != null) {
                    coll.add (f);
                }
            }
        }

        return coll;
    }

    /**
     * Validate the parameters provided to set up the set.
     * @param aPredicate the predicate
     * @param argSet the data source
     * @throws java.lang.IllegalAccessException Thrown if the method wrapped by the predicate is not public.
     * @throws java.lang.IllegalArgumentException Thrown if the return type of the method wrapped by the predicate is not boolean or if the number of argument sets does not match.
     */
    private void initialize(JPredicate aPredicate, DataSource argSet)
            throws NullPointerException, IllegalAccessException,
                   IllegalArgumentException {
        if(argSet == null) {
            throw new NullPointerException (
                "The argument sets cannot be null");
        }

        initialize (aPredicate);

        argumentSet = argSet;
    }
}
