package de.ivu.elect.nl.eml;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.xml.XMLConstants;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.apache.commons.io.IOUtils;
import org.xml.sax.SAXException;

public class EmlValidator {

  private static final String XSD_110a = "110a-electionevent-kiesraad-strict.xsd";

//  private static final String XSD_210 = "210-nomination-kiesraad-strict.xsd";

  private static final String XSD_230 = "230-candidatelist-kiesraad-strict.xsd";

  private static final String XSD_510 = "510-count-kiesraad-strict.xsd";

  // private static final String XSD_520 = "520-result-kiesraad-strict.xsd";

  public static void validateEml110a(InputStream is) throws IOException, SAXException {
    validate(is, XSD_110a);
  }

//  public static void validateEml210(InputStream is) throws IOException, SAXException {
//    validate(is, XSD_210);
//  }

  public static void validateEml230(InputStream is) throws IOException, SAXException {
    validate(is, XSD_230);
  }

  public static void validateEml510(InputStream is) throws IOException, SAXException {
    validate(is, XSD_510);
  }

//  public static void validateEml520(InputStream is) throws IOException, SAXException {
//    validate(is, XSD_520);
//  }

  private static void validate(InputStream is, String eml) throws IOException, SAXException {
    StreamSource source = new StreamSource(is);
    Schema schema = loadSchema(eml);
    Validator validator = schema.newValidator();
    validator.validate(source);
  }

  @SuppressWarnings("java:S2755") // Schema-Dateien referenzieren sich über "file"-Zugriffe, Schema-Dateien sind fix => kein Problem hier
  private static Schema loadSchema(String eml) throws IOException, SAXException {
    SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);


    // ELECT-13929
    try {
      factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "file");
    } catch (Exception e){
      // ignore
    }
    try {
      factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
    } catch (Exception e){
      // ignore
    }


    factory.setResourceResolver(new ClasspathResourceResolver());

    return factory.newSchema(stream(eml));
//    return factory.newSchema(new Source[]{
//        stream(eml),
//        stream(XSD_EMLCORE),
//        stream(XSD_EMLEXTERNAL),
//        stream(XSD_KIESRAAD_EXTENSION),
//        stream(XSD_KIESRAAD_RESTRICTION),
//        stream(XSD_XALXSD_XAL),
//        stream(XSD_XNL),
//        stream(XSD_EML_TIMESTAMP),
//        stream(XSD_EML_XMLDSIG)
//    });
  }

  private static StreamSource stream(String res) throws IOException {
    try (InputStream is = getEmlResource(res)) {
      try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
        IOUtils.copy(is, bos);
        return new StreamSource(new ByteArrayInputStream(bos.toByteArray()));
      }
    }

  }

  private static InputStream getEmlResource(String res) {
    return Thread.currentThread().getContextClassLoader().getResourceAsStream(res);
  }
}
