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     * Created on 01-21-2010
021     */
022    package org.biojava3.core.sequence.transcription;
023    
024    import java.util.List;
025    
026    import org.biojava3.core.sequence.compound.AminoAcidCompound;
027    import org.biojava3.core.sequence.compound.NucleotideCompound;
028    import org.biojava3.core.sequence.template.Compound;
029    import org.biojava3.core.sequence.template.CompoundSet;
030    import org.biojava3.core.util.Equals;
031    import org.biojava3.core.util.Hashcoder;
032    
033    /**
034     * Provides a way of separating us from the specific {@link IUPACTable} even
035     * though this is the only implementing class for the interface.
036     *
037     * @author ayates
038     */
039    public interface Table {
040    
041        List<Codon> getCodons(CompoundSet<NucleotideCompound> nucelotides,
042                CompoundSet<AminoAcidCompound> aminoAcids);
043    
044        CompoundSet<Codon> getCodonCompoundSet(
045                final CompoundSet<NucleotideCompound> rnaCompounds,
046                final CompoundSet<AminoAcidCompound> aminoAcidCompounds);
047    
048        /**
049         * Returns true if the given compound could have been a start amino acid;
050         * this does not assert if the codon that actually coded for the amino
051         * acid was a start codon. This is as accurate a call as we can make with an
052         * {@link AminoAcidCompound}.
053         */
054        boolean isStart(AminoAcidCompound compound);
055    
056        /**
057         * Instance of a Codon which is 3 {@link NucleotideCompound}s, its
058         * corresponding {@link AminoAcidCompound} and if it is a start or stop codon.
059         * The object implements hashCode & equals but according to the nucleotide
060         * compounds & not to the designation of it being a start, stop & amino
061         * acid compound
062         *
063         * @author ayates
064         *
065         */
066        public static class Codon implements Compound {
067    
068            private final CaseInsensitiveTriplet triplet;
069            private final boolean start;
070            private final boolean stop;
071            private final AminoAcidCompound aminoAcid;
072            private final String stringified;
073    
074            public Codon(CaseInsensitiveTriplet triplet, AminoAcidCompound aminoAcid, boolean start,
075                    boolean stop) {
076                this.triplet = triplet;
077                this.start = start;
078                this.stop = stop;
079                this.aminoAcid = aminoAcid;
080                this.stringified = triplet.toString();
081            }
082    
083            public Codon(CaseInsensitiveTriplet triplet) {
084                this(triplet, null, false, false);
085            }
086    
087            public NucleotideCompound getOne() {
088                return triplet.getOne();
089            }
090    
091            public NucleotideCompound getTwo() {
092                return triplet.getTwo();
093            }
094    
095            public NucleotideCompound getThree() {
096                return triplet.getThree();
097            }
098    
099            public boolean isStart() {
100                return start;
101            }
102    
103            public boolean isStop() {
104                return stop;
105            }
106    
107            public AminoAcidCompound getAminoAcid() {
108                return aminoAcid;
109            }
110    
111            public CaseInsensitiveTriplet getTriplet() {
112                return triplet;
113            }
114    
115            @Override
116            public boolean equals(Object obj) {
117                boolean equals = false;
118                if(Equals.classEqual(this, obj)) {
119                    Codon casted = (Codon) obj;
120                    equals =   Equals.equal(getTriplet(), casted.getTriplet()) &&
121                                Equals.equal(isStart(), casted.isStart()) &&
122                                Equals.equal(isStop(), casted.isStop()) &&
123                                Equals.equal(getAminoAcid(), casted.getAminoAcid());
124                }
125                return equals;
126            }
127    
128            @Override
129            public int hashCode() {
130                int result = Hashcoder.SEED;
131                result = Hashcoder.hash(result, getTriplet());
132                result = Hashcoder.hash(result, isStop());
133                result = Hashcoder.hash(result, isStart());
134                result = Hashcoder.hash(result, getAminoAcid());
135                return result;
136            }
137    
138            @Override
139            public String toString() {
140                return stringified;
141            }
142    
143            @Override
144            public boolean equalsIgnoreCase(Compound compound) {
145                return toString().equalsIgnoreCase(compound.toString());
146            }
147    
148            @Override
149            public String getDescription() {
150                throw new UnsupportedOperationException("Not supported");
151            }
152    
153            @Override
154            public String getLongName() {
155                throw new UnsupportedOperationException("Not supported");
156            }
157    
158            @Override
159            public Float getMolecularWeight() {
160                throw new UnsupportedOperationException("Not supported");
161            }
162    
163            @Override
164            public String getShortName() {
165                return stringified;
166            }
167    
168            @Override
169            public void setDescription(String description) {
170                throw new UnsupportedOperationException("Not supported");
171            }
172    
173            @Override
174            public void setLongName(String longName) {
175                throw new UnsupportedOperationException("Not supported");
176            }
177    
178            @Override
179            public void setMolecularWeight(Float molecularWeight) {
180                throw new UnsupportedOperationException("Not supported");
181            }
182    
183            @Override
184            public void setShortName(String shortName) {
185                throw new UnsupportedOperationException("Not supported");
186            }
187        }
188    
189        /**
190         * Class used to hold three nucleotides together and allow for equality
191         * to be assessed in a case insensitive manner.
192         */
193        public static class CaseInsensitiveTriplet {
194    
195            private final NucleotideCompound one;
196            private final NucleotideCompound two;
197            private final NucleotideCompound three;
198    
199            private transient boolean hashSet = false;
200            private transient int hash;
201            private transient boolean stringSet = false;
202            private transient String stringify;
203    
204            public CaseInsensitiveTriplet(NucleotideCompound one,
205                    NucleotideCompound two, NucleotideCompound three) {
206                this.one = one;
207                this.two = two;
208                this.three = three;
209    
210            }
211    
212            public NucleotideCompound getOne() {
213                return one;
214            }
215    
216            public NucleotideCompound getTwo() {
217                return two;
218            }
219    
220            public NucleotideCompound getThree() {
221                return three;
222            }
223    
224            @Override
225            public boolean equals(Object obj) {
226                boolean equals = false;
227                if(Equals.classEqual(this, obj)) {
228                    CaseInsensitiveTriplet casted = (CaseInsensitiveTriplet) obj;
229                    return toString().equals(casted.toString());
230                }
231                return equals;
232            }
233    
234            @Override
235            public int hashCode() {
236                if(!hashSet) {
237                    hash = toString().hashCode();
238                    hashSet = true;
239                }
240                return hash;
241            }
242    
243            @Override
244            public String toString() {
245                if(!stringSet) {
246                    stringify = getOne().getUpperedBase() +
247                        getTwo().getUpperedBase() +
248                        getThree().getUpperedBase();
249                }
250                return stringify;
251            }
252    
253            /**
254             * Attempts to provide an int version of this codon which multiplies
255             * each position by
256             */
257            public int intValue() {
258                return (16 * compoundToInt(getOne())) +
259                        (4 * compoundToInt(getTwo())) +
260                        (compoundToInt(getThree()));
261            }
262    
263            public int compoundToInt(NucleotideCompound c) {
264                char b = c.getUpperedBase().charAt(0);
265                return (int)b;
266    //            int v = -1;
267    //            if('A' == b) {
268    //                v = 1;
269    //            }
270    //            else if('C' == b) {
271    //                v = 2;
272    //            }
273    //            else if('G' == b) {
274    //                v = 3;
275    //            }
276    //            else if('T' == b || 'U' == b) {
277    //                v = 4;
278    //            }
279    //            return v;
280            }
281        }
282    }