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.biojavax;
023
024
025import org.biojava.bio.seq.io.ParseException;
026import org.biojava.utils.AbstractChangeable;
027import org.biojava.utils.ChangeEvent;
028import org.biojava.utils.ChangeSupport;
029import org.biojava.utils.ChangeVetoException;
030import org.biojavax.bio.seq.RichLocation;
031import org.biojavax.bio.seq.SimplePosition;
032import org.biojavax.bio.seq.SimpleRichLocation;
033import org.biojavax.bio.seq.io.GenbankLocationParser;
034
035/**
036 * Represents a documentary reference. 
037 * @author Richard Holland
038 * @author gwaldon
039 * @since 1.5
040 */
041public class SimpleRankedDocRef extends AbstractChangeable implements RankedDocRef {
042    
043    private DocRef docref;
044    private Integer start;
045    private Integer end;
046    private RichLocation location;
047    private int rank;
048    
049    /**
050     * Constructs a new docref for a given location. If one or the other
051     * of start and end are null, only the non-null value is used. If both
052     * are null, no value is used for the location. 
053     * @param docref the document reference. Must not be null.
054     * @param start the start position of the location. 
055     * @param end the end position of the location.
056     */
057    public SimpleRankedDocRef(DocRef docref, Integer start, Integer end, int rank) {
058        if (docref==null) throw new IllegalArgumentException("Document reference cannot be null");
059        this.docref = docref;
060        this.setStart(start);
061        this.setEnd(end);
062        this.rank = rank;
063    }
064    
065    /**
066     * Constructs a new docref for a given location.
067     * @param docref the document reference. Must not be null.
068     * @param location the position of the document reference. Must not be null.
069     */
070    public SimpleRankedDocRef(DocRef docref, RichLocation location, int rank) {
071        if (docref==null) throw new IllegalArgumentException("Document reference cannot be null");
072        this.docref = docref;
073        this.makeLocation(location);
074        this.rank = rank;
075    }
076    
077    // Hibernate requirement - not for public use.
078    protected SimpleRankedDocRef() {}
079    
080    /**
081     * {@inheritDoc}
082     */
083    public void setRank(int rank)  throws ChangeVetoException {
084        if(rank==this.rank)
085            return;
086        if(!this.hasListeners(RankedDocRef.RANK)) {
087            this.rank = rank;
088        } else {
089            ChangeEvent ce = new ChangeEvent(
090                    this,
091                    RankedDocRef.RANK,
092                    new Integer(rank),
093                    new Integer(this.rank)
094                    );
095            ChangeSupport cs = this.getChangeSupport(RankedDocRef.RANK);
096            synchronized(cs) {
097                cs.firePreChangeEvent(ce);
098                this.rank = rank;
099                cs.firePostChangeEvent(ce);
100            }
101        }
102    }
103    
104    /**
105     * {@inheritDoc}
106     */
107    public int getRank() { return this.rank; }
108    
109    /**
110     * {@inheritDoc}
111     */
112    public DocRef getDocumentReference() { return this.docref; }
113    
114    /**
115     * {@inheritDoc}
116     */
117    public Integer getStart() { return this.start; }
118    
119    /**
120     * {@inheritDoc}
121     */
122    public Integer getEnd() { return this.end; }
123    
124    // Hibernate requirement - not for public use.
125    void setDocumentReference(DocRef docref) { this.docref = docref; }
126        
127    // Hibernate requirement - not for public use.
128    private void setStart(Integer start) { 
129        this.start = start; 
130        this.createLocation();
131        }
132    
133    // Hibernate requirement - not for public use.
134    private void setEnd(Integer end) { 
135        this.end = end; 
136        this.createLocation();
137        }
138    
139    // Internal use only.
140    private void createLocation() {
141        if (this.start==null && this.end==null) location = RichLocation.EMPTY_LOCATION;
142        else if (this.start==null) location = new SimpleRichLocation(null, new SimplePosition(this.end.intValue()), 0);
143        else if (this.end==null) location = new SimpleRichLocation(new SimplePosition(this.start.intValue()), null, 0);
144        else location = new SimpleRichLocation(new SimplePosition(this.start.intValue()), new SimplePosition(this.end.intValue()), 0);
145    }
146    
147    // Internal use only.
148    private void makeLocation(RichLocation location) {
149        if (location==null) 
150            throw new IllegalArgumentException("Document location cannot be null");
151        this.location = location;
152        this.start = new Integer(location.getMin());
153        this.end = new Integer(location.getMax());
154    }
155    
156    /**
157     * {@inheritDoc}
158     */
159    public void setLocation(RichLocation location)  throws ChangeVetoException {
160        if(!this.hasListeners(RankedDocRef.LOCATION)) {
161            makeLocation(location);
162        } else {
163            ChangeEvent ce = new ChangeEvent(
164                    this,
165                    RankedDocRef.LOCATION,
166                    location,
167                    this.location
168                    );
169            ChangeSupport cs = this.getChangeSupport(RankedDocRef.LOCATION);
170            synchronized(cs) {
171                cs.firePreChangeEvent(ce);
172                makeLocation(location);
173                cs.firePostChangeEvent(ce);
174            }
175        }
176    }
177    
178    public RichLocation getLocation() {
179        return this.location;
180    }
181    
182    // Internal use only.
183    final void setLocationText(final String theLocation) throws ParseException {
184        if (theLocation == null) {
185                makeLocation(RichLocation.EMPTY_LOCATION);
186        } else {
187                final RichLocation location = GenbankLocationParser.parseLocation(RichObjectFactory.getDefaultNamespace(), null, theLocation);
188                makeLocation(location);
189        }
190    }
191    
192    // Internal use only.
193    final String getLocationText() {
194        return  getLocation() == RichLocation.EMPTY_LOCATION?null:GenbankLocationParser.writeLocation(getLocation());
195    }
196    
197   /**
198     * {@inheritDoc}
199     * Two ranked document references are equal if they have the same rank 
200     * and refer to the same location and same document reference.
201     */
202    public boolean equals(Object obj) {
203        if (this == obj) return true;
204        if (obj==null || !(obj instanceof RankedDocRef)) return false;
205        // Hibernate comparison - we haven't been populated yet
206        if (this.docref==null) return false;
207        // Normal comparison
208        RankedDocRef them = (RankedDocRef)obj;
209        return (this.rank==them.getRank() &&
210                        this.location.equals(them.getLocation()) && 
211                this.docref.equals(them.getDocumentReference()));
212    }
213    
214    /**
215     * {@inheritDoc}
216     * Ranked document references are sorted first by rank then location
217     * then by actual document reference.
218     */
219    public int compareTo(Object o) {
220        if (o==this) return 0;
221        // Hibernate comparison - we haven't been populated yet
222        if (this.docref==null) return -1;
223        // Normal comparison
224        RankedDocRef them = (RankedDocRef)o;
225        if (this.rank!=them.getRank()) return this.rank - them.getRank();
226        if (!this.location.equals(them.getLocation())) return this.location.compareTo(them.getLocation());
227        return this.docref.compareTo(them.getDocumentReference());
228    }
229    
230    /**
231     * {@inheritDoc}
232     */
233    public int hashCode() {
234        int code = 17;
235        // Hibernate comparison - we haven't been populated yet
236        if (this.docref==null) return code;
237        // Normal comparison
238        code = 37*code + this.docref.hashCode();
239        code = 37*code + this.location.hashCode();
240        code = 37*code + this.rank;
241        return code;
242    }
243        
244    /**
245     * {@inheritDoc}
246     * Form: "(#rank) docref"
247     */
248    public String toString() {
249        return "(#"+this.rank+") "+this.docref;
250    }
251}
252
253
254