package eu.freme.bservices.controllers.xsltconverter;

import eu.freme.common.conversion.SerializationFormatMapper;
import eu.freme.common.exception.BadRequestException;
import eu.freme.common.exception.FREMEHttpException;
import eu.freme.common.exception.OwnedResourceNotFoundException;
import eu.freme.common.persistence.dao.OwnedResourceDAO;
import eu.freme.common.persistence.model.XsltConverter;
import eu.freme.common.rest.NIFParameterSet;
import eu.freme.common.rest.RestHelper;
import net.sf.saxon.s9api.*;
import nu.validator.htmlparser.sax.HtmlParser;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.*;
import org.xml.sax.InputSource;

import javax.annotation.PostConstruct;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayOutputStream;
import java.io.StringReader;
import java.util.Map;

/**
 * Created by Arne on 05.07.2016.
 */

@RestController
@RequestMapping("/toolbox/xslt-converter/documents")
public class XsltConverterController {

    Logger logger = Logger.getLogger(XsltConverterController.class);

    public static final String XML = "text/xml";
    public static final String HTML = "text/html";

    @Autowired
    SerializationFormatMapper serializationFormatMapper;

    @Autowired
    RestHelper rest;

    @Autowired
    OwnedResourceDAO<XsltConverter> entityDAO;

    @PostConstruct
    public void init(){
        // add required mimeTypes and in-/outformat values
        serializationFormatMapper.put(XML, XML);
        serializationFormatMapper.put("xml", XML);
        serializationFormatMapper.put(HTML, HTML);
        serializationFormatMapper.put("html", HTML);
    }

    @RequestMapping(value = "/{identifier}", method = RequestMethod.POST)
    @Secured({"ROLE_USER", "ROLE_ADMIN"})
    public ResponseEntity<String> filter(
            @PathVariable("identifier") String identifier,
            @RequestHeader(value = "Accept", required = false) String acceptHeader,
            @RequestHeader(value = "Content-Type", required = false) String contentTypeHeader,
            @RequestBody(required = true) String postBody
    ) {
        try {
            // check access rights and get plain stylesheet
            String stylesheet = entityDAO.findOneByIdentifier(identifier).getStylesheet();

            Processor processor = new Processor(false);
            XsltCompiler compiler = processor.newXsltCompiler();
            // todo: set error listener
            //compiler.setErrorListener(...);
            Xslt30Transformer transformer = compiler.compile(new StreamSource(new StringReader(stylesheet))).load30();

            // configure input
            SAXSource source;
            String informat = serializationFormatMapper.get(contentTypeHeader);
            if(informat == null)
                informat = XML;
            if(informat.equals(HTML)) {
                //// convert html to xml
                HtmlParser parser = new HtmlParser();
                source = new SAXSource(parser, new InputSource(new StringReader(postBody)));
            }else{
                source = new SAXSource(new InputSource(new StringReader(postBody)));
            }

            // configure output
            String outformat = serializationFormatMapper.get(acceptHeader);
            Serializer out = processor.newSerializer();
            if(outformat == null)
                outformat = XML;
            if(outformat.equals(HTML)){
                out.setOutputProperty(Serializer.Property.METHOD, "html");
            }else{
                outformat = XML;
                out.setOutputProperty(Serializer.Property.METHOD, "xml");
            }
            out.setOutputProperty(Serializer.Property.INDENT, "yes");
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            out.setOutputStream(outputStream);

            // do transformation
            XdmValue transformed = transformer.applyTemplates(source);

            // serialize the result
            out.serializeXdmValue(transformed);
            String serialization = outputStream.toString("UTF-8");

            HttpHeaders responseHeaders = new HttpHeaders();
            responseHeaders.add("Content-Type", outformat);
            return new ResponseEntity<>(serialization, responseHeaders,
                    HttpStatus.OK);
        } catch (AccessDeniedException ex){
            logger.error(ex.getMessage());
            throw new eu.freme.common.exception.AccessDeniedException(ex.getMessage());
        } catch (OwnedResourceNotFoundException | BadRequestException ex){
            logger.error(ex.getMessage());
            throw ex;
        } catch(Exception ex){
            logger.error(ex.getMessage());
            throw new FREMEHttpException(ex.getMessage());
        }
    }
}

@@ -1038,16 +1038,149 @@
 struct;%0A
+import javax.xml.transform.ErrorListener;%0Aimport javax.xml.transform.SourceLocator;%0Aimport javax.xml.transform.TransformerException;%0A
 import j
@@ -1205,32 +1205,32 @@
 .sax.SAXSource;%0A
-
 import javax.xml
@@ -1674,16 +1674,529 @@
 html%22;%0A%0A
+    private ErrorListener saxonListener = new ErrorListener() %7B%0A        public void error(TransformerException exception) throws TransformerException %7B%0A            logger.error(exception);        %7D%0A%0A        public void fatalError(TransformerException exception) throws TransformerException %7B%0A            logger.error(exception);%0A            throw exception;%0A        %7D%0A%0A        public void warning(TransformerException exception) throws TransformerException %7B%0A            logger.warn(exception);%0A        %7D%0A    %7D;%0A%0A
     @Aut
@@ -3438,50 +3438,8 @@
     
-// todo: set error listener%0A            //
 comp
@@ -3464,11 +3464,21 @@
 ner(
-...
+saxonListener
 );%0A 
@@ -3594,16 +3594,73 @@
 oad30();
+%0A            transformer.setErrorListener(saxonListener);
 %0A%0A      

set ErrorListener