// Copyright 2000-2005, FreeHEP.

package hep.graphics.heprep.xml;

import java.io.*;
import java.util.*;
import java.util.zip.*;
import javax.xml.parsers.*;

import org.xml.sax.*;

import org.freehep.util.io.*;
import hep.graphics.heprep.*;
import hep.graphics.heprep.ref.*;

/**
 *
 * @author M.Donszelmann
 *
 * @version $Id: XMLHepRepReader.java,v 1.34 2005/02/27 22:58:50 duns Exp $
 */
public class XMLHepRepReader extends AbstractHepRepReader {
    public static final String cvsId = "$Id: XMLHepRepReader.java,v 1.34 2005/02/27 22:58:50 duns Exp $";

    private XMLSequence sequence;
    
    XMLHepRepReader(InputStream in) throws IOException {
        super(in);
        reset();
    }

    XMLHepRepReader(String fileName) throws IOException {
        super(fileName);
        reset();
    }

    public void close() throws IOException {
        super.close();
        if (sequence != null) {
            sequence.close();
        }
    }

    public void reset() throws IOException, UnsupportedOperationException {
        if ((input != null) && !(input instanceof ZipInputStream)) {
            sequence = new XMLSequence(new BufferedInputStream(input));
        } else if ((name != null) && !name.toLowerCase().endsWith(".zip")) {
            if (sequence != null) sequence.close();
            if (name.toLowerCase().endsWith(".gz")) {
                sequence = new XMLSequence(new BufferedInputStream(new GZIPInputStream(new FileInputStream(name))));
            } else {
                sequence = new XMLSequence(new BufferedInputStream(new FileInputStream(name)));
            }    
        } else {
            super.reset();
        }
    }
    
    public boolean hasNext() throws IOException, UnsupportedOperationException {
        if (sequence != null) return sequence.hasNext();
        return super.hasNext();
    }

    public HepRep next() throws IOException, UnsupportedOperationException, NoSuchElementException {
        if (!hasNext()) throw new UnsupportedOperationException(getClass()+" no more elements");
        
        if (sequence != null) {
            return readHepRep(sequence.next());
        }
        
        return super.next();
    }


    protected HepRep readHepRep(InputStream stream) throws IOException {

        HepRep heprep = readHepRep(new XMLHepRepFactory().createHepRep(), stream);
        return heprep;
    }

    private HepRep readHepRep(HepRep heprep, InputStream stream) throws IOException {

        try {
            XMLHepRepHandler handler = new XMLHepRepHandler(heprep);
            SAXParserFactory factory = SAXParserFactory.newInstance();
            factory.setNamespaceAware(true);
            SAXParser xml = factory.newSAXParser();
            // show namespace specific attributes
            xml.getXMLReader().setFeature("http://xml.org/sax/features/namespace-prefixes", true);

            // now read real document
            InputSource source = new InputSource(new BufferedReader(new InputStreamReader(stream)));
            xml.parse(source, handler);

            return heprep;
        } catch (ParserConfigurationException e) {
            IOException exception = new IOException();
            exception.initCause(e);
            throw exception;
        } catch (SAXParseException e) {
            if ((e.getLineNumber() == 1) && (e.getColumnNumber() == -1)) throw new EOFException();
            IOException exception = new IOException("Syntax error at Line: "+e.getLineNumber()+"("+e.getColumnNumber()+")");
            exception.initCause(e);
            throw exception;
        } catch (SAXException e) {
            IOException exception = new IOException();
            exception.initCause(e);
            throw exception;
        }
    }


    public static void readDefaults() throws IOException {

        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();
            factory.setNamespaceAware(true);
            XMLReader xmlReader = factory.newSAXParser().getXMLReader();
            XMLHepRepDefaultsHandler handler = new XMLHepRepDefaultsHandler();
            xmlReader.setContentHandler(handler);
            xmlReader.setDTDHandler(handler);
            xmlReader.setErrorHandler(handler);
            xmlReader.setEntityResolver(handler);

            Reader reader = new BufferedReader(
                            new InputStreamReader(XMLHepRepReader.class.getResourceAsStream("AttributeDefaults.xml")));
            InputSource source = new InputSource(reader);
            xmlReader.parse(source);
            reader.close();
        } catch (Exception e) {
            IOException exception = new IOException();
            exception.initCause(e);
            throw exception;
        }
    }
}
