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-2015 - UDS/Centre de Données astronomiques de Strasbourg (CDS),
* Astronomisches Rechen Institut (ARI)
*/
import java.util.Iterator;
import java.util.Vector;
/**
* <p>Represents a list of ADQL items.</p>
*
* <p>Since it is a list, it is possible to add, remove, modify and iterate on a such object.</p>
*
* @author Grégory Mantelet (CDS;ARI)
* @version 1.4 (06/2015)
*
* @see ClauseADQL
* @see ClauseConstraints
* @see adql.query.operand.Operation
* @see adql.query.operand.Concatenation
*/
public abstract class ADQLList< T extends ADQLObject > implements ADQLObject, Iterable<T> {
/** Label of the list. */
private final String name;
/** List of ADQL items. */
private final Vector<T> list = new Vector<T>();
/** Position inside an ADQL query string.
* @since 1.4 */
private TextPosition position = null;
/**
* Builds an ADQLList with only its name. This name will always prefix the list.
*
* @param name Prefix/Name of this list.
*/
protected ADQLList(String name){
if (name != null){
name = name.trim();
if (name.length() == 0)
name = null;
}
this.name = name;
}
/**
* <p>Builds an ADQLList by copying the given one.</p>
* <p><i><u>Note:</u> It is a deep copy.</i></p>
*
* @param toCopy The ADQLList to copy.
* @throws Exception If there is an error during the copy.
*/
@SuppressWarnings("unchecked")
protected ADQLList(ADQLList<T> toCopy) throws Exception{
this(toCopy.getName());
for(T obj : toCopy)
add((T)obj.getCopy());
position = (toCopy.position != null) ? new TextPosition(toCopy.position) : null;
}
/**
* Adds the given item (if not <i>null</i>) at the end of this clause.
*
* @param item The ADQL item to add to this clause.
* @return <i>true</i> if the given item has been successfully added, <i>false</i> otherwise.
* @throws NullPointerException If the given item is <i>null</i>.
*/
public boolean add(T item) throws NullPointerException{
if (item == null)
throw new NullPointerException("It is impossible to add NULL items to an ADQL clause !");
else{
if (list.add(item)){
position = null;
return true;
}else
return false;
}
}
/**
* Adds the given item (if not <i>null</i>) at the given position into this clause.
*
* @param index Position at which the given item must be added.
* @param item ADQL item to add to this clause.
* @throws NullPointerException If the given item is <i>null</i>.
* @throws ArrayIndexOutOfBoundsException If the index is out of range (index < 0 || index > size()).
*/
public void add(int index, T item) throws NullPointerException, ArrayIndexOutOfBoundsException{
if (item != null){
list.add(index, item);
position = null;
}else
throw new NullPointerException("It is impossible to add NULL items to an ADQL clause !");
}
/**
* Replaces the specified ADQL item by the given one.
*
* @param index Position of the item to replace.
* @param item Replacer of the specified ADQL item.
* @return The replaced ADQL item.
* @throws NullPointerException If the given item is <i>null</i>.
* @throws ArrayIndexOutOfBoundsException If the index is out of range (index < 0 || index > size()).
*/
public T set(int index, T item) throws NullPointerException, ArrayIndexOutOfBoundsException{
if (item != null){
T removed = list.set(index, item);
position = null;
return removed;
}else
throw new NullPointerException("It is impossible to replace an ADQL item by a NULL item into an ADQL clause !");
}
/**
* Gets the specified ADQL item.
*
* @param index Index of the ADQL item to retrieve.
* @return The corresponding ADQL item.
* @throws ArrayIndexOutOfBoundsException If the index is out of range (index < 0 || index > size()).
*/
public T get(int index) throws ArrayIndexOutOfBoundsException{
return list.get(index);
}
/**
* Removes the specified ADQL item.
*
* @param index Index of the ADQL item to remove.
* @return The removed ADQL item.
* @throws ArrayIndexOutOfBoundsException If the index is out of range (index < 0 || index > size()).
*/
public T remove(int index) throws ArrayIndexOutOfBoundsException{
T removed = list.remove(index);
if (removed != null)
position = null;
return removed;
}
/**
* Clears this clause.
*/
public void clear(){
list.clear();
position = null;
}
/**
* Gets the length of this clause.
*
* @return The number of ADQL items contained into this clause.
*/
public int size(){
return list.size();
}
/**
* Tells whether this clause contains at least one ADQL item.
*
* @return <i>true</i> if this clause is empty, <i>false</i> otherwise.
*/
public boolean isEmpty(){
return list.isEmpty();
}
@Override
public String getName(){
return name;
}
@Override
public final TextPosition getPosition(){
return position;
}
/**
* Sets the position at which this {@link ADQLList} has been found in the original ADQL query string.
*
* @param position Position of this {@link ADQLList}.
* @since 1.4
*/
public final void setPosition(final TextPosition position){
this.position = position;
}
@Override
public String toADQL(){
StringBuffer adql = new StringBuffer((getName() == null) ? "" : (getName() + " "));
for(int i = 0; i < size(); i++){
if (i > 0)
adql.append(" " + getSeparator(i) + " ");
adql.append(get(i).toADQL());
}
return adql.toString();
}
@Override
public Iterator<T> iterator(){
return list.iterator();
}
@Override
public ADQLIterator adqlIterator(){
return new ADQLListIterator(this);
}
/**
* Gets the list of all possible separators for this {@link ADQLList}.
*
* @return Possible separators.
*/
public abstract String[] getPossibleSeparators();
/**
* Gets the separator between the list items index-1 and index.
*
* @param index Index of the right list item.
* @return The corresponding separator.
* @throws ArrayIndexOutOfBoundsException If the index is less or equal than 0, or is greater or equal than {@link ADQLList#size() size()}.
*/
public abstract String getSeparator(int index) throws ArrayIndexOutOfBoundsException;
@Override
public abstract ADQLObject getCopy() throws Exception;
/**
* Lets iterating on all ADQL objects of the given {@link ADQLList}.
*
* @author Grégory Mantelet (CDS)
* @version 06/2011
*/
public static class ADQLListIterator implements ADQLIterator {
protected final ADQLList<ADQLObject> list;
protected int index = -1;
protected boolean removed = false;
@SuppressWarnings("unchecked")
public ADQLListIterator(ADQLList<? extends ADQLObject> lst){
list = (ADQLList<ADQLObject>)lst;
}
@Override
public boolean hasNext(){
return index + 1 < list.size();
}
@Override
public ADQLObject next(){
removed = false;
return list.get(++index);
}
@Override
public void replace(ADQLObject replacer) throws UnsupportedOperationException, IllegalStateException{
if (index <= -1)
throw new IllegalStateException("replace(ADQLObject) impossible: next() has not yet been called !");
if (removed)
throw new IllegalStateException("The remove() has already been called !");
if (replacer == null)
remove();
else
list.set(index, replacer);
}
@Override
public void remove(){
if (index <= -1)
throw new IllegalStateException("remove() impossible: next() has not yet been called !");
if (removed)
throw new IllegalStateException("The remove() has already been called !");
list.remove(index--);
removed = true;
}
}
}