package org.flymine.objectstore.query;

/*
 * Copyright (C) 2002-2003 FlyMine
 *
 * This code may be freely distributed and modified under the
 * terms of the GNU Lesser General Public Licence.  This should
 * be distributed with the code.  See the LICENSE file for more
 * information or http://www.gnu.org/copyleft/lesser.html.
 *
 */

/**
 * Constrain whether a QueryClass is member of a QueryReference or not.
 * QueryReference can refer to an object or a collection, test whether
 * QueryClass is a member of the collection or an instance of the object
 *
 * @author Richard Smith
 * @author Mark Woodbridge
 */

public class ContainsConstraint implements Constraint
{

    /**
     * QueryCollection does contain the specified QueryClass.
     */
    public static final int CONTAINS = 1;

    /**
     * QueryCollection does not contain the specified QueryClass.
     */
    public static final int DOES_NOT_CONTAIN = 2;

    protected boolean negated;
    protected QueryReference ref;
    protected QueryClass cls;
    protected int type;

    /**
     * Constructor for ContainsConstraint.
     *
     * @param ref the target QueryReference
     * @param type specify CONTAINS or DOES_NOT_CONTAIN
     * @param cls the QueryClass to to be tested against reference
     */
    public ContainsConstraint(QueryReference ref, int type, QueryClass cls) {
        this(ref, type, cls, false);
    }

    /**
     * Constructor for ContainsConstraint.
     *
     * @param ref the target QueryReference
     * @param type specify CONTAINS or DOES_NOT_CONTAIN
     * @param cls the QueryClass to be tested
     * @param negated reverse the constraint logic if true
     */
    public ContainsConstraint(QueryReference ref, int type, QueryClass cls, boolean negated) {
        if (ref == null) {
            throw (new NullPointerException("ref cannot be null"));
        }
        if (cls == null) {
            throw (new NullPointerException("cls cannot be null"));
        }

        if (QueryObjectReference.class.isAssignableFrom(ref.getClass())) {
            if (ref.getType() != cls.getType()) {
                throw (new IllegalArgumentException("QueryObjectReference type(" + ref.getType()
                                                    + ") not equal to QueryClass type("
                                                    + cls.getType() + ")"));
            }
        }

        if ((type < 1) || (type > 2)) {
            throw (new IllegalArgumentException("Invalid value for type: " + type));
        }

        this.ref = ref;
        this.cls = cls;
        this.type = type;
        this.negated = negated;
    }

    /**
     * Set whether constraint is negated.  Negated reverses the logic of the constraint
     * i.e equals becomes not equals.
     *
     * @param negated true if constraint logic to be reversed
     */
    public void setNegated(boolean negated) {
        this.negated = negated;
    }

    /**
     * Test if constraint logic has been reversed
     *
     * @return true if constraint is negated
     */
    public boolean isNegated() {
        return negated;
    }

    /**
     * Return the operation type
     *
     * @return the operation type
     */
    public int getType() {
        return type;
    }

    /**
     * Returns the QueryReference of the constraint.
     *
     * @return the QueryReference
     */
    public QueryReference getReference() {
        return ref;
    }

    /**
     * Returns the QueryClass of the constraint.
     *
     * @return the QueryClass
     */
    public QueryClass getQueryClass() {
        return cls;
    }

    /**
     * Returns true if the constraint is effectively "DOES_NOT_CONTAIN", taking negated into
     * account.
     *
     * @return true if it is DOES_NOT_CONTAIN
     */
    public boolean isNotContains() {
        return (type == CONTAINS ? negated : !negated);
    }

    /**
     * Test whether two ContainsConstraints are equal, overrides Object.equals()
     *
     * @param obj the object to compare with
     * @return true if objects are equal
     */
    public boolean equals(Object obj) {
        if (obj instanceof ContainsConstraint) {
            ContainsConstraint cc = (ContainsConstraint) obj;
            return (ref.equals(cc.ref)
                    && (type == cc.type)
                    && (negated == cc.negated)
                    && cls.equals(cc.cls));
        }
        return false;
    }


    /**
     * Get the hashCode for this object, overrides Object.hashCode()
     *
     * @return the hashCode
     */
    public int hashCode() {
        return ref.hashCode() + (3 * type) + ((negated) ? 29 : 0)
            + (5 * cls.hashCode());
    }


}

@@ -671,263 +671,8 @@
 t%0A%7B%0A
-%0A    /**%0A     * QueryCollection does contain the specified QueryClass.%0A     */%0A    public static final int CONTAINS = 1;%0A%0A    /**%0A     * QueryCollection does not contain the specified QueryClass.%0A     */%0A    public static final int DOES_NOT_CONTAIN = 2;%0A%0A
     
@@ -2155,9 +2155,9 @@
 e %3C 
-1
+0
 ) %7C%7C
@@ -2165,17 +2165,17 @@
 (type %3E 
-2
+1
 )) %7B%0A   
@@ -4440,10 +4440,914 @@
     %7D%0A%0A%0A
+    //-------------------------------------------------------------------------%0A    %0A    /**%0A     * QueryCollection does contain the specified QueryClass.%0A     */%0A    public static final int CONTAINS = 0;%0A%0A    /**%0A     * QueryCollection does not contain the specified QueryClass.%0A     */%0A    public static final int DOES_NOT_CONTAIN = 1;%0A%0A    protected static final String%5B%5D OPERATIONS = %7B%0A        %22CONTAINS%22,%0A        %22DOES NOT CONTAIN%22%7D;%0A%0A    /**%0A     * Returns the String representation of the operation.%0A     *%0A     * @param type the operator code%0A     * @return String representation%0A     */%0A    public static String getOpString(int type) %7B%0A        return OPERATIONS%5Btype%5D;%0A    %7D%0A%0A    /**%0A     * Return the list of valid (binary) operator codes%0A     * @return an array of character codes%0A     */%0A    public static int%5B%5D validOperators() %7B%0A        return new int%5B%5D %7BCONTAINS, DOES_NOT_CONTAIN%7D;%0A    %7D%0A
 %7D%0A

move towards common Constraint structure (see SimpleConstraint)