package adql.query;
/*
* This file is part of ADQLLibrary.
*
* ADQLLibrary 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 3 of the License, or
* (at your option) any later version.
*
* ADQLLibrary 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 ADQLLibrary. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2012 - UDS/Centre de Données astronomiques de Strasbourg (CDS)
*/
import java.util.Vector;
import adql.query.constraint.ADQLConstraint;
/**
* <p>Represents a clause which deals with {@link ADQLConstraint}s (i.e. WHERE, HAVING).</p>
*
* <p>The logical operators AND (see {@link ClauseConstraints#AND}) and OR (see {@link ClauseConstraints#OR}) are managed
* in a separated list by this class. To add a constraint you can use the default add functions or use the one defined by this class:
* <ul>
* <li> {@link ClauseConstraints#add(String, ADQLConstraint) add(String, ADQLConstraint}: which lets you specify the logical operator
* between the added constraint (index=size()) and the previous one (index=size()-1) in the list.</li>
* <li> {@link ClauseConstraints#add(int, String, ADQLConstraint) add(int, String, ADQLConstraint}: which lets you specify
* the logical operator between the added constraint (index) and the previous one (index-1) in the list.</li>
* </ul></p>
*
* <p>If no logical separator is specified the default one is used (see {@link ClauseConstraints#getDefaultSeparator() getDefaultSeparator()}).
* The only way to set this default separator is during the {@link ClauseConstraints} creation
* (see {@link ClauseConstraints#ClauseConstraints(String, String) ClauseConstraints(String, String)}).</p>
*
* @author Grégory Mantelet (CDS)
* @version 01/2012
*
* @see adql.query.constraint.ConstraintsGroup
*/
public class ClauseConstraints extends ClauseADQL<ADQLConstraint> {
/** The logical separator OR <i>(By default, the default separator (see {@link ClauseConstraints#getDefaultSeparator() getDefaultSeparator()}) is equals to OR)</i>. */
public final static String OR = "OR";
/** The logical separator AND. */
public final static String AND = "AND";
/** The logical separator used when none is specified during a constraint insertion <i>(by default = {@link ClauseConstraints#OR OR})</i>. */
protected final String defaultSeparator;
/** The used separators for the constraints list (vSeparators.size() = size()-1 ;
* vSeparators.get(i) gives the separator between get(i-1) and get(i)). */
private Vector<String> vSeparators = new Vector<String>();
/**
* <p>Builds a constraints list with only its name (which will prefix the whole list).</p>
*
* <p><i><u>Note:</u> The default separator is automatically set to OR.</i></p>
*
* @param name The name/prefix of the list.
*/
public ClauseConstraints(String name){
super(name);
defaultSeparator = OR;
}
/**
* <p>Builds a constraints list with its name and its default separator.</p>
*
* <p><i><u>Note:</u> if the given separator is no {@link ClauseConstraints#AND}
* or {@link ClauseConstraints#OR}, the default separator is automatically set to {@link ClauseConstraints#OR}.</i></p>
*
* @param name The name/prefix of the list.
* @param logicalSep The constraints separator (a logical separator: {@link ClauseConstraints#AND} or {@link ClauseConstraints#OR}).
*
* @see ClauseConstraints#checkSeparator(String)
*/
public ClauseConstraints(String name, String logicalSep){
super(name);
defaultSeparator = checkSeparator(logicalSep);
}
/**
* <p>Builds a ClauseConstraints by copying the given one.</p>
*
* @param toCopy The ClauseConstraints to copy.
* @throws Exception If there is an error during the copy.
*
* @see ClauseConstraints#checkSeparator(String)
*/
public ClauseConstraints(ClauseConstraints toCopy) throws Exception{
super(toCopy);
defaultSeparator = checkSeparator(toCopy.defaultSeparator);
}
/**
* Gets the default constraints separator ({@link ClauseConstraints#AND} or {@link ClauseConstraints#OR}).
*
* @return The default separator.
*/
public final String getDefaultSeparator(){
return defaultSeparator;
}
/**
* Checks/Converts the given separator in one of the two logical separators.
* If the given separator is neither AND nor OR, then the returned separator is {@link ClauseConstraints#OR OR}.
*
* @param sepToCheck The separator to check/convert.
* @return The understood separator (OR if neither AND nor OR).
*/
public final static String checkSeparator(String sepToCheck){
if (sepToCheck != null && sepToCheck.equalsIgnoreCase(AND))
return AND;
else
return OR;
}
/**
* @see adql.query.ADQLList#add(adql.query.ADQLObject)
* @see ClauseConstraints#add(String, ADQLConstraint)
*/
@Override
public boolean add(ADQLConstraint constraint) throws NullPointerException{
return add(defaultSeparator, constraint);
}
/**
* @see adql.query.ADQLList#add(int, adql.query.ADQLObject)
* @see ClauseConstraints#add(int, String, ADQLConstraint)
*/
@Override
public void add(int index, ADQLConstraint constraint) throws NullPointerException, ArrayIndexOutOfBoundsException{
add(index, defaultSeparator, constraint);
}
/**
* Adds the given constraint with the given separator. The separator is added just before the added constraint,
* that is to say between the last constraint of the list and the added one.
*
* @param logicalSep The separator to add just before the given constraint.
* @param constraint The constraint to add.
* @return <i>true</i> if the constraint has been successfully added, <i>false</i> otherwise.
* @throws NullPointerException If the given constraint is <i>null</i>.
*
* @see ADQLList#add(ADQLObject)
* @see ClauseConstraints#checkSeparator(String)
*/
public boolean add(String logicalSep, ADQLConstraint constraint) throws NullPointerException{
boolean added = super.add(constraint);
if (added && size() > 1)
vSeparators.add(checkSeparator(logicalSep));
return added;
}
/**
* Adds the given constraint with the given separator at the given position in the constraints list.
* The separator is added just before the added constraint, that is to say between the (index-1)-th constraint of the list and the added one (at the index position).
*
* @param index Position at which the given constraint must be added.
* @param logicalSep The constraints separator to add just before the given constraint.
* @param constraint The constraint to add.
* @throws NullPointerException If the given constraint is <i>null</i>.
* @throws ArrayIndexOutOfBoundsException If the given index is incorrect (index < 0 || index >= size()).
*
* @see ADQLList#add(int, ADQLObject)
* @see ClauseConstraints#checkSeparator(String)
*/
public void add(int index, String logicalSep, ADQLConstraint constraint) throws NullPointerException, ArrayIndexOutOfBoundsException{
super.add(index, constraint);
if (index > 0)
vSeparators.add(index - 1, checkSeparator(logicalSep));
}
/**
* @see adql.query.ADQLList#set(int, adql.query.ADQLObject)
* @see ClauseConstraints#set(int, String, ADQLConstraint)
*/
@Override
public ADQLConstraint set(int index, ADQLConstraint constraint) throws NullPointerException, ArrayIndexOutOfBoundsException{
return set(index, null, constraint);
}
/**
* Replaces the specified constraint by the given one with the given constraint separator.
* The separator is added just before the added constraint, that is to say between the (index-1)-th constraint of the list and the added one (at the index position).
*
* @param index Position of the constraint to replace.
* @param logicalSep The separator to insert just before the given constraint (if <i>null</i>, the previous separator is kept).
* @param constraint The replacer.
* @return The replaced constraint.
* @throws NullPointerException If the given constraint is <i>null</i>.
* @throws ArrayIndexOutOfBoundsException If the given index is incorrect (index < 0 || index >= size()).
*
* @see ADQLList#set(int, ADQLObject)
*/
public ADQLConstraint set(int index, String logicalSep, ADQLConstraint constraint) throws NullPointerException, ArrayIndexOutOfBoundsException{
ADQLConstraint replaced = super.set(index, constraint);
if (replaced != null && logicalSep != null && index > 0)
vSeparators.set(index - 1, logicalSep);
return replaced;
}
@Override
public void clear(){
super.clear();
vSeparators.clear();
}
@Override
public ADQLConstraint remove(int index) throws ArrayIndexOutOfBoundsException{
ADQLConstraint removed = super.remove(index);
if (removed != null)
if (index > 0)
vSeparators.remove(index - 1);
else if (index == 0)
vSeparators.remove(index);
return removed;
}
@Override
public ADQLObject getCopy() throws Exception{
return new ClauseConstraints(this);
}
/**
* Only two values in this case: the both logical separators: {@link ClauseConstraints#AND AND} and {@link ClauseConstraints#OR OR}.
*
* @see adql.query.ADQLList#getPossibleSeparators()
*/
@Override
public String[] getPossibleSeparators(){
return new String[]{AND,OR};
}
@Override
public String getSeparator(int index) throws ArrayIndexOutOfBoundsException{
if (index <= 0 || index > size())
throw new ArrayIndexOutOfBoundsException("Impossible to get the logical separator between the item " + (index - 1) + " and " + index + " !");
else
return vSeparators.get(index - 1);
}
}