package ru.yandex.wmconsole.servantlet.xmlsearch;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

/**
 * User: azakharov
 * Date: 25.09.13
 * Time: 17:20
 */
public class RewritingHandler extends DefaultHandler {

    private XMLStreamWriter writer;
    private StringBuilder builder = new StringBuilder();

    public RewritingHandler(XMLStreamWriter writer) {
        this.writer = writer;
    }

    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
        builder = new StringBuilder();
        if (!skipElement(uri, localName, qName)) {
            try {
                writer.writeStartElement("", localName, uri);
                for (int i = 0; i < attributes.getLength(); i++) {
                    String replacedValue = replaceAttributeValue(
                            uri, localName, qName, attributes.getLocalName(i), attributes.getValue(i));
                    writer.writeAttribute(attributes.getQName(i), replacedValue);
                }
            } catch (XMLStreamException ex) {
                throw new SAXException(ex);
            }
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
        try {
            if (!skipElement(uri, localName, qName)) {
                String originalContent = builder.toString().replaceAll("\\n", "");
                String replacedContent = replaceElementContent(uri, localName, qName, originalContent);
                writer.writeCharacters(replacedContent);
                writer.writeEndElement();
                appendElement(uri, localName, qName, originalContent, writer);
            }
        } catch (XMLStreamException ex) {
            throw new SAXException(ex);
        } finally {
            builder.setLength(0);
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        builder.append(ch, start, length);
    }

    @Override
    public void endDocument() throws SAXException {
        try {
            writer.flush();
            writer.close();
        } catch (XMLStreamException e) {
            throw new SAXException(e);
        }
    }

    protected String replaceAttributeValue(String namespaceUri, String localName, String qName, String attribute, String value) {
         return value;
    }

    protected String replaceElementContent(String namespaceUri, String localName, String qName, String content) {
        return content;
    }

    /**
     * A handler for appending some element after the end of given element
     *
     * @param namespaceUri
     * @param localName
     * @param qName
     * @param content
     * @param writer
     */
    protected void appendElement(String namespaceUri, String localName, String qName, String content, XMLStreamWriter writer) {
    }

    /**
     * A handler for skipping some elements
     *
     * @param namespaceUri
     * @param localName
     * @param qName
     * @return
     */
    protected boolean skipElement(String namespaceUri, String localName, String qName) {
        return false;
    }
}
