package przyklady.software;
/**Przykład do artykułu "Alternatywne źródła SAX".
 * Filtr SAX wybierający wpisy z zadanych kategorii.
 * 
 * Kwiecień 2004.
 * @author Patryk Czarnik
 */

import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl;
import org.xml.sax.helpers.XMLFilterImpl;

/**Klasa jest filtrem SAX wybierającym wpisy z określonych kategorii.
 * Klasa działa dla dokumentów zgodnych z encyklopedia.dtd.
 * @author Patryk Czarnik
 */
public class CategoryFilter extends XMLFilterImpl {
  /** Tworzy filtr nie przepuszczający żadnego wpisu. */
  public CategoryFilter() {
    super();
    fAllowedSet = new TreeSet();
    fCurrentSet = new TreeSet();
  }
  public CategoryFilter(XMLReader aParent) {
    this();
    setParent(aParent);
  }
  
  /** Dodaje kategorię do przepuszczanych. */
  public void addCategory(String aCategory) {
    fAllowedSet.add(aCategory);
  }

  //metody SAX:
  
  public void startElement(String aURI,  String aLocalName,
      String aQName, Attributes aAtts)
  throws SAXException {
    if(aQName.equals("encyklopedia")) { //przepuszczamy
      getContentHandler().startElement(aURI, aLocalName, aQName, aAtts);
    } else if(aQName.equals("wpis")) { //buforujemy
      fHaslo = aAtts.getValue("haslo");
      fCurrentSet.clear();
    } else if(aQName.equals("kategoria")) { //buforujemy
      fCurrentSet.add(aAtts.getValue("kategoria"));
    } else if(aQName.equals("opis")) {
      //za kategoriami, spr. czy przepuszczac
      Iterator iter = fCurrentSet.iterator();
      fIsAllowed = false;
      while(!fIsAllowed && iter.hasNext())
        if(fAllowedSet.contains(iter.next()))
          fIsAllowed = true;

      if(fIsAllowed) { // przesylamy zbuforowane zdarzenia
        AttributesImpl attrs = new AttributesImpl();
        attrs.addAttribute("", "haslo", "haslo", "CDATA", fHaslo);
        getContentHandler().startElement("", "wpis", "wpis", attrs);
        attrs.clear();
        iter = fCurrentSet.iterator();
        while(iter.hasNext()) {
          attrs.addAttribute("", "kategoria", "kategoria", "CDATA", (String)iter.next());
          getContentHandler().startElement("", "kategoria", "kategoria", attrs);
          getContentHandler().endElement("", "kategoria", "kategoria");
          attrs.clear();
        }
        getContentHandler().startElement("", "opis", "opis", attrs);
      }
    } else if(aQName.equals("ref")) { // przepuszczamy, jeśli fIsAllowed
      if(fIsAllowed)
        getContentHandler().startElement(aURI, aLocalName, aQName, aAtts);
    }
  }

  public void endElement(String aURI,  String aLocalName, String aQName)
  throws SAXException {
    if (aQName.equals("encyklopedia") ||
        aQName.equals("wpis") && fIsAllowed ||
        aQName.equals("opis") && fIsAllowed ||
        aQName.equals("ref") && fIsAllowed) {
      getContentHandler().endElement(aURI, aLocalName, aQName);
    }
  }

  public void characters(char[] aCh, int aStart, int aLength)
  throws SAXException {
    // znaczące napisy znajdują się tylko w elementach opis
    if(fIsAllowed) {
      getContentHandler().characters(aCh, aStart, aLength);
    }
  }

  private Set fAllowedSet;
  private Set fCurrentSet;
  private String fHaslo;
  private boolean fIsAllowed;
}
