/*
 * Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
// rbarkhouse - 2011 March 21 - 2.3 - Initial implementation
package org.eclipse.persistence.testing.jaxb.xmlvirtualaccessmethods;

import java.io.*;
import java.math.*;
import java.util.*;

import jakarta.xml.bind.*;
import jakarta.xml.bind.util.JAXBSource;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.*;
import javax.xml.validation.Validator;

import org.eclipse.persistence.internal.oxm.XMLConversionManager;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
import org.eclipse.persistence.oxm.XMLConstants;
import org.eclipse.persistence.testing.oxm.XMLTestCase;
import org.w3c.dom.*;
import org.w3c.dom.Element;
import org.xml.sax.*;

public class XmlVirtualAccessMethodsTestCases extends XMLTestCase {

    private static boolean DEBUG = false;
    private static boolean THROW_VALIDATION_ERRORS = false;

    private JAXBContext ctx;

    private byte[] bytes = new byte[] {23,1,112,12,1,64,1,14,3,2};
    private Byte[] bigBytes = new Byte[] {23,1,112,12,1,64,1,14,3,2};

    public XmlVirtualAccessMethodsTestCases(String name) {
        super(name);
    }

    @Override
    public String getName() {
        return "XML Virtual Access Methods: " + super.getName();
    }

    public void testBasicModel() throws Exception {
        InputStream oxm = ClassLoader.getSystemClassLoader().getResourceAsStream(
            "org/eclipse/persistence/testing/jaxb/xmlvirtualaccessmethods/basic-eclipselink-oxm.xml");

        Map<String, Object> ctxProperties = new HashMap<String, Object>();
        ctxProperties.put(JAXBContextProperties.OXM_METADATA_SOURCE, oxm);

        /**
         * Employee extensions:
         *      - salary (BigDecimal)
         *      - age (Integer)
         *      - batphone (PhoneNumber)
         *
         * PhoneNumber extensions:
         *      - ext (String)
         *      - countryCode (String)
         *      - forwards (LinkedList of PhoneNumber)
         */

        ctx = JAXBContextFactory.createContext(new Class[] {Employee.class, PhoneNumber.class}, ctxProperties);

        Document marshalDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();

        Marshaller m = ctx.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        m.marshal(getControlObjectBasic(), marshalDoc);

        if (DEBUG) {
            System.out.println("*** TEST BASIC MODEL ***");
            m.marshal(getControlObjectBasic(), System.out);
        }

        String[] extensions = new String[] {
                "salary", "age", "batphone", "ext", "country-code", "forwards"
        };

        for (int i = 0; i < extensions.length; i++) {
            // Test that Extensions appear in the marshalled document
            NodeList nodeList = marshalDoc.getDocumentElement().getElementsByTagName(extensions[i]);
            boolean found = nodeList != null && nodeList.getLength() > 0;
            assertTrue("'" + extensions[i] + "' extension not found.", found);
        }

        // Test that all 'forwards' PhoneNumbers were marshalled
        NodeList nodeList = marshalDoc.getDocumentElement().getElementsByTagName("forwards");
        Node forwadsNode = nodeList.item(0);

        assertEquals("Incorrect number of 'forwards'.", 3, forwadsNode.getChildNodes().getLength());
    }

    public void testCompleteModel() throws Exception {
        InputStream oxm = ClassLoader.getSystemClassLoader().getResourceAsStream(
            "org/eclipse/persistence/testing/jaxb/xmlvirtualaccessmethods/eclipselink-oxm.xml");

        Map<String, Object> ctxProperties = new HashMap<String, Object>();
        ctxProperties.put(JAXBContextProperties.OXM_METADATA_SOURCE, oxm);

        /**
         * Extensions:
         *       - @directatt
         *       - directelem
         *       - nullpol
         *       - join
         *       - idref
         *       - xmllist
         *       - references
         *       - base64
         *       - hex
         *       - bigByteArray
         *       - myStringArray
         */

        ctx = JAXBContextFactory.createContext(new Class[] {ExtObjectRoot.class, ExtObjectA.class,
                ExtObjectB.class, ExtObjectC.class}, ctxProperties);

        Document marshalDoc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();

        Marshaller m = ctx.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        m.marshal(getControlObjectComplete(), marshalDoc);

        if (DEBUG) {
            System.out.println("*** TEST COMPLETE MODEL ***");
            m.marshal(getControlObjectComplete(), System.out);
        }

        String[] extensions = new String[] {
                "directelem", "nullpol", "join", "idref", "xmllist", "references", "base64", "hex", /*"bigByteArray",*/ "myStringArray"
        };

        Node attNode = marshalDoc.getDocumentElement().getChildNodes().item(0).getChildNodes().item(0).getAttributes().getNamedItem("directatt");
        assertNotNull("'directatt' extension not found.", attNode);

        for (int i = 0; i < extensions.length; i++) {
            // Test that Extensions appear in the marshalled document
            NodeList nodeList = marshalDoc.getDocumentElement().getElementsByTagName(extensions[i]);
            boolean found = nodeList != null && nodeList.getLength() > 0;
            assertTrue("'" + extensions[i] + "' extension not found.", found);
        }

        Unmarshaller u = ctx.createUnmarshaller();
        ExtObjectRoot root = (ExtObjectRoot) u.unmarshal(marshalDoc);

        // Check that the Inverse Reference was set
        try {
            ExtObjectA a = root.flexObjectAs.get(0);
            ExtObjectB b = (ExtObjectB) a.get("join");
            List refs = (List) b.get("references");
            ExtObjectC c = (ExtObjectC) refs.get(0);
            assertTrue("Inverse Reference not set correctly.", c.get("inverse") == b);
        } catch (Exception e) {
            fail("Error testing inverse reference.");
        }

        // Check Binary formats
        String base64Str =
            XMLConversionManager.getDefaultXMLManager().convertObject(bytes, String.class, XMLConstants.BASE_64_BINARY_QNAME).toString();
        String hexStr =
            XMLConversionManager.getDefaultXMLManager().convertObject(bytes, String.class, XMLConstants.HEX_BINARY_QNAME).toString();

        Element docElement = marshalDoc.getDocumentElement();
        Element flexObjectAsElem = (Element) docElement.getChildNodes().item(0);
        Element base64Elem = (Element) flexObjectAsElem.getElementsByTagName("base64").item(0);
        Element hexElem = (Element) flexObjectAsElem.getElementsByTagName("hex").item(0);

        assertEquals(base64Str, base64Elem.getFirstChild().getNodeValue());
        assertEquals(hexStr, hexElem.getFirstChild().getNodeValue());
    }

    public void testSchemaValidationBasic() throws Exception {
        InputStream oxm = ClassLoader.getSystemClassLoader().getResourceAsStream(
            "org/eclipse/persistence/testing/jaxb/xmlvirtualaccessmethods/basic-eclipselink-oxm.xml");

        Map<String, Object> ctxProperties = new HashMap<String, Object>();
        ctxProperties.put(JAXBContextProperties.OXM_METADATA_SOURCE, oxm);

        ctx = JAXBContextFactory.createContext(new Class[] {Employee.class, PhoneNumber.class}, ctxProperties);

        validateAgainstSchema(ctx, getControlObjectBasic());
    }

    public void testSchemaValidationComplete() throws Exception {
        InputStream oxm = ClassLoader.getSystemClassLoader().getResourceAsStream(
            "org/eclipse/persistence/testing/jaxb/xmlvirtualaccessmethods/eclipselink-oxm.xml");

        Map<String, Object> ctxProperties = new HashMap<String, Object>();
        ctxProperties.put(JAXBContextProperties.OXM_METADATA_SOURCE, oxm);

        ctx = JAXBContextFactory.createContext(new Class[] {ExtObjectRoot.class, ExtObjectA.class,
                ExtObjectB.class, ExtObjectC.class}, ctxProperties);

        validateAgainstSchema(ctx, getControlObjectComplete());
    }

    private void validateAgainstSchema(JAXBContext ctx, Object obj) throws Exception {
        JAXBSource source = new JAXBSource(ctx, obj);

        // Generate Schemas
        StringOutputResolver sor = new StringOutputResolver();
        ctx.generateSchema(sor);

        if (DEBUG) {
            System.out.println("*** VALIDATE SCHEMA " + obj.getClass());
            System.out.println(sor.getSchemas());
            Marshaller m = ctx.createMarshaller();
            m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            m.marshal(obj, System.out);
        }

        // Build javax.xml.validation.Schema
        Schema schema;
        Source[] schemaSources = new StreamSource[sor.getSchemas().size()];
        SchemaFactory schemaFactory = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
        for (int i = 0; i < sor.getSchemas().size() ; i++) {
            StringReader r = new StringReader(sor.getSchemas().get(i));
            schemaSources[i] = new StreamSource(r);
        }
        schema = schemaFactory.newSchema(schemaSources);


        LogErrorHandler handler = new LogErrorHandler();
        Validator validator = schema.newValidator();
        validator.setErrorHandler(handler);
        validator.validate(source);

        assertEquals("Unexpected number of validation errors thrown.", 0, handler.getErrorCount());
    }

    // ========================================================================

    private Object getControlObjectBasic() {
        PhoneNumber p1 = new PhoneNumber();
        p1.setId(1);
        p1.setAreaCode(613);
        p1.setNumber(2832684);
        p1.setType("H");

        PhoneNumber p2 = new PhoneNumber();
        p2.setId(2);
        p2.setAreaCode(613);
        p2.setNumber(2884613);
        p2.setType("W");

        PhoneNumber p3 = new PhoneNumber();
        p3.setId(3);
        p3.setAreaCode(613);
        p3.setNumber(8500210);
        p3.setType("C");

        Employee e = new Employee();
        e.id = 1;
        e.firstName = "Rick";
        e.lastName = "Barkhouse";
        e.phoneNumbers.add(p1);
        e.phoneNumbers.add(p2);
        e.phoneNumbers.add(p3);

        e.extensions.put("salary", new BigDecimal(151755.75));
        e.setInt("age", 35);
        e.setInt("dept", 14113);

        PhoneNumber p4 = new PhoneNumber();
        p4.setId(4);
        p4.setAreaCode(555);
        p4.setNumber(8884441);
        p4.setType("Secret");
        p4.putExt("ext", "666");
        p4.putExt("countryCode", "GOTHAM");

        e.extensions.put("batphone", p4);

        LinkedList<PhoneNumber> forwards = new LinkedList<PhoneNumber>();
        forwards.add(p1);
        forwards.add(p2);
        forwards.add(p3);
        p4.putExt("forwards", forwards);

        return e;
    }

    private Object getControlObjectComplete() {
        ExtObjectC objC = new ExtObjectC();
        objC.set("directatt", "456");
        objC.set("directelem", "Baz1");

        ExtObjectC objC2 = new ExtObjectC();
        objC2.set("directatt", "457");
        objC2.set("directelem", "Baz2");

        ExtObjectB objB = new ExtObjectB();
        objB.set("directatt", "z123");
        objB.set("directelem", "Bar");

        ArrayList<ExtObjectC> references = new ArrayList<ExtObjectC>();
        references.add(objC);
        references.add(objC2);
        objB.set("references", references);
        objC.set("inverse", objB);
        objC2.set("inverse", objB);

        ExtObjectA objA = new ExtObjectA();
        objA.set("directatt", "888");
        objA.set("directelem", "Foo");
        objA.set("nullpol", null);
        objA.set("join", objB);
        objA.set("idref", objB);
        objA.set("anEnum", "N");

        ArrayList<String> xmllist = new ArrayList<String>();
        xmllist.add("ONE"); xmllist.add("TWO"); xmllist.add("THREE");
        objA.set("xmllist", xmllist);

        ArrayList elements = new ArrayList();
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(true);
        factory.setIgnoringElementContentWhitespace(true);
        try {
            DocumentBuilder builder = factory.newDocumentBuilder();
            InputStream xml = ClassLoader.getSystemClassLoader().getResourceAsStream(
                "org/eclipse/persistence/testing/jaxb/xmlvirtualaccessmethods/basic-eclipselink-oxm.xml");
            Document doc = builder.parse(xml);
            Element rootElem = doc.getDocumentElement();
            NodeList children = rootElem.getChildNodes();
            for(int i = 0; i < children.getLength(); i++) {
                if(children.item(i).getNodeType() == Element.ELEMENT_NODE) {
                    elements.add(children.item(i));
                }
            }
        } catch(Exception ex) {}
        objA.set("mixed", elements);

        objA.set("base64", bytes);
        objA.set("hex", bytes);
        objA.set("bigByteArray", bigBytes);

        String[] s = new String[] {"one", "two", "three", "for"};
        objA.set("myStringArray", s);

        ExtObjectRoot root = new ExtObjectRoot();
        root.flexObjectAs.add(objA);
        root.flexObjectBs.add(objB);

        return root;
    }

    private class LogErrorHandler implements ErrorHandler {
        private int errorCount = 0;

        @Override
        public void warning(SAXParseException exception) throws SAXException {
            errorCount++;
            if (DEBUG) {
                System.out.println("\nWARNING");
                System.out.println(exception.getMessage());
            }
            if (THROW_VALIDATION_ERRORS) throw exception;
        }

        @Override
        public void error(SAXParseException exception) throws SAXException {
            errorCount++;
            if (DEBUG) {
                System.out.println("\nERROR");
                System.out.println(exception.getMessage());
            }
            if (THROW_VALIDATION_ERRORS) throw exception;
        }

        @Override
        public void fatalError(SAXParseException exception) throws SAXException {
            errorCount++;
            if (DEBUG) {
                System.out.println("\nFATAL ERROR");
                exception.printStackTrace();
            }
            if (THROW_VALIDATION_ERRORS) throw exception;
        }

        public int getErrorCount() {
            return errorCount;
        }
    }

    private class StringOutputResolver extends SchemaOutputResolver {
        private HashMap<String, StringWriter> stringWriters;

        public StringOutputResolver() {
            stringWriters = new HashMap<String, StringWriter>();
        }

        @Override
        public Result createOutput(String arg0, String arg1) throws IOException {
            StringWriter sw = stringWriters.get(arg1);
            if (sw == null) {
                sw = new StringWriter();
                stringWriters.put(arg1, sw);
            }
            StreamResult sr = new StreamResult(sw);
            sr.setSystemId(arg1);
            return sr;
        }

        private List<String> getSchemas() {
            List<String> schemas = new ArrayList<String>();
            Iterator<StringWriter> it = stringWriters.values().iterator();
            while (it.hasNext()) {
                StringWriter sw = it.next();
                schemas.add(sw.toString());
            }
            return schemas;
        }
    }

}
