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 */
021package org.biojava.nbio.core.search.io;
022
023import java.util.ArrayList;
024import java.util.List;
025import org.biojava.nbio.core.alignment.SimpleAlignedSequence;
026import org.biojava.nbio.core.alignment.SimpleSequencePair;
027import org.biojava.nbio.core.alignment.template.AlignedSequence.Step;
028import org.biojava.nbio.core.alignment.template.SequencePair;
029import org.biojava.nbio.core.exceptions.CompoundNotFoundException;
030import org.biojava.nbio.core.sequence.DNASequence;
031import org.biojava.nbio.core.sequence.ProteinSequence;
032import org.biojava.nbio.core.sequence.RNASequence;
033import org.biojava.nbio.core.sequence.compound.AminoAcidCompoundSet;
034import org.biojava.nbio.core.sequence.compound.DNACompoundSet;
035import org.biojava.nbio.core.sequence.template.Compound;
036import org.biojava.nbio.core.sequence.template.Sequence;
037import org.slf4j.Logger;
038import org.slf4j.LoggerFactory;
039
040/**
041 * This class models a search Hsp.
042 * You will retrieve a list of this using iterator of a Hit
043 *
044 * Designed by Paolo Pavan.
045 * You may want to find my contacts on Github and LinkedIn for code info
046 * or discuss major changes.
047 * https://github.com/paolopavan
048 *
049 * @author Paolo Pavan
050 */
051
052public abstract class Hsp <S extends Sequence<C>, C extends Compound> {
053        private static final Logger logger = LoggerFactory.getLogger(Hsp.class);
054        private Integer hspNum;
055        private Double hspBitScore;
056        private Integer hspScore;
057        private Double hspEvalue;
058        private Integer hspQueryFrom;
059        private Integer hspQueryTo;
060        private Integer hspHitFrom;
061        private Integer hspHitTo;
062        private Integer hspQueryFrame;
063        private Integer hspHitFrame;
064        private Integer hspIdentity;
065        private Integer hspPositive;
066        private Integer hspGaps;
067        private Integer hspAlignLen;
068        private String hspQseq;
069        private String hspHseq;
070        private String hspIdentityString;
071        private Double percentageIdentity = null;
072        private Integer mismatchCount = null;
073        private SimpleSequencePair<S, C> returnAln;
074
075        @Override
076        public int hashCode() {
077                int hash = 5;
078                hash = 67 * hash + (this.hspQseq != null ? this.hspQseq.hashCode() : 0);
079                hash = 67 * hash + (this.hspHseq != null ? this.hspHseq.hashCode() : 0);
080                hash = 67 * hash + (this.hspIdentityString != null ? this.hspIdentityString.hashCode() : 0);
081                return hash;
082        }
083        /**
084         * Experimental.
085         * Wants to implement conceptual comparisons of search results.
086         * Fields unrelated to search are deliberately not considered.
087         *
088         * In HSP case, alignment representation strings are considered.
089         * @return true if HSP alignments are the same,
090         * false otherwise or if alignment strings are undetermined
091         */
092        @Override
093        public boolean equals(Object obj) {
094                if (obj == null) {
095                        return false;
096                }
097                if (getClass() != obj.getClass()) {
098                        return false;
099                }
100                final Hsp<?, ?> other = (Hsp<?, ?>) obj;
101                if ((this.hspQseq == null) ? (other.hspQseq != null) : !this.hspQseq.equals(other.hspQseq)) {
102                        return false;
103                }
104                if ((this.hspHseq == null) ? (other.hspHseq != null) : !this.hspHseq.equals(other.hspHseq)) {
105                        return false;
106                }
107                if ((this.hspIdentityString == null) ? (other.hspIdentityString != null) : !this.hspIdentityString.equals(other.hspIdentityString)) {
108                        return false;
109                }
110                return true;
111        }
112
113        public SequencePair<S,C> getAlignment(){
114                if (returnAln != null) return returnAln;
115
116                SimpleAlignedSequence<S,C> alignedQuery, alignedHit;
117                // queryFrom e hitTo?
118                int numBefore, numAfter;
119
120                alignedQuery = new SimpleAlignedSequence(getSequence(hspQseq), getAlignmentsSteps(hspQseq));
121                alignedHit = new SimpleAlignedSequence(getSequence(hspHseq), getAlignmentsSteps(hspHseq));
122
123                returnAln = new SimpleSequencePair<S, C>(alignedQuery, alignedHit);
124
125                return returnAln;
126        }
127
128        private Sequence getSequence(String gappedSequenceString){
129                if (gappedSequenceString == null) return null;
130
131                Sequence returnSeq = null;
132                String sequenceString = gappedSequenceString.replace("-", "");
133
134                try {
135                        if (sequenceString.matches("^[ACTG]+$"))
136                                returnSeq = new DNASequence(sequenceString, DNACompoundSet.getDNACompoundSet());
137                        else if (sequenceString.matches("^[ACUG]+$"))
138                                returnSeq = new RNASequence(sequenceString, DNACompoundSet.getDNACompoundSet());
139                        else
140                                returnSeq = new ProteinSequence(sequenceString, AminoAcidCompoundSet.getAminoAcidCompoundSet());
141                } catch (CompoundNotFoundException ex) {
142                        logger.error("Unexpected error, could not find compound when creating Sequence object from Hsp", ex);
143                }
144                return returnSeq;
145        }
146
147        private List<Step> getAlignmentsSteps(String gappedSequenceString){
148                List<Step> returnList = new ArrayList<Step>();
149
150                for (char c: gappedSequenceString.toCharArray()){
151                        if (c=='-') returnList.add(Step.GAP); else returnList.add(Step.COMPOUND);
152                }
153                return returnList;
154        }
155
156        public int getHspNum() {
157                return hspNum;
158        }
159
160        public double getHspBitScore() {
161                return hspBitScore;
162        }
163
164        public int getHspScore() {
165                return hspScore;
166        }
167
168        public double getHspEvalue() {
169                return hspEvalue;
170        }
171
172        public int getHspQueryFrom() {
173                return hspQueryFrom;
174        }
175
176        public int getHspQueryTo() {
177                return hspQueryTo;
178        }
179
180        public int getHspHitFrom() {
181                return hspHitFrom;
182        }
183
184        public int getHspHitTo() {
185                return hspHitTo;
186        }
187
188        public int getHspQueryFrame() {
189                return hspQueryFrame;
190        }
191
192        public int getHspHitFrame() {
193                return hspHitFrame;
194        }
195
196        public int getHspIdentity() {
197                return hspIdentity;
198        }
199
200        public int getHspPositive() {
201                return hspPositive;
202        }
203
204        public int getHspGaps() {
205                return hspGaps;
206        }
207
208        public int getHspAlignLen() {
209                return hspAlignLen;
210        }
211        /**
212         * HSP aligned query sequence string
213         * @return
214         */
215        public String getHspQseq() {
216                return hspQseq;
217        }
218        /**
219         * HSP aligned hit sequence string
220         * @return
221         */
222        public String getHspHseq() {
223                return hspHseq;
224        }
225        /**
226         * Identity string representing correspondence between aligned residues
227         * @return
228         */
229        public String getHspIdentityString() {
230                return hspIdentityString;
231        }
232
233        public Double getPercentageIdentity() {
234                if (percentageIdentity != null) return percentageIdentity;
235                if (hspIdentity!= null && hspAlignLen != null) return (double)hspIdentity/hspAlignLen;
236                return null;
237        }
238
239        public Integer getMismatchCount() {
240                if (mismatchCount != null) return mismatchCount;
241                if (hspIdentity!= null && hspAlignLen != null) return hspIdentity-hspAlignLen;
242                return null;
243        }
244
245        public Hsp(int hspNum, double hspBitScore, int hspScore, double hspEvalue, int hspQueryFrom, int hspQueryTo, int hspHitFrom, int hspHitTo, int hspQueryFrame, int hspHitFrame, int hspIdentity, int hspPositive, int hspGaps, int hspAlignLen, String hspQseq, String hspHseq, String hspIdentityString, Double percentageIdentity, Integer mismatchCount) {
246                this.hspNum = hspNum;
247                this.hspBitScore = hspBitScore;
248                this.hspScore = hspScore;
249                this.hspEvalue = hspEvalue;
250                this.hspQueryFrom = hspQueryFrom;
251                this.hspQueryTo = hspQueryTo;
252                this.hspHitFrom = hspHitFrom;
253                this.hspHitTo = hspHitTo;
254                this.hspQueryFrame = hspQueryFrame;
255                this.hspHitFrame = hspHitFrame;
256                this.hspIdentity = hspIdentity;
257                this.hspPositive = hspPositive;
258                this.hspGaps = hspGaps;
259                this.hspIdentity = hspAlignLen;
260                this.hspQseq = hspQseq;
261                this.hspHseq = hspHseq;
262                this.hspIdentityString = hspIdentityString;
263                this.percentageIdentity = percentageIdentity;
264                this.mismatchCount = mismatchCount;
265
266                // sanity check
267                if (percentageIdentity != null && (percentageIdentity < 0 || percentageIdentity >1))
268                        throw new IllegalArgumentException("Percentage identity must be between 0 and 1");
269
270        }
271
272}