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