001    /*
002     * Copyright 2007, 2012 Stephen Fisher and Junhyong Kim, University of
003     * Pennsylvania.
004     *
005     * This file is part of Glo-DB.
006     * 
007     * Glo-DB is free software: you can redistribute it and/or modify it
008     * under the terms of the GNU General Public License as published by
009     * the Free Software Foundation, either version 3 of the License, or
010     * (at your option) any later version.
011     * 
012     * Glo-DB is distributed in the hope that it will be useful, but
013     * WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015     * General Public License for more details.
016     * 
017     * You should have received a copy of the GNU General Public License
018     * along with Glo-DB. If not, see <http://www.gnu.org/licenses/>.
019     *
020     * @(#)AbstractFeature.java
021     */
022    
023    package edu.upenn.gloDB;
024    
025    import java.util.HashMap;
026    import java.util.Iterator;
027    
028    /**
029     * AbstractFeature.
030     *
031     * @author  Stephen Fisher
032     * @version $Id: AbstractFeature.java,v 1.1.2.10 2007/03/01 21:17:32 fisher Exp $
033     */
034    
035    public abstract class AbstractFeature implements Feature {
036    
037             /** The contig that underlies the positions. */
038             protected String source;
039    
040             /** 
041              * This is similar to "qualifiers" in GenBank.  ex: scores, strand
042              * (+/-), phase (within codon).  Each key/value pair is delimited
043              * by a ";".  the keys and values are separated by "=". ex:
044              * "scores=.; strand=+". Key based attribute searches are case
045              * sensitive.
046              * @XXX Should any of these be hardcoded as fields?
047              */
048             //      protected HashMap attributes = new HashMap();
049             protected String attributes = "";
050    
051    
052             /** 
053              * Set the source when the Feature is created.  Don't allow the
054              * source to change there after.
055              * @XXX Should throw an exception if source is null.
056              */
057             public AbstractFeature(Sequence source) { 
058                      if (source == null) {
059                                    GloDBUtils.printMsg("No sequence info for feature.", 2); // error
060                      }
061                      this.source = source.getID();
062             }
063    
064    
065        //--------------------------------------------------------------------------
066        // Setters and Getters
067       
068             /** Returns Feature type (see GloDBUtils) */
069             public int getType() { return GloDBUtils.FEATURE; }
070    
071        /** 
072              * Set the attributes. 
073              * @param attributes a String of Feature attributes
074              */
075        public void setAttributes(String attributes) { 
076                      // make sure attributes is never set to null
077                      if (GloDBUtils.isEmpty(attributes)) attributes = "";
078                      this.attributes = attributes; 
079             }
080    
081        /** 
082              * Set the attributes using a HashMap. 
083              * @param attribMap a HashMap of Feature attributes
084              */
085        public void setAttributes(HashMap attribMap) { 
086                      // test for null or empty maps
087                      if ((attribMap == null) || (attribMap.isEmpty())) {
088                                    this.attributes = "";
089                                    return;
090                      }
091                      
092                      Iterator keys = attribMap.keySet().iterator();
093                      String key = (String) keys.next();
094                      String value = (String) attribMap.get(key);
095                      String attribs = key + "=" + value;
096    
097                      while (keys.hasNext()) {
098                                    key = (String) keys.next();
099                                    value = (String) attribMap.get(key);
100                                    attribs += ";" + key + "=" + value;
101                      }
102    
103                      this.attributes = attribs; 
104             }
105    
106        /** Get the attributes. */
107        public String getAttributes() { return attributes; }
108             //    public HashMap getAttributes() { return attributes; }
109    
110        /** 
111              * Returns the underlying Sequence object. 
112              * @return Returns the sequence object.
113              */
114        public Sequence getSource() { return ObjectHandles.getSequence(source); }
115    
116             /** Returns the underlying Sequence object's ID. */
117             public String getSourceID() { return source; }
118    
119        //--------------------------------------------------------------------------
120        // Miscellaneous Methods
121       
122        /** Add an attribute. */
123        public void addAttribute(String key, String value) { 
124                      if (GloDBUtils.isEmpty(attributes)) attributes += key + "=" + value; 
125                      else attributes += ";" + key + "=" + value; 
126             }
127    
128        /** Add an attribute (key/value pair). */
129        public void addAttribute(String value) { 
130                      if (GloDBUtils.isEmpty(attributes)) attributes += value; 
131                      else attributes += ";" + value; 
132             }
133             
134        /** Remove an attribute. This is case sensitive. */
135        public void delAttribute(String key) { 
136                      if (GloDBUtils.isEmpty(attributes)) return;
137    
138                      String[] pairs = attributes.split(";");
139                      String newAttribs = "";
140                      
141                      for (int i = 0; i < pairs.length; i++) {
142                                    if (! pairs[i].startsWith(key)) {
143                                             if (i == 0) newAttribs += pairs[i];
144                                             else newAttribs += ";" + pairs[i];
145                                    }
146                      }
147                     
148                      this.attributes = newAttribs;
149             }
150    
151        /** Returns true if attribute 'key' exists. This is case sensitive. */
152        public boolean containsAttribute(String key) { 
153                      return attributes.matches(".*key\\s?=.+"); 
154             }
155    
156        /** 
157              * Get the attributes as HashMap. If no attributes, then an empty
158              * HashMap is returned. 
159              */
160             public HashMap getAttributesMap() { 
161                      if (GloDBUtils.isEmpty(attributes)) return new HashMap();
162    
163                      String[] pairs = attributes.split(";");
164    
165                      HashMap attribMap = new HashMap();
166                      for (int i = 0; i < pairs.length; i++) {
167                                    String[] keyVal = pairs[i].split("=");
168                                    if (keyVal.length == 1) {
169                                             // this should never happen
170                                             attribMap.put(keyVal[0], keyVal[0]);
171                                             GloDBUtils.printWarning("Found potentially invalid Feature attributes (" + keyVal[0] + ") in " + attributes);
172                                    } else {
173                                             attribMap.put(keyVal[0], keyVal[1]);
174                                    }
175                      }
176    
177                      return attribMap; 
178             }
179    
180        /** Get value for attribute 'key'. This is case sensitive. */
181        public String getAttribute(String key) { 
182                      if (GloDBUtils.isEmpty(attributes)) return "";
183    
184                      String[] pairs = attributes.split(";");
185                      
186                      for (int i = 0; i < pairs.length; i++) {
187                                    if (pairs[i].startsWith(key)) {
188                                             return pairs[i].split("=")[1];
189                                    }
190                      }
191    
192                      return "";
193             }
194    
195             /** Returns description and Feature information. */
196             public String toString() {
197                      String out = "";
198    
199                      // will convert itself to a string
200                      if (attributes == null) {
201                                    out += "Attributes: none";  
202                      } else {
203                                    out += "Attributes:\n  " + attributes;  
204                      }
205                      out += "\nSource:  " + source + "\n";
206    
207                      return out;
208             }
209            
210    } // AbstractxFeature.java