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.search;
023
024import org.biojava.bio.Annotatable;
025import org.biojava.bio.Annotation;
026import org.biojava.bio.alignment.Alignment;
027import org.biojava.bio.seq.StrandedFeature.Strand;
028import org.biojava.utils.AbstractChangeable;
029import org.biojava.utils.ChangeForwarder;
030import org.biojava.utils.ChangeListener;
031import org.biojava.utils.ChangeSupport;
032import org.biojava.utils.ChangeType;
033import org.biojava.utils.ObjectUtil;
034
035/**
036 * <p><code>SequenceDBSearchSubHit</code> objects represent sub-hits
037 * which make up a hit. In the case of Blast these correspond to
038 * HSPs.</p>
039 *
040 * @author Keith James
041 * @since 1.1
042 * @deprecated SimpleSeqSimilaritySearchSubHit has been made
043 * Annotatable and is now functionally identical.
044 * @see SeqSimilaritySearchSubHit
045 */
046public class SequenceDBSearchSubHit  extends AbstractChangeable
047    implements SeqSimilaritySearchSubHit
048{
049    protected transient ChangeForwarder annotationForwarder;
050
051    private double     score;
052    private double     pValue;
053    private double     eValue;
054    private int        queryStart;
055    private int        queryEnd;
056    private Strand     queryStrand;
057    private int        subjectStart;
058    private int        subjectEnd;
059    private Strand     subjectStrand;
060    private Alignment  alignment;
061    private Annotation annotation;
062
063    // Hashcode is cached after first calculation because the data on
064    // which is is based do not change
065    private int hc;
066    private boolean hcCalc;
067
068    /**
069     * Creates a new <code>SequenceDBSearchSubHit</code> object.
070     *
071     * @param queryStart an <code>int</code> value indicating the
072     * start coordinate of the hit on the query sequence.
073     * @param queryEnd an <code>int</code> value indicating the end
074     * coordinate of the hit on the query sequence.
075     * @param queryStrand a <code>Strand</code> object indicating the
076     * strand of the hit with respect to the query sequence, which may
077     * be null for protein similarities.
078     * @param subjectStart an <code>int</code> value indicating the
079     * start coordinate of the hit on the subject sequence.
080     * @param subjectEnd an <code>int</code> value indicating the end
081     * coordinate of the hit on the query sequence.
082     * @param subjectStrand a <code>Strand</code> object indicating
083     * the strand of the hit with respect to the query sequence, which
084     * may be null for protein similarities.
085     * @param score a <code>double</code> value; the score of the
086     * subhit, which may not be NaN.
087     * @param eValue a <code>double</code> the E-value of the
088     * subhit, which may be NaN.
089     * @param pValue a <code>double</code> value; the P-value of the
090     * hit, which may be NaN.
091     * @param alignment an <code>Alignment</code> object containing
092     * the alignment described by the subhit region, which may not be
093     * null.
094     * @param annotation an <code>Annotation</code> object, which may
095     * not be null.
096     */
097    public SequenceDBSearchSubHit(double    score,
098                                  double    eValue,
099                                  double    pValue,
100                                  int       queryStart,
101                                  int       queryEnd,
102                                  Strand    queryStrand,
103                                  int       subjectStart,
104                                  int       subjectEnd,
105                                  Strand    subjectStrand,
106                                  Alignment alignment,
107                                  Annotation annotation)
108    {
109        if (Double.isNaN(score))
110        {
111            throw new IllegalArgumentException("score was NaN");
112        }
113
114        // pValue may be NaN
115        // eValue may be NaN
116        if (alignment == null)
117        {
118            throw new IllegalArgumentException("alignment was null");
119        }
120
121        if (annotation == null)
122        {
123            throw new IllegalArgumentException("annotation was null");
124        }
125
126        this.score         = score;
127        this.eValue        = eValue;
128        this.pValue        = pValue;
129        this.queryStart    = queryStart;
130        this.queryEnd      = queryEnd;
131        this.queryStrand   = queryStrand;
132        this.subjectStart  = subjectStart;
133        this.subjectEnd    = subjectEnd;
134        this.subjectStrand = subjectStrand;
135        this.alignment     = alignment;
136        this.annotation    = annotation;
137
138        // Lock alignment by vetoing all changes
139        this.alignment.addChangeListener(ChangeListener.ALWAYS_VETO);
140
141        // Lock the annotation by vetoing all changes to properties
142        annotation.addChangeListener(ChangeListener.ALWAYS_VETO);
143
144        hcCalc = false;
145    }
146
147    public double getScore()
148    {
149        return score;
150    }
151
152    public double getPValue()
153    {
154        return pValue;
155    }
156
157    public double getEValue()
158    {
159        return eValue;
160    }
161
162    public int getQueryStart()
163    {
164        return queryStart;
165    }
166
167    public int getQueryEnd()
168    {
169        return queryEnd;
170    }
171
172    public Strand getQueryStrand()
173    {
174        return queryStrand;
175    }
176
177    public int getSubjectStart()
178    {
179        return subjectStart;
180    }
181
182    public int getSubjectEnd()
183    {
184        return subjectEnd;
185    }
186
187    public Strand getSubjectStrand()
188    {
189        return subjectStrand;
190    }
191
192    public Alignment getAlignment()
193    {
194        return alignment;
195    }
196
197    public Annotation getAnnotation()
198    {
199        return annotation;
200    }
201
202    public boolean equals(Object other)
203    {
204        if (other == this) return true;
205        if (other == null) return false;
206
207        if (! other.getClass().equals(this.getClass())) return false;
208
209        SequenceDBSearchSubHit that = (SequenceDBSearchSubHit) other;
210
211        if (! ObjectUtil.equals(this.score, that.score))
212            return false;
213        if (! ObjectUtil.equals(this.pValue, that.pValue))
214            return false;
215        if (! ObjectUtil.equals(this.eValue, that.eValue))
216            return false;
217        if (! ObjectUtil.equals(this.queryStart, that.queryStart))
218            return false;
219        if (! ObjectUtil.equals(this.queryEnd, that.queryEnd))
220            return false;
221        if (! ObjectUtil.equals(this.queryStrand, that.queryStrand))
222            return false;
223        if (! ObjectUtil.equals(this.subjectStart, that.subjectStart))
224            return false;
225        if (! ObjectUtil.equals(this.subjectEnd, that.subjectEnd))
226            return false;
227        if (! ObjectUtil.equals(this.subjectStrand, that.subjectStrand))
228            return false;
229        if (! ObjectUtil.equals(this.annotation, that.annotation))
230            return false;
231
232        return true;
233    }
234  
235    public int hashCode()
236    {
237        if (! hcCalc)
238        {
239            hc = ObjectUtil.hashCode(hc, score);
240            hc = ObjectUtil.hashCode(hc, pValue);
241            hc = ObjectUtil.hashCode(hc, eValue);
242            hc = ObjectUtil.hashCode(hc, queryStart);
243            hc = ObjectUtil.hashCode(hc, queryEnd);
244            hc = ObjectUtil.hashCode(hc, queryStrand);
245            hc = ObjectUtil.hashCode(hc, subjectStart);
246            hc = ObjectUtil.hashCode(hc, subjectEnd);
247            hc = ObjectUtil.hashCode(hc, subjectStrand);
248            hc = ObjectUtil.hashCode(hc, annotation);
249            hcCalc = true;
250        }
251
252        return hc;
253    }
254
255    public String toString()
256    {
257        return "SequenceDBSearchSubHit with score " + getScore();
258    }
259
260    protected ChangeSupport getChangeSupport(ChangeType ct)
261    {
262        ChangeSupport cs = super.getChangeSupport(ct);
263
264        if (annotationForwarder == null &&
265            (ct.isMatchingType(Annotatable.ANNOTATION) || Annotatable.ANNOTATION.isMatchingType(ct)))
266        {
267            annotationForwarder =
268                new ChangeForwarder.Retyper(this, cs, Annotation.PROPERTY);
269            getAnnotation().addChangeListener(annotationForwarder,
270                                              Annotatable.ANNOTATION);
271        }
272
273        return cs;
274    }
275}