001/* 002 * BioJava development code 003 * 004 * This code may be freely distributed and modified under the 005 * terms of the GNU Lesser General Public Licence. This should 006 * be distributed with the code. If you do not have a copy, 007 * see: 008 * 009 * http://www.gnu.org/copyleft/lesser.html 010 * 011 * Copyright for this code is held jointly by the individual 012 * authors. These should be listed in @author doc comments. 013 * 014 * For more information on the BioJava project and its aims, 015 * or to join the biojava-l mailing list, visit the home page 016 * at: 017 * 018 * http://www.biojava.org/ 019 * 020 */ 021 022package org.biojava.bio.seq; 023 024import org.biojava.bio.BioError; 025import org.biojava.bio.BioException; 026import org.biojava.bio.seq.impl.ViewSequence; 027import org.biojava.bio.symbol.CircularLocation; 028import org.biojava.bio.symbol.Edit; 029import org.biojava.bio.symbol.Location; 030import org.biojava.bio.symbol.SimpleSymbolList; 031import org.biojava.bio.symbol.Symbol; 032import org.biojava.bio.symbol.SymbolList; 033import org.biojava.utils.ChangeVetoException; 034 035/** 036 * <p> 037 * A circular view onto another Sequence object. The class allows for 038 * reinterpretation of locations and indices onto the sequence to allow for 039 * overlapping of the origin. The origin is assumed to be the first symbol. 040 * Future versions may support changing the origin. 041 * </p> 042 * In biojavax {@link org.biojavax.bio.seq.RichSequence RichSequences} intrinsicly know about 043 * circularity. No view is required. We strongly recommend using RichSequence 044 * if possible. 045 * 046 * 047 * @author Mark Schreiber 048 * @version 1.2 049 * @since 1.1 050 * @see org.biojavax.bio.seq.RichSequence 051 */ 052 053public class CircularView extends ViewSequence{ 054 public CircularView(Sequence seq, FeatureRealizer fr){ 055 super(seq, fr); 056 } 057 058 public CircularView(Sequence seq){ 059 super(seq); 060 } 061 062 private int realValue(int val){ 063 val = (val % length()); 064 if(val < 1) val = length() + val; 065 return val; 066 } 067 068 /** 069 * <p> 070 * Over rides ViewSequence. Allows any integer index, positive or negative 071 * to return a symbol via the equation 072 * <CODE>val = (val % length);</CODE> 073 * Note that base zero is the base immediately before base 1 which is of course 074 * the last base of the sequence. 075 * </p> 076 * @param index the index of the <code>Symbol </code>requested. 077 * @return the <code>Symbol </code>specified by the <code>index.</code> 078 */ 079 public Symbol symbolAt(int index){ 080 return super.symbolAt(realValue(index)); 081 } 082 083 /** 084 * <p> 085 * Over rides ViewSequence. Allows any integer index, positive or negative 086 * to return a symbol via the equation 087 * <CODE>val = (val % length);</CODE> 088 * </p> 089 * 090 * <p> 091 * Will return a linear String which can, if nescessary, span the origin. 092 * </p> 093 * @param start the index of the fist base 094 * @param end the index of the last base 095 * @return a <code>String </code>representation of the tokenized <code>Symbol</code>s 096 */ 097 public String subStr(int start, int end){ 098 099 start = realValue(start); 100 end = realValue(end); 101 102 if(start <= end){ 103 return super.subStr(start, end); 104 } 105 else{ 106 String toEnd = super.subStr(start,super.length()); 107 String fromStart = super.subStr(1,end); 108 return toEnd + fromStart; 109 } 110 } 111 112 /** 113 * Over rides ViewSequence to allow the use of locations that have 114 * coordinates outside of the sequence length (which are needed to 115 * describe locations that overlap the origin of a circular sequence). 116 * 117 * @since 1.2 118 * @throws BioException if a non circular location is added that exceeds the 119 * 'boundaries' of the sequence. 120 * @throws ChangeVetoException if the sequence is locked. 121 * @param template the template of the feature to be created. 122 * @return the feature created you can use the template of the returned feature 123 * to create another of the same type. 124 */ 125 public Feature createFeature(Feature.Template template) 126 throws ChangeVetoException, BioException 127 { 128 Location loc = template.location; 129 if(loc.getMax() > length() && (loc instanceof CircularLocation == false)){ 130 throw new BioException("Only CircularLocations may exceed sequence length"); 131 } 132 Feature f = realizeFeature(this, template); 133 ((SimpleFeatureHolder)getAddedFeatures()).addFeature(f); 134 return f; 135 } 136 137 /** 138 * <p> 139 * Over rides ViewSequence. Allows any integer index, positive or negative 140 * to return a symbol via the equation 141 * <CODE>index = ((index -1) % length)+1</CODE> 142 * </p> 143 * 144 * <p> 145 * Will return a linear SymbolList which can ,if nescessary, span the origin. 146 * </p> 147 * @param start the first base of the sublist 148 * @param end the last base of the sublist 149 * @return a <code>SymbolList </code>containing the <code>Symbols</code> from 150 * <code>start</code> to <code>end</code> inclusive 151 */ 152 public SymbolList subList(int start, int end){ 153 154 start = realValue(start); 155 end = realValue(end); 156 157 if(start <= end){ 158 return super.subList(start, end); 159 } 160 else{ 161 SimpleSymbolList fromStart = new SimpleSymbolList(super.subList(1,end)); 162 SimpleSymbolList toEnd = new SimpleSymbolList(super.subList(start,length())); 163 Edit edit = new Edit(toEnd.length() +1, 0, fromStart); 164 try{ 165 toEnd.edit(edit); 166 }catch(Exception e){ 167 throw new BioError("Couldn't construct subList, this shouldn't happen",e); 168 } 169 return toEnd; 170 } 171 } 172} 173