/*
 * Copyright (c) 2017, 2020 Oracle and/or its affiliates. All rights reserved.
 */

package javasoft.sqe.tests.bind.jaxbcontext;

import java.net.URL;
import javasoft.sqe.tests.api.jakarta.xml.bind.ErrorCollector;
import jakarta.xml.bind.Binder;
import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.JAXBIntrospector;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import javasoft.sqe.javatest.Status;
import java.io.PrintWriter;
import javasoft.sqe.tests.api.jakarta.xml.bind.CTTest;

public class JAXBContext_CTTests extends CTTest {

    /**
     * Command line starter.
     */
    public static void main(String[] args) {
        JAXBContext_CTTests test = new JAXBContext_CTTests();
        PrintWriter err = new PrintWriter(System.err, true);
        PrintWriter out = new PrintWriter(System.out, true);
        Status status = test.run(args, err, out);
        err.flush();
        out.flush();
        status.exit();
    }

    public Status createMarshaller001( ) {
        ErrorCollector eh = new ErrorCollector();

        try {
            JAXBContext jc = getJAXBContext();

            Object docInstance = (new ObjectFactory()).createRoot("createMarshaller001");

            Marshaller m = jc.createMarshaller();
            if (m == null) {
                return Status.failed("createMarshaller returns null");
            }

            m.setEventHandler(eh);
            m.marshal(docInstance, getOut());

            return Status.passed("OK");

        } catch (JAXBException jaxbe) {
            jaxbe.printStackTrace(ref);
            return Status.failed(jaxbe.toString());
        } finally {
            eh.printEvents(ref);
        }
    }

    public Status createUnmarshaller001( ) {
        ErrorCollector eh = new ErrorCollector();

        try {
            JAXBContext jc = getJAXBContext();
            Unmarshaller u = jc.createUnmarshaller();

            eh.setParent(u.getEventHandler());
            u.setSchema(schema);
            u.setEventHandler(eh);

            Object obj = u.unmarshal(getDocumentURL("JAXBContext.xml"));

            if (!eh.hasEvents()) {
                return Status.passed("OKAY");
            }

            return Status.failed("No exception is thrown but some error events are handled");

        } catch (JAXBException jaxbe) {
            if (!eh.hasEvents()) {
                return Status.failed("no error events are handled but " + jaxbe + " is thrown");
            }
            return Status.failed(jaxbe.toString());
        } finally {
            eh.printEvents(ref);
        }
    }

    public Status createBinder001( ) {
        ErrorCollector eh = new ErrorCollector();
		try{
			JAXBContext jc = getJAXBContext();
			Binder<Node> binder = jc.createBinder();
			eh.setParent(binder.getEventHandler());
			binder.setEventHandler(eh);
			URL documentURL = getDocumentURL("JAXBContext.xml");
			DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
			docBuilderFactory.setNamespaceAware(true);
			DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
			Document doc = docBuilder.parse(documentURL.openStream());
			Object o = binder.unmarshal(doc);
			//perform updateXML and updateJAXB without changing
			//document and object
			binder.updateXML(o);
			binder.updateJAXB(doc);
			if(!eh.hasEvents()){
				return Status.passed("OK");
			}
			return Status.failed("No exception is thrown but some error events are handled");
		}catch(JAXBException jaxbe){
		    jaxbe.printStackTrace(ref);
			if (!eh.hasEvents()) {
                return Status.failed("no error events are handled but " + jaxbe + " is thrown");
            }
            return Status.failed(jaxbe.toString());
		}catch(Exception x){
		    x.printStackTrace(ref);
			return Status.failed(x.toString());
		}finally{
			eh.printEvents(ref);
		}
    }

    public Status createBinder002( ) {
        try{
			JAXBContext jc = getJAXBContext();
			Binder<Node> binder = jc.createBinder(Node.class);
            Binder<Node> binder1 = jc.createBinder(Node.class);
            if( binder == binder1 )
                return Status.failed( "public <T> Binder<T> createBinder(Class<T> domType) returns same object twice" );
		} catch( Exception x ){
            x.printStackTrace(ref);
            return Status.failed( x.toString() );
		}
        return Status.passed("OK");
    }

    public Status createJAXBIntrospector001( ) {
        JAXBContext jaxbContext;
        try {
            jaxbContext = getJAXBContext();
        } catch (JAXBException e) {
            e.printStackTrace(ref);
            return Status.failed("Unable to create valid context");
        }
        JAXBIntrospector introspector = jaxbContext.createJAXBIntrospector();
        if(introspector == null){
            return Status.failed("JAXBIntrospector is not created");
        }
        Object o = unmarshal("JAXBContext.xml");
        if(!introspector.isElement(o)){
            return Status.failed("Introspector is created successfully, but it does " +
                    "not recognize root of unmarshalled object tree as element.");
        }
        javax.xml.namespace.QName qName = introspector.getElementName(o);
        if(!"root".equals(qName.getLocalPart())||
           !"api/JAXBContext".equals(qName.getNamespaceURI())){
            return Status.failed("Introspector returns invalid element name.");
        }

        if(!"createUnmarshaller001".equals(JAXBIntrospector.getValue(o))){
            return Status.failed("Introspector returns invalid element value.");
        }
        return Status.passed("Ok");
    }


}

