/** * */ package cz.cuni.mff.peckam.java.origamist.files; import java.util.Hashtable; import java.util.Iterator; import java.util.NoSuchElementException; import javax.xml.bind.annotation.XmlTransient; import org.apache.log4j.Logger; import cz.cuni.mff.peckam.java.origamist.utils.HashtableElementAdapter; import cz.cuni.mff.peckam.java.origamist.utils.HashtableObserver; import cz.cuni.mff.peckam.java.origamist.utils.ObservableList; /** * A list of subcategories. * * @author Martin Pecka */ public class Categories extends cz.cuni.mff.peckam.java.origamist.files.jaxb.Categories { /** * The hastable for more comfortable search in subcatagories. */ @XmlTransient protected final Hashtable<String, Category> categories = new Hashtable<String, Category>(); public Categories() { HashtableElementAdapter<Category, String, Category> elementAdapter = new HashtableElementAdapter<Category, String, Category>() { @Override public String getKey(Category item) { return item.getId(); } @Override public Category getValue(Category item) { return item; } }; HashtableObserver<Category, String, Category> listener = new HashtableObserver<Category, String, Category>( categories, elementAdapter); ((ObservableList<Category>) category).addObserver(listener); } /** * @return The hashtable with the same elements as getCategory(), with category ids as keys. */ public Hashtable<String, Category> getHashtable() { return categories; } /** * Count the overall number of files in this category and its subcategories. * * @return The overall number of files in this category and its subcategories. */ public int numOfFilesRecursive() { int result = 0; for (Category cat : category) { if (cat.getFiles() != null) result += cat.getFiles().getFile().size(); if (cat.getCategories() != null) result += cat.getCategories().numOfFilesRecursive(); } return result; } /** * Iterator that iterates over all files in this list of categories and their subcategories. * * @return Iterator that iterates over all files in this list of categories and their subcategories. */ public Iterator<File> recursiveFileIterator() { return new Iterator<File>() { Iterator<Category> categoryIterator = category.iterator(); Iterator<File> catFileIterator = null; boolean wasRemoved = false; { if (categoryIterator.hasNext()) { catFileIterator = categoryIterator.next().recursiveFileIterator(); } } @Override public void remove() { if (wasRemoved) { Logger.getLogger(getClass()).warn( "Tried to delete a file from a categorie's recursive iterator twice."); } else if (catFileIterator != null) { wasRemoved = true; catFileIterator.remove(); } else { Logger.getLogger(getClass()).warn( "Tried to delete a file from a categorie's recursive iterator before a call to next()."); } } @Override public File next() { if (!hasNext()) throw new NoSuchElementException("No more elements in recursive file iterator."); // hasNext will do all the magic for us wasRemoved = false; return catFileIterator.next(); } @Override public boolean hasNext() { if (catFileIterator == null) { return false; } else if (catFileIterator.hasNext()) { return true; } else if (categoryIterator.hasNext()) { while (categoryIterator.hasNext() && !catFileIterator.hasNext()) { catFileIterator = categoryIterator.next().recursiveFileIterator(); } return catFileIterator.hasNext(); } return false; } }; } /** * Iterator that iterates over all categories and subcategories in this list of categories. * * @return Iterator that iterates over all categories and subcategories in this list of categories. */ public Iterator<Category> recursiveCategoryIterator() { return new Iterator<Category>() { Iterator<Category> categoryIterator = category.iterator(); Category current = null; Iterator<Category> currentIterator = null; boolean wasRemoved = false; @Override public void remove() { if (wasRemoved) { Logger.getLogger(getClass()).warn( "Tried to delete a subcategory from a categorie's recursive iterator twice."); } else if (currentIterator != null) { currentIterator.remove(); } else { Logger.getLogger(getClass()).warn( "Tried to delete a file from a categorie's recursive iterator before a call to next()."); } } @Override public Category next() { if (currentIterator != null && currentIterator.hasNext()) { return currentIterator.next(); } else if (current == null && categoryIterator.hasNext()) { current = categoryIterator.next(); currentIterator = current.recursiveCategoryIterator(); return current; } else if (current == null) { throw new NoSuchElementException("No more elements in recursive file iterator."); } else /* if ((currentIterator == null || !currentIterator.hasNext()) && current != null) */{ current = null; return next(); } } @Override public boolean hasNext() { // if we are in a categorie's iterator, just use it... when it ends up, the next category returned // should be the next category of this category list if (currentIterator != null && currentIterator.hasNext()) { return true; } else { return categoryIterator.hasNext(); } } }; } @Override public String toString() { return "Categories [categories=" + categories + "]"; } }