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    
023    package org.biojava3.core.sequence.features;
024    
025    import java.util.ArrayList;
026    import java.util.Comparator;
027    import java.util.List;
028    import org.biojava3.core.sequence.location.SequenceLocation;
029    import org.biojava3.core.sequence.template.AbstractSequence;
030    import org.biojava3.core.sequence.template.Compound;
031    
032    /**
033     * A feature is currently any descriptive item that can be associated with a sequence position(s)
034     * A feature has a type and a source which is currently a string to allow flexibility for the user
035     * Ideally well defined features should have a class to describe attributes of that feature
036     * @author Scooter Willis <willishf at gmail dot com>
037     */
038    public abstract class AbstractFeature<S extends AbstractSequence<C>, C extends Compound>
039            implements FeatureInterface<S, C> {
040        List<FeatureInterface<S, C>> childrenFeatures = new ArrayList<FeatureInterface<S, C>>();
041        FeatureInterface<S, C> parentFeature;
042        SequenceLocation<S, C> sequenceLocation;
043        String type = "";
044        String source = "";
045        private String description = "";
046        private String shortDescription = "";
047        private Object userObject = null;
048    
049        /**
050         * A feature has a type and a source
051         * @param type
052         * @param source
053         */
054        public AbstractFeature(String type,String source){
055            this.type = type;
056            this.source = source;
057        }
058    
059        /**
060         * A feature could be a single sequence position like a mutation or a post translational modification of an amino acid.
061         * It could also be the docking interface of N number of amino acids on the surface. The location wold then be a collection
062         * of sequence positions instead of a single sequence position or the begin and end of a sequence seqment.
063         * @return
064         */
065    
066        @Override
067        public SequenceLocation<S, C> getLocations() {
068            return sequenceLocation;
069        }
070    
071        /**
072         *  A feature could be a single sequence position like a mutation or a post translational modification of an amino acid.
073         * It could also be the docking interface of N number of amino acids on the surface. The location wold then be a collection
074         * of sequence positions instead of a single sequence position or the begin and end of a sequence seqment.
075         * @param loc
076         */
077        @Override
078        public void setLocation(SequenceLocation<S, C> loc) {
079            sequenceLocation = loc;
080        }
081    
082        /**
083         * The feature type
084         * @return
085         */
086        @Override
087        public String getType() {
088            return type;
089        }
090    
091        /**
092         * Set the feature type
093         * @param type
094         */
095        @Override
096        public void setType(String type) {
097            this.type = type;
098        }
099    
100        /**
101         * The feature source
102         * @return
103         */
104    
105        @Override
106        public String getSource() {
107            return source;
108        }
109    
110        /**
111         * Set the feature source
112         * @param source
113         */
114        @Override
115        public void setSource(String source) {
116            this.source = source;
117        }
118    
119        /**
120         * A feature can be the child or contained by a parent feature. An example is a Helix feature could contain
121         * children features. A PFAM domain could contain secondary structures.
122         * @param feature
123         */
124        @Override
125        public void setParentFeature(FeatureInterface<S, C> feature) {
126            parentFeature = feature;
127        }
128    
129        /**
130         * Get the parent Feature
131         * @return
132         */
133        @Override
134        public FeatureInterface<S, C> getParentFeature() {
135           return parentFeature;
136        }
137    
138        /**
139         * Get the children features
140         * @return
141         */
142        @Override
143        public List<FeatureInterface<S, C>> getChildrenFeatures() {
144            return childrenFeatures;
145        }
146    
147        /**
148         * Set the children features
149         * @param features
150         */
151        @Override
152        public void setChildrenFeatures(List<FeatureInterface<S, C>> features) {
153            childrenFeatures = features;
154    
155        }
156    
157        /**
158         * @return the description
159         */
160        public String getDescription() {
161            return description;
162        }
163    
164        /**
165         * @param description the description to set
166         */
167        public void setDescription(String description) {
168            this.description = description;
169        }
170    
171        /**
172         * @return the shortDescription
173         */
174        public String getShortDescription() {
175            return shortDescription;
176        }
177    
178        /**
179         * @param shortDescription the shortDescription to set
180         */
181        public void setShortDescription(String shortDescription) {
182            this.shortDescription = shortDescription;
183        }
184    
185        /**
186         * Sort features by start position and then longest length. When features are added
187         * having them sorted by start position and then longest length helps on the layout
188         * of overlapping features so they are delivered in a proper order.
189         */
190    
191        public static final Comparator<FeatureInterface<?, ?>> LOCATION_LENGTH = new Comparator<FeatureInterface<?, ?>>() {
192    
193            public int compare(FeatureInterface<?, ?> e1, FeatureInterface<?, ?> e2) {
194                double v1 = e1.getLocations().getStart().getPosition();
195                double v2 = e2.getLocations().getStart().getPosition();
196                if (v1 < v2) {
197                    return -1;
198                } else if (v1 > v2) {
199                    return 1;
200                } else {
201                    double end1 = e1.getLocations().getEnd().getPosition();
202                    double end2 = e2.getLocations().getEnd().getPosition();
203                    if(end1 > end2)
204                        return -1;
205                    else if(end1 < end2)
206                        return 1;
207                    else
208                    return 0;
209                }
210    
211            }
212        };
213    
214         /**
215         * Sort features by length. //TODO need to handle cases where features have multiple locations, strand etc
216         *
217         */
218    
219        static public final Comparator<FeatureInterface<?, ?>> LENGTH = new Comparator<FeatureInterface<?, ?>>() {
220    
221            public int compare(FeatureInterface<?, ?> e1, FeatureInterface<?, ?> e2) {
222                double v1 = Math.abs(e1.getLocations().getEnd().getPosition()- e1.getLocations().getStart().getPosition());
223                double v2 = Math.abs(e2.getLocations().getEnd().getPosition() -  e2.getLocations().getStart().getPosition());
224                if (v1 < v2) {
225                    return -1;
226                } else if (v1 > v2) {
227                    return 1;
228                } else {
229                    return 0;
230                }
231    
232            }
233        };
234    
235        /**
236         * @return the userObject
237         */
238        public Object getUserObject() {
239            return userObject;
240        }
241    
242        /**
243         * Allow the user to associate an object with the feature. This way if a feature which is displayed in a GUI
244         * is clicked on the application can then get a user defined object associated with the feature.
245         * @param userObject the userObject to set
246         */
247        public void setUserObject(Object userObject) {
248            this.userObject = userObject;
249        }
250    
251    }