/*
* BioJava development code
*
* 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. If you do not have a copy,
* see:
*
* http://www.gnu.org/copyleft/lesser.html
*
* Copyright for this code is held jointly by the individual
* authors. These should be listed in @author doc comments.
*
* For more information on the BioJava project and its aims,
* or to join the biojava-l mailing list, visit the home page
* at:
*
* http://www.biojava.org/
*
*/
package org.biojava.bio.symbol;
/**
* Factory methods for constructing useful views onto SymbolLists.
*
* @author Thomas Down
* @author Matthew Pocock
* @since 1.1
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.biojava.bio.seq.SequenceIterator;
import org.biojava.utils.ChangeVetoException;
import org.biojava.utils.Unchangeable;
/**
* Tools class for constructing views of SymbolList
objects.
*
* @since 1.2
*/
public final class SymbolListViews {
private SymbolListViews() {}
/**
* An n-th order view of another SymbolList.
*
* In practice, what this means is that you can view a DNA sequence into an * overlapping dinucleotide sequence without having to do any work yourself. *
* * @param source The underlying SymbolList to view * @param order The window size */ public static SymbolList orderNSymbolList(SymbolList source, int order) throws IllegalAlphabetException { if (order == 1) return source; return new OrderNSymbolList(source, order); } /** * A view of windows onto another SymbolList. ** In practice, what this means is that you can view a DNA sequence as codons which * do not overlap. *
* * @param source The underlying SymbolList to view * @param wsize The window size. * @throws IllegalArgumentException if the symbollist length isn't an integer multiple of wsize. */ public static SymbolList windowedSymbolList(SymbolList source, int wsize) throws IllegalArgumentException { return new WindowedSymbolList(source, wsize); } /** * A reversed view onto a SymbolList. * * @param symbols the SymbolList to reverse. */ public static SymbolList reverse(SymbolList symbols) { return new ReverseSymbolList(symbols); } /** * Provides a 'translated' view of an underlying SymbolList. ** This method allows you to translate from one alphabet into another, so * for example, you could translate from DNA-triplets into amino-acids. You * could also translate from DNA-dinucleotide into the 'twist' structural * metric, or any other translation that takes your fancy. *
** The actual mapping from source to view Symbol is encapsulated in a * TranslationTable object. *
** The translated SymbolList will be the same length as the source, and each * Symbol in the view will correspond to a single Symbol in the source. *
* * @param symbols a SymbolList to translate. * @param table a translation table for mapping symbols. */ public static SymbolList translate(SymbolList symbols, TranslationTable table) throws IllegalAlphabetException { return new TranslatedSymbolList(symbols, table); } /** * Construct an alignment of the SymbolLists contained in the values collection * oflabelToSymList
.
*
* @param labelToSymList A Map containing label -> SymbolList mappings
*/
public static Alignment alignment(Map labelToSymList)
throws IllegalArgumentException {
return new SimpleAlignment(labelToSymList);
}
/**
* View a SymbolList over a cross-product Alphabet as an Alignment.
*
* @param labels a List of labels, which should be the same length
* as the order symList
's Alphabet.
* @param symList a SymbolList over a cross-product alphabet.
*/
public static Alignment alignment(List labels, SymbolList symList)
throws IllegalArgumentException {
return new SymListAsAlignment(labels, symList);
}
/**
* View a portion of a SymbolList. Unlike SymbolList.subList, this
* method is guarenteed to return a view, which will change when
* the underlying SymbolList is modified.
*
* @param parent the SymbolList to view
* @param start the first index to include in the view
* @param end the last index to include in the view
* @throws IllegalArgumentException if the start or end points fall outside the parent SymbolList.
* @since 1.4
*/
public static SymbolList subList(SymbolList parent, int start, int end)
throws IllegalArgumentException
{
if (start < 1 || end > parent.length()) {
throw new IndexOutOfBoundsException(
"Sublist index out of bounds " + parent.length() + ":" + start + "," + end
);
}
if (end < start) {
throw new IllegalArgumentException(
"end must not be lower than start: start=" + start + ", end=" + end
);
}
return new SubList(parent, start, end);
}
/**
* Get a new immutable, empty symbol list with the given alphabet.
*
* @since 1.4
* @param alpha the Alphabet this symbol list is over
* @return a new empty SymbolList
*/
public static SymbolList emptyList(Alphabet alpha)
{
return new EmptySymbolList(alpha);
}
private static class SymListAsAlignment
extends Unchangeable
implements Alignment {
private final SymbolList symList;
private final List labels;
public SymListAsAlignment(List labels, SymbolList symList) {
if(labels.size() != symList.getAlphabet().getAlphabets().size()) {
throw new IllegalArgumentException("There must be one label per symbol list");
}
this.labels = Collections.unmodifiableList(new ArrayList(labels));
this.symList = symList;
}
public List getLabels() {
return labels;
}
public SequenceIterator sequenceIterator() {
throw new UnsupportedOperationException("This method sucks");
}
public Iterator symbolListIterator() {
return new Alignment.SymbolListIterator(this);
}
public Symbol symbolAt(Object label, int column) {
BasisSymbol sym = (BasisSymbol) symList.symbolAt(column);
return (Symbol) sym.getSymbols().get(labels.indexOf(label));
}
public SymbolList symbolListForLabel(Object label) {
return new IndexedSymbolList(symList, labels.indexOf(label));
}
public Alphabet getAlphabet() {
return symList.getAlphabet();
}
public Iterator iterator() {
return symList.iterator();
}
public int length() {
return symList.length();
}
public String seqString() {
return symList.seqString();
}
public SymbolList subList(int start, int end)
throws IndexOutOfBoundsException {
return symList.subList(start, end);
}
public String subStr(int start, int end)
throws IndexOutOfBoundsException {
return symList.subStr(start, end);
}
public void edit(Edit edit)
throws
IndexOutOfBoundsException,
IllegalAlphabetException,
ChangeVetoException
{
symList.edit(edit);
}
public List toList() {
return symList.toList();
}
public Symbol symbolAt(int indx)
throws IndexOutOfBoundsException {
return symList.symbolAt(indx);
}
public Alignment subAlignment(Set labels, Location loc) {
throw new UnsupportedOperationException("Fixme: this needs to be implemented");
}
}
private static class IndexedSymbolList
extends AbstractSymbolList {
private final int indx;
private final SymbolList symList;
public IndexedSymbolList(SymbolList symList, int indx)
throws IllegalArgumentException {
if(indx >= symList.getAlphabet().getAlphabets().size()) {
throw new IllegalArgumentException("index too high");
}
this.indx = indx;
this.symList = symList;
}
public Alphabet getAlphabet() {
return (Alphabet) symList.getAlphabet().getAlphabets().get(indx);
}
public int length() {
return symList.length();
}
public Symbol symbolAt(int indx)
throws IndexOutOfBoundsException {
return (Symbol) ((BasisSymbol) symList.symbolAt(indx)).getSymbols().get(this.indx);
}
}
}