package przyklady.software;
/**Przykład do artykułu "Alternatywne źródła SAX".
 * Parser zgodny z SAX czytający dokumenty w formacie
 * nie XML.
 * 
 * Kwiecień 2004.
 * @author Patryk Czarnik
 */

import java.io.FileReader;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;

import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.AttributesImpl;

/**Parser zgodny z SAX, czytający dane z dokumentów tekstowych
 * zgodnych z formatem encyklopedii.
 * Tworzy zdarzenia SAX reprezentujące odpowiadający dokument
 * encyklopedii w formacie XML (encyklopedia.dtd).
 *  
 * @author Patryk Czarnik
 */
public class TxtReader implements XMLReader {

  public void parse(String aSystemId) throws IOException, SAXException {
    this.parse(new InputSource(aSystemId));
  }

  /** Parsuje dokument (szuka źródła w aInput) i wysyła zdarzenia SAX
   * do obiektu podanego w setContentHandler.
   */
  public void parse(InputSource aInput) throws IOException, SAXException {
    if(fHandler != null) {
      BufferedReader src = null;
      if(aInput.getCharacterStream() != null)
        src = new BufferedReader(aInput.getCharacterStream());
      else if(aInput.getByteStream() != null)
        src = new BufferedReader(new InputStreamReader(aInput.getByteStream()));
      else if(aInput.getSystemId() != null)
        src = new BufferedReader(new FileReader(aInput.getSystemId()));
      else
        throw new SAXException("Nie okreslono zrodla danych");

      AttributesImpl attrs = new AttributesImpl();
      fHandler.startDocument();
      fHandler.startElement("", "encyklopedia", "encyklopedia", attrs);

      boolean cont = true;
      while(cont) {
        String word = src.readLine();
        if(word == null)
          break;
        attrs.addAttribute("", "haslo", "haslo", "CDATA", word);
        fHandler.startElement("", "wpis", "wpis", attrs);
        attrs.clear();
        
        String line = src.readLine();
        if(line == null)
          break;
        String[] categs = line.split(",");
        for(int i = 0; i < categs.length; i++) {
          attrs.addAttribute("", "kategoria", "kategoria", "CDATA", categs[i]);
          fHandler.startElement("", "kategoria", "kategoria", attrs);
          fHandler.endElement("", "kategoria", "kategoria");
          attrs.clear();
        }
        
        fHandler.startElement("", "opis", "opis", attrs);
        while(true) {
          line = src.readLine();
          if(line == null) { // koniec dokumentu
            cont = false;
            break;
          }
          int len = line.length(); 
          if(len == 0) // koniec wpisu
            break;
          char[] line_arr = line.toCharArray();
          int pos = 0;
          while(true) {
            int old_pos = pos;
            pos = line.indexOf('#', old_pos);
            if(pos == -1)
              pos = len;
            fHandler.characters(line_arr, old_pos, pos - old_pos);
            if(pos == len)
              break;
            old_pos = pos + 1;
            pos = line.indexOf('#', old_pos);
            if(pos == -1)
              throw new SAXException("Niedomknieta referencja");
            word = line.substring(old_pos, pos);
            pos++;

            attrs.addAttribute("", "haslo", "haslo", "CDATA", word);
            fHandler.startElement("", "ref", "ref", attrs);
            fHandler.endElement("", "ref", "ref");
            attrs.clear();
          }
        }
        fHandler.endElement("", "opis", "opis");
        fHandler.endElement("", "wpis", "wpis");
      }
      
      fHandler.endElement("", "encyklopedia", "encyklopedia");
      fHandler.endDocument();
    }
  }

  public ContentHandler getContentHandler() {
    return fHandler;
  }

  /**Ustawia obiekt, do którego będą wysyłane zdarzenia SAX
   * podczas parsowania.
   */
  public void setContentHandler(ContentHandler aHandler) {
    fHandler = aHandler;
  }

  // Nie implementowane:
  public DTDHandler getDTDHandler() {
    return null;
  }
  public void setDTDHandler(DTDHandler handler) {
  }
  public EntityResolver getEntityResolver() {
    return null;
  }
  public void setEntityResolver(EntityResolver resolver) {
  }
  public ErrorHandler getErrorHandler() {
    return null;
  }
  public void setErrorHandler(ErrorHandler handler) {
  }
  public boolean getFeature(String name) throws SAXNotRecognizedException,
  SAXNotSupportedException {
    return false;
  }
  public void setFeature(String name, boolean value)
  	throws SAXNotRecognizedException, SAXNotSupportedException {
  }
  public Object getProperty(String name) throws SAXNotRecognizedException,
      SAXNotSupportedException {
    return null;
  }
  public void setProperty(String name, Object value)
      throws SAXNotRecognizedException, SAXNotSupportedException {
  }
  
  private Counter fCounter;
  private ContentHandler fHandler;
}
