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

package javasoft.sqe.tests.bind.binder;

import java.io.IOException;
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.JAXBElement;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import javasoft.sqe.javatest.Status;
import java.io.PrintWriter;
import javasoft.sqe.tests.api.jakarta.xml.bind.CTTest;

public class Binder_CTTests extends CTTest {

    /**
     * Command line starter.
     */
    public static void main(String[] args) {
        Binder_CTTests test = new Binder_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 Binder<Node> getBinder() throws JAXBException{
    JAXBContext jaxbContext = getJAXBContext();
    return jaxbContext.createBinder();
  }

  public Document getDocument(String doc) throws ParserConfigurationException, SAXException, IOException{
    URL documentURL = getDocumentURL(doc);
    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    documentBuilderFactory.setNamespaceAware(true);
    DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
    return documentBuilder.parse(documentURL.openStream());
  }

    Document createNewDocument() {
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
        documentBuilderFactory.setNamespaceAware(true);
        try {
            return documentBuilderFactory.newDocumentBuilder().newDocument();
        } catch ( ParserConfigurationException x ){
            x.printStackTrace(ref);
            throw new RuntimeException(x);
        }
    }

    public Status navigation001( ) {
        Binder<Node> binder;
        try {
            binder = getBinder();
        } catch (JAXBException e) {
            e.printStackTrace(ref);
            return Status.failed("Unable to create valid context or binder");
        }
        Document doc;
        try {
           doc = getDocument("Binder.xml");
        } catch (Exception e) {
           e.printStackTrace(ref);
           return Status.failed("Exception is thrown on parsing XML to DOM tree: "+e);
        }
        Object jaxbObject;
        try {
            jaxbObject = binder.unmarshal(doc.getDocumentElement());
        } catch (JAXBException e) {
            e.printStackTrace(ref);
            return Status.failed("Error on unmarshal document");
        }
        PurchaseOrder po = null;
        if (jaxbObject instanceof JAXBElement) {
            JAXBElement jaxbElement = (JAXBElement) jaxbObject;
            if(jaxbElement.getValue() instanceof PurchaseOrder){
                po = (PurchaseOrder)jaxbElement.getValue();
            }
        }
        if(po == null){
            return Status.failed("Unrecognized unmarshal result");
        }


        Address shipTo = po.getShipTo();

        Element poElem = doc.getDocumentElement();
        Element shipToElem = null;
        for(Node n = poElem.getFirstChild();n != null; n = n.getNextSibling()){
            if(n.getNodeType() == Node.ELEMENT_NODE && "shipTo".equals(n.getLocalName())){
                shipToElem = (Element) n;
                break;
            }
        }
        if(shipToElem == null){
            return Status.failed("shipTo element not found in DOM tree");
        }

        if(binder.getJAXBNode(shipToElem) == shipTo){
            return Status.passed("Ok");
        }

        return Status.failed("getJAXBNode failed");
    }

    public Status getJAXBNode002( ) {
        try {
        getBinder().getJAXBNode(null);
        return Status.failed( "expected IllegalArgumentException wasn't thrown" );
    } catch( IllegalArgumentException x ){
        return Status.passed("OK");
    } catch (JAXBException e) {
        e.printStackTrace(ref);
        return Status.failed(e.toString());
    }
    }

    public Status getJAXBNode003( ) {
        try {
        Document doc = getDocument("Binder.xml");
        Binder<Node> binder = getBinder();
        if( binder.getJAXBNode( doc ) != null )
            return Status.failed( "binder.getJAXBNode( 'unknown Node' ) returns not null" );
        return Status.passed("OK");
    } catch( Exception e ) {
        e.printStackTrace(ref);
        return Status.failed(e.toString());
    }
    }

    public Status getJAXBNode004( ) {
        try {
        Document doc = getDocument("Binder.xml");
        Binder<Node> binder = getBinder();
        Object jaxbObject = binder.unmarshal(doc.getDocumentElement());
        if( binder.getJAXBNode( doc.getDocumentElement().appendChild( doc.createElement( "newElement" ) ) ) != null )
            return Status.failed( "binder.getJAXBNode( 'Node without corresponding Jakarta XML Binding object' ) returns not null" );
        return Status.passed("OK");
    } catch( Exception e ) {
        e.printStackTrace(ref);
        return Status.failed(e.toString());
    }
    }

    public Status navigation002( ) {
        Binder<Node> binder;
        try {
            binder = getBinder();
        } catch (JAXBException e) {
            e.printStackTrace(ref);
            return Status.failed("Unable to create valid context or binder");
        }
        Document doc;
        try {
           doc = getDocument("Binder.xml");
        } catch (Exception e) {
           e.printStackTrace(ref);
           return Status.failed("Exception is thrown on parsing XML to DOM tree: "+e);
        }
        Object jaxbObject;
        try {
            jaxbObject = binder.unmarshal(doc.getDocumentElement());
        } catch (JAXBException e) {
            e.printStackTrace(ref);
            return Status.failed("Error on unmarshal document");
        }
        PurchaseOrder po = null;
        if (jaxbObject instanceof JAXBElement) {
            JAXBElement jaxbElement = (JAXBElement) jaxbObject;
            if(jaxbElement.getValue() instanceof PurchaseOrder){
                po = (PurchaseOrder)jaxbElement.getValue();
            }
        }
        if(po == null){
            return Status.failed("Unrecognized unmarshal result");
        }

        Address shipTo = po.getShipTo();

        Element poElem = doc.getDocumentElement();
        Element shipToElem = null;
        for(Node n = poElem.getFirstChild();n != null; n = n.getNextSibling()){
            if(n.getNodeType() == Node.ELEMENT_NODE && "shipTo".equals(n.getLocalName())){
                shipToElem = (Element) n;
                break;
            }
        }
        if(shipToElem == null){
            return Status.failed("shipTo element not found in DOM tree");
        }

        if(binder.getXMLNode(shipTo) == shipToElem){
            return Status.passed("Ok");
        }

        return Status.failed("getXMLNode failed");
    }

    public Status getXMLNode002( ) {
        try {
        getBinder().getXMLNode(null);
        return Status.failed( "expected IllegalArgumentException wasn't thrown" );
    } catch( IllegalArgumentException x ){
        return Status.passed("OK");
    } catch (JAXBException e) {
        e.printStackTrace(ref);
        return Status.failed(e.toString());
    }
    }

    public Status getXMLNode003( ) {
        try {
        if( getBinder().getXMLNode(new PurchaseOrder()) != null )
            return Status.failed( "getXMLNode( 'unknown Jakarta XML Binding object' ) isn't null" );
        return Status.passed("OK");
    } catch (JAXBException e) {
        e.printStackTrace(ref);
        return Status.failed(e.toString());
    }
    }

    public Status getXMLNode004( ) {
        try {
        Document doc = getDocument("Binder.xml");
        Binder<Node> binder = getBinder();
        PurchaseOrder po =
            (PurchaseOrder)((JAXBElement)binder.unmarshal(doc.getDocumentElement())).getValue();
        if( binder.getXMLNode( po.getShipTo() ) == null )
            return Status.failed( "binder.getXMLNode( 'Jakarta XML Binding object with corresponding Node' ) returns null" );
        po.setShipTo( new Address() );
        if( binder.getXMLNode( po.getShipTo() ) != null )
            return Status.failed( "binder.getXMLNode( 'Jakarta XML Binding object without corresponding Node' ) returns not null" );
        return Status.passed("OK");
    } catch( Exception e ) {
        e.printStackTrace(ref);
        return Status.failed(e.toString());
    }
    }

    public Status update001( ) {
        Binder<Node> binder;
        try {
            binder = getBinder();
        } catch (JAXBException e) {
            e.printStackTrace(ref);
            return Status.failed("Unable to create valid context or binder");
        }
        Document doc;
        try {
           doc = getDocument("Binder.xml");
        } catch (Exception e) {
           e.printStackTrace(ref);
           return Status.failed("Exception is thrown on parsing XML to DOM tree: "+e);
        }
        Object jaxbObject;
        try {
            jaxbObject = binder.unmarshal(doc.getDocumentElement());
        } catch (JAXBException e) {
            e.printStackTrace(ref);
            return Status.failed("Error on unmarshal document");
        }
        PurchaseOrder po = null;
        if (jaxbObject instanceof JAXBElement) {
            JAXBElement jaxbElement = (JAXBElement) jaxbObject;
            if(jaxbElement.getValue() instanceof PurchaseOrder){
                po = (PurchaseOrder)jaxbElement.getValue();
            }
        }
        if(po == null){
            return Status.failed("Unrecognized unmarshal result");
        }

        po.getShipTo().setName("John Smith");
        Element poElement = doc.getDocumentElement();
        try {
            poElement = (Element) binder.updateXML(jaxbObject,poElement);
        } catch (JAXBException e) {
            e.printStackTrace(ref);
            return Status.failed("Binder.updateXML(jaxbObject,node) has thrown JAXBException: "+e);
        }

        NodeList list = poElement.getElementsByTagNameNS("*","name");
        if(list.getLength() != 1){
            return Status.failed("Document structure changed");
        }
        Element nameElement = (Element) list.item(0);
        StringBuffer text = new StringBuffer();
        for(Node n = nameElement.getFirstChild(); n != null; n = n.getNextSibling()){
            switch(n.getNodeType()){
            case Node.TEXT_NODE:
            case Node.CDATA_SECTION_NODE:
                text.append(n.getNodeValue());
                break;
            }
        }
        if(!text.toString().contains("John Smith")){
            return Status.failed("Binder.updateXML(jaxbObject,node) did not updated xml node");
        }
        return Status.passed("Ok");
    }

    public Status updateXML002( ) {
        try {
        getBinder().updateXML(null);
        return Status.failed( "expected IllegalArgumentException was not thrown" );
    } catch( IllegalArgumentException x ){
        // OK
    } catch( JAXBException x ){
        x.printStackTrace(ref);
        return Status.failed( x.toString() );
    }
    return Status.passed("Ok");
    }

    public Status updateXML004( ) {
        try {
        Document doc = getDocument("Binder.xml");
        Binder<Node> binder = getBinder();
        PurchaseOrder po = (PurchaseOrder)((JAXBElement)binder.unmarshal(doc.getDocumentElement())).getValue();
        try {
            binder.updateXML(null, doc.getDocumentElement());
            return Status.failed( "expected IllegalArgumentException was not thrown. updateXML(null, Node)" );
        } catch(IllegalArgumentException x) {}
        try {
            binder.updateXML(po, null);
            return Status.failed( "expected IllegalArgumentException was not thrown. updateXML(Object, null)" );
        } catch(IllegalArgumentException x) {}
        try {
            binder.updateXML(null, null);
            return Status.failed( "expected IllegalArgumentException was not thrown. updateXML(null, null)" );
        } catch(IllegalArgumentException x) {}
    } catch( Exception x ){
        x.printStackTrace(ref);
        return Status.failed( x.toString() );
    }
    return Status.passed("Ok");
    }

    public Status updateXML005( ) {
        try {
        Binder<Node> binder = getBinder();
        List list = new List( 1, new List( 2, new List( 3 ) ) );
        Document doc;
        binder.marshal( list, doc = createNewDocument() );
        binder.updateXML( list, binder.getXMLNode( list.next ) );
    } catch( JAXBException x ){
        x.printStackTrace(ref);
        return Status.failed( x.toString() );
    }
    return Status.passed("Ok");
    }

    public Status update002( ) {
        Binder<Node> binder;
        try {
            binder = getBinder();
        } catch (JAXBException e) {
            e.printStackTrace(ref);
            return Status.failed("Unable to create valid context or binder");
        }
        Document doc;
        try {
           doc = getDocument("Binder.xml");
        } catch (Exception e) {
           e.printStackTrace(ref);
           return Status.failed("Exception is thrown on parsing XML to DOM tree: "+e);
        }
        Object jaxbObject;
        try {
            jaxbObject = binder.unmarshal(doc.getDocumentElement());
        } catch (JAXBException e) {
            e.printStackTrace(ref);
            return Status.failed("Error on unmarshal document");
        }

        PurchaseOrder po = null;
        if (jaxbObject instanceof JAXBElement) {
            JAXBElement jaxbElement = (JAXBElement) jaxbObject;
            if(jaxbElement.getValue() instanceof PurchaseOrder){
                po = (PurchaseOrder)jaxbElement.getValue();
            }
        }
        if(po == null){
            return Status.failed("Unrecognized unmarshal result");
        }

        NodeList nodeList = doc.getDocumentElement().getElementsByTagNameNS("*","name");
        Element nameElement = (Element) nodeList.item(0);
        for(Node n = nameElement.getFirstChild();n != null; n = n.getNextSibling()){
            if(n.getNodeType() == Node.TEXT_NODE){
                n.setNodeValue("John Smith");
            }
        }

        try {
            jaxbObject = binder.updateJAXB(doc.getDocumentElement());
        } catch (JAXBException e) {
            e.printStackTrace(ref);
            return Status.failed("Binder.updateJAXB(Node) has thrown JAXBException: "+e);
        }

        po = null;
        if (jaxbObject instanceof JAXBElement) {
            JAXBElement jaxbElement = (JAXBElement) jaxbObject;
            if(jaxbElement.getValue() instanceof PurchaseOrder){
                po = (PurchaseOrder)jaxbElement.getValue();
            }
        }
        if(po == null){
            return Status.failed("Unrecognized updateJAXB result");
        }

        if(!po.getShipTo().getName().contains("John Smith")){
            return Status.failed("Binder.updateJAXB(Node) failed");
        }
        return Status.passed("Ok");
    }

    public Status updateJAXB002( ) {
        try {
        getBinder().updateJAXB(null);
        return Status.failed( "expected IllegalArgumentException was not thrown" );
    } catch( IllegalArgumentException x ){
        // OK
    } catch( JAXBException x ){
        x.printStackTrace(ref);
        return Status.failed( x.toString() );
    }
    return Status.passed("Ok");
    }

    public Status updateJAXB003( ) {
        try {
        Document doc = getDocument("Binder.xml");
        Binder<Node> binder = getBinder();
        PurchaseOrder po = (PurchaseOrder)((JAXBElement)binder.unmarshal(doc.getDocumentElement())).getValue();
        try {
            binder.updateJAXB( doc.createElement("newElement") );
            return Status.failed( "expected JAXBException was not thrown" );
        } catch( JAXBException x ){
            // OK
        }
    } catch( Exception x ){
        x.printStackTrace(ref);
        return Status.failed( x.toString() );
    }
    return Status.passed("Ok");
    }


}

