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
022
023package org.biojava.bio.symbol;
024
025import java.io.Serializable;
026import java.util.HashSet;
027import java.util.Iterator;
028import java.util.List;
029import java.util.Set;
030
031import org.biojava.bio.Annotatable;
032import org.biojava.bio.Annotation;
033import org.biojava.bio.SimpleAnnotation;
034import org.biojava.utils.ChangeEvent;
035import org.biojava.utils.ChangeForwarder;
036import org.biojava.utils.ChangeSupport;
037import org.biojava.utils.ChangeType;
038import org.biojava.utils.ChangeVetoException;
039import org.biojava.utils.SingletonList;
040
041/**
042 * A simple no-frills implementation of the FiniteAlphabet interface.
043 *
044 * @serial WARNING the serialized version of this class may not be compatible with future versions
045 * @author Matthew Pocock
046 */
047public class SimpleAlphabet
048extends AbstractAlphabet
049implements Serializable {
050  private String name;
051  private Annotation annotation;
052  private final Set symbols;
053  protected transient ChangeForwarder annotationForwarder;
054
055    //BE SURE TO CHANGE THIS VALUE IF YOU CHANGE THE IMPLEMENTATION
056    //SUCH THAT SERIALIZATION WILL FAIL.
057  private static final long serialVersionUID = 216254146;
058
059  /**
060   * A list of alphabets that make up this one - a singleton list containing
061   * this.
062   */
063  private List alphabets;
064
065  public Iterator iterator() {
066    return symbols.iterator();
067  }
068
069  public String getName() {
070    return name;
071  }
072
073  /**
074   * Assign a name to the alphabet
075   * @param name the name you wish to give this alphabet
076   */
077  public void setName(String name) {
078    this.name = name;
079  }
080
081  public Annotation getAnnotation() {
082    if(annotation == null)
083      annotation = new SimpleAnnotation();
084    return annotation;
085  }
086
087  public int size() {
088    return symbols.size();
089  }
090
091  protected boolean containsImpl(AtomicSymbol s) {
092    return symbols.contains(s);
093  }
094
095  protected void addSymbolImpl(AtomicSymbol s)
096  throws IllegalSymbolException, ChangeVetoException {
097    symbols.add(s);
098  }
099
100  public void removeSymbol(Symbol s)
101  throws IllegalSymbolException {
102    validate(s);
103    //change checking should probably happen in AbstractAlphabet but oh well.
104    if(hasListeners(Alphabet.SYMBOLS)) {
105      ChangeSupport cs = getChangeSupport(Alphabet.SYMBOLS);
106      synchronized(cs) {
107        ChangeEvent ce = new ChangeEvent(this, Alphabet.SYMBOLS, null, s);
108        cs.firePreChangeEvent(ce);
109        _removeSymbol(s);
110        cs.firePostChangeEvent(ce);
111      }
112    }else{
113        _removeSymbol(s);
114    }
115  }
116
117    private void _removeSymbol(final Symbol s) {
118        
119        if(s instanceof AtomicSymbol) {
120          symbols.remove(s);
121        } else {
122          FiniteAlphabet sa = (FiniteAlphabet) s.getMatches();
123          Iterator i = sa.iterator();
124          while(i.hasNext()) {
125            Symbol sym = (Symbol) i.next();
126            symbols.remove(sym);
127          }
128        }
129    }
130
131  public List getAlphabets() {
132    if(this.alphabets == null) {
133      this.alphabets = new SingletonList(this);
134    }
135    return this.alphabets;
136  }
137
138  protected AtomicSymbol getSymbolImpl(List symL)
139  throws IllegalSymbolException {
140    AtomicSymbol s = (AtomicSymbol) symL.get(0);
141    return s;
142  }
143
144  public SimpleAlphabet() {
145    this(new HashSet(), null);
146  }
147
148  public SimpleAlphabet(Set symbols) {
149    this(symbols, null);
150  }
151
152  public SimpleAlphabet(String name) {
153    this(new HashSet(), name);
154  }
155
156  public SimpleAlphabet(Set symbols, String name) {
157    this.symbols = new HashSet();
158    this.name = name;
159    this.alphabets = null;
160
161    // this costs, but I am tracking down a ClassCast exception.
162    // roll on parameterised types.
163    for(Iterator i = symbols.iterator(); i.hasNext(); ) {
164      AtomicSymbol a = (AtomicSymbol) i.next();
165      this.symbols.add(a);
166    }
167  }
168
169  protected ChangeSupport getChangeSupport(ChangeType ct){
170    ChangeSupport cs = super.getChangeSupport(ct);
171
172    if(annotationForwarder == null &&
173      (ct.isMatchingType(Annotatable.ANNOTATION) || Annotatable.ANNOTATION.isMatchingType(ct)))
174    {
175      annotationForwarder =
176              new ChangeForwarder.Retyper(this, cs, Annotation.PROPERTY);
177      getAnnotation().addChangeListener(
178          annotationForwarder,
179          Annotatable.ANNOTATION);
180    }
181    return cs;
182  }
183
184}