package com.r11.tools.xml;

import com.r11.tools.controller.internal.XPathQueryResult;
import net.sf.saxon.s9api.*;

import javax.xml.transform.stream.StreamSource;
import java.io.StringReader;
import java.io.StringWriter;

/**
 * Handler for Saxon engine
 * @author Wojciech Czop
 */
public class Saxon implements XmlEngine{

    /**
     * Transforms string containing xml document via xslt
     * @param data xml to be transformed
     * @param transform xslt
     * @return transformed xml
     * @throws SaxonApiException thrown on stylesheet or transformation errors
     */
    public String processXSLT(String data, String transform) throws SaxonApiException {
        Processor processor = new Processor(false);
        XsltCompiler compiler = processor.newXsltCompiler();
        XsltExecutable stylesheet = compiler.compile(new StreamSource(new StringReader(transform)));
        StringWriter sw = new StringWriter();
        Serializer out = processor.newSerializer(sw);
        out.setOutputProperty(Serializer.Property.METHOD, "xml");
        out.setOutputProperty(Serializer.Property.INDENT, "yes");

        Xslt30Transformer transformer = stylesheet.load30();
        transformer.transform(new StreamSource(new StringReader(data)), out);
        return sw.toString();
    }

    @Override
    public String validate(String data, String xsd) {
        throw new UnsupportedOperationException();
    }

    /**
     * Process xpath and return either node or wrapped atomic value
     * @param data xml to be querried
     * @param query xpath queryy
     * @param version processor version
     * @return string xml representation of the node
     * @throws Exception thrown on node building errors or invalid xpath
     */
    public XPathQueryResult processXPath(String data, String query, String version) throws Exception {
        Processor p = new Processor(false);
        XPathCompiler compiler = p.newXPathCompiler();
        DocumentBuilder builder = p.newDocumentBuilder();
        XdmNode doc = builder.build(new StreamSource(new StringReader(data)));

        compiler.setLanguageVersion(version);

        NewNamespaceResolver resolver = new NewNamespaceResolver();

        resolver.process(doc);

        resolver.exportNamespaces(compiler);

        XdmValue result = compiler.evaluate(query, doc);
        StringBuilder sb = new StringBuilder();
        for (XdmItem xdmItem : result) {
            sb.append(xdmItem);
            sb.append('\n');
        }
        return new XPathQueryResult(sb.toString(), "N/A");

    }

    /**
     * Returns version of the processor
     * @return version of the processor
     */
    public String getVersion() {
        return new Processor(false).getSaxonProductVersion();
    }
}
