package org.seqcode.gseutils.datastructures; import java.io.*; import java.util.*; import org.seqcode.gseutils.*; import org.seqcode.gseutils.EventSource.Default; public class TaxonomyImpl<X> implements Taxonomy<X>, Saveable, Listener<TaxonomyEvent> { private Set<X> elmts; private Map<String,TaxonomyImpl<X>> subTaxa; private EventSource.Default<TaxonomyEvent> src; public TaxonomyImpl(DataInputStream dis, Factory<X> loadingFactory) throws IOException { int numElmts = dis.readInt(); int numSubTaxa = dis.readInt(); src = new EventSource.Default<TaxonomyEvent>(); elmts = new HashSet<X>(); subTaxa = new HashMap<String,TaxonomyImpl<X>>(); for(int i = 0; i < numElmts; i++) { elmts.add(loadingFactory.createObject()); } for(int i = 0; i < numSubTaxa; i++) { String k = dis.readUTF(); TaxonomyImpl<X> ti = new TaxonomyImpl<X>(dis, loadingFactory); ti.addEventListener(this); subTaxa.put(k, ti); } } public TaxonomyImpl() { elmts = new HashSet<X>(); subTaxa = new HashMap<String,TaxonomyImpl<X>>(); src = new EventSource.Default<TaxonomyEvent>(); } public TaxonomyImpl(Taxonomy<X> t) { src = new EventSource.Default<TaxonomyEvent>(); if(t != null) { elmts = new HashSet<X>(t.getImmediateElements()); subTaxa = new HashMap<String,TaxonomyImpl<X>>(); for(String k : t.getAddrs()) { subTaxa.put(k, new TaxonomyImpl<X>(t.getSubTaxonomy(k))); subTaxa.get(k).addEventListener(this); } } else { elmts = new HashSet<X>(); subTaxa = new HashMap<String,TaxonomyImpl<X>>(); } } public void save(DataOutputStream dos) throws IOException { dos.writeInt(elmts.size()); dos.writeInt(subTaxa.size()); for(X v : elmts) { Saveable s = (Saveable)v; s.save(dos); } for(String k : subTaxa.keySet()) { dos.writeUTF(k); subTaxa.get(k).save(dos); } } public void recursiveRemoveElement(X v) { if(elmts.contains(v)) { elmts.remove(v); fireElementRemoved(v); } for(String k : subTaxa.keySet()) { subTaxa.get(k).recursiveRemoveElement(v); } } public void fireElementRemoved(Object elmt) { //System.out.println("Element Removed: " + elmt); TaxonomyEvent te = new TaxonomyEvent(this, TaxonomyEvent.ELEMENT_REMOVED, elmt); src.fireEvent(te); } public void fireElementAdded(Object elmt) { //System.out.println("Element Added: " + elmt); TaxonomyEvent te = new TaxonomyEvent(this, TaxonomyEvent.ELEMENT_ADDED, elmt); src.fireEvent(te); } public void fireTaxonRemoved(String addr) { //System.out.println("Taxon Removed: " + addr); TaxonomyEvent te = new TaxonomyEvent(this, TaxonomyEvent.TAXON_REMOVED, addr); te.addAddr(addr); src.fireEvent(te); } public void fireTaxonAdded(String addr) { //System.out.println("Taxon Added: " + addr); TaxonomyEvent te = new TaxonomyEvent(this, TaxonomyEvent.TAXON_ADDED, addr); te.addAddr(addr); src.fireEvent(te); } public void fireElementChanged(Object elmt) { //System.out.println("Element Changed: " + elmt); if(!elmts.contains(elmt)) { throw new IllegalArgumentException(); } TaxonomyEvent te = new TaxonomyEvent(this, TaxonomyEvent.ELEMENT_CHANGED, elmt); src.fireEvent(te); } public void eventRegistered(TaxonomyEvent te) { Object source = te.getSource(); String addr = null; Iterator<String> kitr = subTaxa.keySet().iterator(); while(kitr.hasNext() && addr == null) { String k = kitr.next(); if(subTaxa.get(k) == source) { addr = k; } } if(addr != null) { TaxonomyEvent te2 = new TaxonomyEvent(this, te, addr); src.fireEvent(te2); //System.out.println("** Passing: " + te2.toString()); } else { //System.out.println("## couldn't find addr."); src.fireEvent(te); } } public void print(PrintStream ps) { indentedPrint(ps, 0); } private void indentedPrint(PrintStream ps, int indents) { for(X v : elmts) { for(int i = 0; i < indents; i++) { ps.print("\t"); } ps.println("- " + v.toString()); } for(String k : subTaxa.keySet()) { for(int i = 0; i < indents; i++) { ps.print("\t"); } ps.println("* " + k); subTaxa.get(k).indentedPrint(ps, indents+1); } } public int size() { int c = elmts.size(); for(String k : subTaxa.keySet()) { c += subTaxa.get(k).size(); } return c; } public int getNumElements() { return elmts.size(); } public int getNumSubTaxonomies() { return subTaxa.size(); } public void addElement(X k) { if(!elmts.contains(k)) { elmts.add(k); fireElementAdded(k); } } public void addElement(Collection<String> addrs, X e) { if(addrs.size() == 0) { addElement(e); } else { LinkedList<String> rest = new LinkedList<String>(addrs); String k = rest.removeFirst(); if(!subTaxa.containsKey(k)) { subTaxa.put(k, new TaxonomyImpl<X>()); subTaxa.get(k).addEventListener(this); } subTaxa.get(k).addElement(rest, e); } } public void addTaxonomy(String addr, Taxonomy<X> tax) { if(subTaxa.containsKey(addr)) { throw new IllegalArgumentException("addr already exists: " + addr); } subTaxa.put(addr, new TaxonomyImpl<X>(tax)); subTaxa.get(addr).addEventListener(this); fireTaxonAdded(addr); } public Collection<X> getImmediateElements() { return elmts; } public Collection<X> getAllElements() { Set<X> total = new HashSet<X>(elmts); for(String k : subTaxa.keySet()) { total.addAll(subTaxa.get(k).getAllElements()); } return total; } public Taxonomy<X> getSubTaxonomy(Collection<String> addr) { if(addr.size() == 0) { return this; } LinkedList<String> lst = new LinkedList<String>(addr); String f = lst.removeFirst(); Taxonomy<X> sub = getSubTaxonomy(f); if(sub == null) { return null; } return sub.getSubTaxonomy(lst); } public TaxonomyImpl<X> getSubTaxonomy(String addr) { if(subTaxa.containsKey(addr) && subTaxa.get(addr)==null) { throw new IllegalArgumentException(); } return subTaxa.get(addr); } public Set<String> getAddrs() { return subTaxa.keySet(); } public boolean hasAddr(String s) { return subTaxa.containsKey(s); } public Object clone() { TaxonomyImpl<X> newT = new TaxonomyImpl<X>(this); return newT; } public Taxonomy<X> combine(Taxonomy<X> t) { TaxonomyImpl<X> newT = new TaxonomyImpl<X>(); newT.elmts.addAll(elmts); for(String k : subTaxa.keySet()) { if(t.hasAddr(k)) { TaxonomyImpl<X> newImpl = new TaxonomyImpl<X>(subTaxa.get(k)); newImpl = new TaxonomyImpl<X>(t.getSubTaxonomy(k).combine(newImpl)); newT.subTaxa.put(k, newImpl); newImpl.addEventListener(newT); } else { newT.subTaxa.put(k, new TaxonomyImpl<X>(subTaxa.get(k))); newT.subTaxa.get(k).addEventListener(newT); } } newT.elmts.addAll(t.getImmediateElements()); for(String k : t.getAddrs()) { if(!subTaxa.containsKey(k)) { newT.subTaxa.put(k, new TaxonomyImpl<X>(t.getSubTaxonomy(k))); newT.subTaxa.get(k).addEventListener(newT); } } return newT; } public void addEventListener(Listener<TaxonomyEvent> el) { src.addEventListener(el); } public void removeEventListener(Listener<TaxonomyEvent> el) { src.removeEventListener(el); } public boolean hasListeners() { return src.hasListeners(); } }