001package org.biojava.bio.annodb;
002
003import java.util.ArrayList;
004import java.util.Iterator;
005import java.util.List;
006import java.util.NoSuchElementException;
007
008import org.biojava.bio.AnnotationTools;
009import org.biojava.bio.AnnotationType;
010
011/**
012 * <p>An AnnotationDB that provides a merged view of a list of underlying DBs.</p>
013 *
014 * @author Matthew Pocock
015 * @since 1.3
016 */
017public class MergingAnnotationDB implements AnnotationDB {
018  private final String name;
019  private final List merged;
020
021  /**
022   * Create a new MergingAnnotationDB with a name and no DBs to merge.
023   *
024   * @param name  the name of this DB
025   */
026  public MergingAnnotationDB(String name) {
027    this.name = name;
028    this.merged = new ArrayList();
029  }
030
031  /**
032   * Create a new MergingAnnotationDB with a name and a list of DBs to merge.
033   *
034   * @param name    the name of this DB
035   * @param merged  a list of DBs to merge
036   */
037  public MergingAnnotationDB(String name, List merged) {
038    this.name = name;
039    this.merged = new ArrayList(merged);
040  }
041
042  /**
043   * Add a DB to be merged in this view.
044   *
045   * @param toAdd the AnnotationDB to add
046   */
047  public void addAnnotationDB(AnnotationDB toAdd) {
048    if(!merged.contains(toAdd)) {
049      merged.add(toAdd);
050    }
051  }
052
053  /**
054   * Remove a DB from this view.
055   *
056   * @param toRemove  the AnnotationDB to remove
057   */
058  public void removeAnnotationDB(AnnotationDB toRemove) {
059    merged.remove(toRemove);
060  }
061
062  /**
063   * Return a list of merged DBs. This can be modified independantly of this DB.
064   *
065   * @return a List of merged DBs
066   */
067  public List getMerged() {
068    return new ArrayList(merged);
069  }
070  
071  public String getName() {
072    return name;
073  }
074  
075  public AnnotationType getSchema() {
076    AnnotationType schema = AnnotationType.NONE;
077    
078    for(Iterator i = merged.iterator(); i.hasNext(); ) {
079      AnnotationDB db = (AnnotationDB) i.next();
080      schema = AnnotationTools.union(schema, db.getSchema());
081    }
082    
083    return schema;
084  }
085
086  public Iterator iterator() {
087    return new Iterator() {
088      Iterator ii;
089      Iterator ci;
090      Object item;
091      
092      {
093        ii = merged.iterator();
094       EVERYTHING:
095        while(item == null) {
096          if(ii.hasNext()) {
097            AnnotationDB adb = (AnnotationDB) ii.next();
098            ci = adb.iterator();
099            if(ci.hasNext()) {
100              item = ci.next();
101            }
102          } else {
103            break EVERYTHING;
104          }
105        }
106      }
107      
108      public boolean hasNext() {
109        return item != null;
110      }
111      
112      public Object next() {
113        Object it = item;
114        item = _next();
115        return it;
116      }
117      
118      private Object _next() {
119        while(!ci.hasNext()) {
120          if(ii.hasNext()) {
121            AnnotationDB adb = (AnnotationDB) ii.next();
122            ci = adb.iterator();
123          } else {
124            return null;
125          }
126        }
127        
128        return ci.next();
129      }
130      
131      public void remove() {
132        throw new NoSuchElementException();
133      }
134    };
135  }
136  
137  public int size() {
138    int size = 0;
139    
140    for(Iterator dbi = merged.iterator(); dbi.hasNext(); ) {
141      size += ((AnnotationDB) dbi.next()).size();
142    }
143    
144    return size;
145  }
146  
147  public AnnotationDB filter(AnnotationType at) {
148    List anns = new ArrayList();
149    
150    for(Iterator i = merged.iterator(); i.hasNext(); ) {
151      AnnotationDB adb = (AnnotationDB) i.next();
152      AnnotationDB res = adb.filter(at);
153      if(res.size() > 0) {
154        anns.add(res);
155      }
156    }
157    
158    if(anns.isEmpty()) {
159      return AnnotationDB.EMPTY;
160    } else if(anns.size() == 1) {
161      return (AnnotationDB) anns.get(0);
162    } else {
163      return new MergingAnnotationDB("", anns);
164    }
165  }
166  
167  public AnnotationDB search(AnnotationType at) {
168    List anns = new ArrayList();
169    
170    for(Iterator i = merged.iterator(); i.hasNext(); ) {
171      AnnotationDB adb = (AnnotationDB) i.next();
172      AnnotationDB res = adb.search(at);
173      if(res.size() > 0) {
174        anns.add(res);
175      }
176    }
177    
178    if(anns.isEmpty()) {
179      return AnnotationDB.EMPTY;
180    } else if(anns.size() == 1) {
181      return (AnnotationDB) anns.get(0);
182    } else {
183      return new MergingAnnotationDB("", anns);
184    }
185  }
186}
187