package com.mobenga.ngen.xml.parser;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.xml.stream.*;
import javax.xml.stream.events.*;
import java.io.InputStream;

/**
 * Parses an input stream with XML content using the provided document parser.
 */
public class XmlParser {

    private static final Logger log = LoggerFactory.getLogger(XmlParser.class);
    private String encoding;

    /**
     * Creates an XML Parser instance using UTF-8 encoding
     */
    public XmlParser() {
        this.encoding = "UTF-8";
    }

    /**
     * Creates an XML Parser instance using the specified encoding
     * @param encoding the character encoding of the stream
     */
    public XmlParser(String encoding) {
        this.encoding = encoding;
    }

    /**
     * Parses an input stream with XML content using the provided document parser.
     *
     * @param documentParser Document parser to use for parsing the result
     * @param xmlStream      xml content to parse
     * @param resultClass    Class for the required result type
     * @param <T>            Required result type
     * @return an object of required result type.
     * @throws XMLStreamException    Malformed data causes this exception.
     * @throws IllegalStateException Misconfigured mapping files are the most common cause of this exception.
     */
    public <T> T parseXmlUnsafe(InputStream xmlStream, DocumentParser documentParser, Class<T> resultClass) throws XMLStreamException {
        XMLInputFactory inputFactory = XMLInputFactory.newInstance();
        XMLEventReader eventReader = inputFactory.createXMLEventReader(xmlStream, encoding);

        while (eventReader.hasNext()) {
            XMLEvent xmlEvent = eventReader.nextEvent();

            if (xmlEvent.isStartElement()) {
                documentParser.parseStartElement(xmlEvent);
            } else if (xmlEvent.isCharacters()) {
                documentParser.parseCharacters(((Characters) xmlEvent).getData());
            } else if (xmlEvent.isEndElement()) {
                documentParser.parseEndElement(xmlEvent);
            }
        }
        T resObj = documentParser.getResult(resultClass);
        if (log.isWarnEnabled() && null == resObj) {
            log.warn("No object of requested class was available on the object branch in the document parser.");
        }
        return resObj;
    }
}

@@ -177,16 +177,64 @@
 tStream;
+%0Aimport java.util.HashMap;%0Aimport java.util.Map;
 %0A%0A/**%0A *
@@ -436,24 +436,226 @@
 ate 
-String encoding;
+static final String UTF_8 = %22UTF-8%22;%0A%0A    private Map%3CString, Object%3E xmlInputFactoryProperties;%0A    private String encoding;%0A%0A    public static XmlParserBuilder builder() %7B%0A        return new XmlParserBuilder();%0A    %7D
 %0A%0A  
@@ -768,27 +768,15 @@
 this
-.encoding = %22UTF-8%22
+(UTF_8)
 ;%0A  
@@ -979,28 +979,476 @@
 this
-.encoding = encoding
+(encoding, null);%0A    %7D%0A%0A    /**%0A     * Creates an XML Parser instance using the specified encoding%0A     * @param encoding the character encoding of the stream%0A     * @param xmlInputFactoryProperties the properties that will be used during construction of XMLInputFactory%0A     */%0A    private XmlParser(String encoding, Map%3CString, Object%3E xmlInputFactoryProperties) %7B%0A        this.encoding = encoding;%0A        this.xmlInputFactoryProperties = xmlInputFactoryProperties
 ;%0A  
@@ -2207,19 +2207,24 @@
 ctory = 
-XML
+buildXml
 InputFac
@@ -2231,20 +2231,8 @@
 tory
-.newInstance
 ();%0A
@@ -3055,11 +3055,1087 @@
 j;%0A    %7D
+%0A%0A    protected XMLInputFactory buildXmlInputFactory() %7B%0A        XMLInputFactory inputFactory = XMLInputFactory.newInstance();%0A        if(xmlInputFactoryProperties != null && xmlInputFactoryProperties.size() %3E 0)%7B%0A            for( Map.Entry%3CString, Object%3E entry : xmlInputFactoryProperties.entrySet() )%7B%0A                inputFactory.setProperty(entry.getKey(), entry.getValue());%0A            %7D%0A        %7D%0A        return inputFactory;%0A    %7D%0A%0A    private static class XmlParserBuilder%7B%0A        private Map%3CString, Object%3E xmlInputFactoryProperties = new HashMap%3C%3E();%0A        private String encoding = UTF_8;%0A%0A        private XmlParserBuilder()%7B%7D%0A%0A        public XmlParserBuilder encoding(String encoding)%7B%0A            this.encoding = encoding;%0A            return this;%0A        %7D%0A%0A        public XmlParserBuilder addXmlInputFactoryProperty(String key, Object value)%7B%0A            xmlInputFactoryProperties.put(key, value);%0A            return this;%0A        %7D%0A%0A        public XmlParser build()%7B%0A            return new XmlParser(encoding, xmlInputFactoryProperties);%0A        %7D%0A%0A    %7D
 %0A%7D%0A

add ability to configure XmlInputFactory