/*
 * Copyright (c) 1998, 2019 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:
//     Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.internal.oxm;

import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.namespace.QName;

import org.eclipse.persistence.exceptions.DescriptorException;
import org.eclipse.persistence.exceptions.XMLMarshalException;
import org.eclipse.persistence.internal.core.helper.CoreField;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;
import org.eclipse.persistence.internal.oxm.mappings.Descriptor;
import org.eclipse.persistence.internal.oxm.mappings.Field;
import org.eclipse.persistence.internal.oxm.mappings.Mapping;
import org.eclipse.persistence.internal.oxm.mappings.UnmarshalKeepAsElementPolicy;
import org.eclipse.persistence.internal.oxm.mappings.XMLConverterMapping;
import org.eclipse.persistence.internal.oxm.record.MarshalRecord;
import org.eclipse.persistence.internal.oxm.record.UnmarshalRecord;
import org.eclipse.persistence.internal.oxm.record.XMLReader;
import org.eclipse.persistence.internal.oxm.record.XMLRecord;
import org.eclipse.persistence.internal.oxm.record.deferred.DescriptorNotFoundContentHandler;
import org.eclipse.persistence.core.queries.CoreAttributeGroup;
import org.eclipse.persistence.core.queries.CoreAttributeItem;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

public abstract class XMLRelationshipMappingNodeValue extends MappingNodeValue {

    // Protected to public
    public void processChild(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Attributes atts, Descriptor xmlDescriptor, Mapping mapping) throws SAXException {
        if(xmlDescriptor == null){
            //Use the DescriptorNotFoundContentHandler to "look ahead" and determine if this is a simple or complex element
            //if it is complex the exception should be thrown
            DescriptorNotFoundContentHandler handler = new DescriptorNotFoundContentHandler(unmarshalRecord, mapping);
            String qnameString = xPathFragment.getLocalName();
            if(xPathFragment.getPrefix() != null) {
                qnameString = xPathFragment.getPrefix()  +Constants.COLON + qnameString;
            }
            handler.startElement(xPathFragment.getNamespaceURI(), xPathFragment.getLocalName(), qnameString, atts);
            XMLReader xmlReader = unmarshalRecord.getXMLReader();
            xmlReader.setContentHandler(handler);
            xmlReader.setLexicalHandler(handler);
            return;
        }

        if (xmlDescriptor.hasInheritance()) {
            unmarshalRecord.setAttributes(atts);
            CoreAbstractSession session = unmarshalRecord.getSession();
            Class classValue = ((ObjectBuilder)xmlDescriptor.getObjectBuilder()).classFromRow(unmarshalRecord, session);
            if (classValue == null) {
                // no xsi:type attribute - look for type indicator on the default root element
                XPathQName leafElementType = unmarshalRecord.getLeafElementType();

                // if we have a user-set type, try to get the class from the inheritance policy
                if (leafElementType != null) {
                    Object indicator = xmlDescriptor.getInheritancePolicy().getClassIndicatorMapping().get(leafElementType);
                    if(indicator != null) {
                        classValue = (Class)indicator;
                    }
                }
                // if xsi:type is overriden by JSON_TYPE_ATTRIBUTE_NAME unmarshall property
                if (classValue == null && unmarshalRecord.getUnmarshaller().isApplicationJSON() &&
                        unmarshalRecord.getUnmarshaller().getJsonTypeConfiguration().getJsonTypeAttributeName() != null && atts.getValue(unmarshalRecord.getUnmarshaller().getJsonTypeConfiguration().getJsonTypeAttributeName()) != null) {
                    QName qname = new QName(xmlDescriptor.getSchemaReference().getSchemaContextAsQName().getNamespaceURI(), atts.getValue(unmarshalRecord.getUnmarshaller().getJsonTypeConfiguration().getJsonTypeAttributeName()));
                    classValue = (Class)xmlDescriptor.getInheritancePolicy().getClassIndicatorMapping().get(qname);
                }
            }
            if (classValue != null) {
                xmlDescriptor = (Descriptor)session.getDescriptor(classValue);
            } else {
                // since there is no xsi:type attribute, use the reference descriptor set
                // on the mapping -  make sure it is non-abstract
                if (Modifier.isAbstract(xmlDescriptor.getJavaClass().getModifiers())) {
                    // need to throw an exception here
                    throw DescriptorException.missingClassIndicatorField(unmarshalRecord, (org.eclipse.persistence.oxm.XMLDescriptor)xmlDescriptor.getInheritancePolicy().getDescriptor());
                }
            }
        }
        ObjectBuilder targetObjectBuilder = (ObjectBuilder)xmlDescriptor.getObjectBuilder();

        CoreAttributeGroup group = unmarshalRecord.getUnmarshalAttributeGroup();
        CoreAttributeGroup nestedGroup = null;
        if(group == XMLRecord.DEFAULT_ATTRIBUTE_GROUP) {
            nestedGroup = group;
        }
        if(nestedGroup == null) {
            CoreAttributeItem item = group.getItem(getMapping().getAttributeName());
            nestedGroup = item.getGroup(xmlDescriptor.getJavaClass());
            if(nestedGroup == null) {
                if(item.getGroup() == null) {
                    nestedGroup = XMLRecord.DEFAULT_ATTRIBUTE_GROUP;
                } else {
                    nestedGroup = item.getGroup();
                }
            }
        }
        UnmarshalRecord childRecord = unmarshalRecord.getChildUnmarshalRecord(targetObjectBuilder);
        childRecord.setAttributes(atts);
        childRecord.startDocument();
        childRecord.initializeRecord(null);
        childRecord.setUnmarshalAttributeGroup(nestedGroup);
        childRecord.startElement(xPathFragment.getNamespaceURI(), xPathFragment.getLocalName(), xPathFragment.getShortName(), atts);

        XMLReader xmlReader = unmarshalRecord.getXMLReader();
        xmlReader.setContentHandler(childRecord);
        xmlReader.setLexicalHandler(childRecord);
    }

    protected Descriptor findReferenceDescriptor(XPathFragment xPathFragment, UnmarshalRecord unmarshalRecord, Attributes atts, Mapping mapping, UnmarshalKeepAsElementPolicy policy) {
        Descriptor returnDescriptor = null;
        //try xsi:type
        if(atts != null){
            Context xmlContext = unmarshalRecord.getUnmarshaller().getContext();
            String schemaType = null;
            if(unmarshalRecord.isNamespaceAware()){
                schemaType = atts.getValue(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, Constants.SCHEMA_TYPE_ATTRIBUTE);
            }else{
                schemaType = atts.getValue(Constants.EMPTY_STRING, Constants.SCHEMA_TYPE_ATTRIBUTE);
            }


            if(schemaType != null){
                schemaType = schemaType.trim();
                if(schemaType.length() > 0) {
                    XPathFragment frag = new XPathFragment(schemaType, unmarshalRecord.getNamespaceSeparator(), unmarshalRecord.isNamespaceAware());

                    QName qname = null;
                    if (frag.hasNamespace()) {
                        String prefix = frag.getPrefix();
                        String url = unmarshalRecord.resolveNamespacePrefix(prefix);
                        frag.setNamespaceURI(url);

                        qname = new QName(url, frag.getLocalName());
                        unmarshalRecord.setTypeQName(qname);
                    } else {
                        String url = unmarshalRecord.resolveNamespacePrefix(Constants.EMPTY_STRING);
                        if(null != url) {
                            frag.setNamespaceURI(url);

                            qname = new QName(url, frag.getLocalName());
                            unmarshalRecord.setTypeQName(qname);
                        }
                        if(!unmarshalRecord.isNamespaceAware() || !unmarshalRecord.getUnmarshaller().getJsonTypeConfiguration().useXsdTypesWithPrefix()){
                            qname = new QName(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI ,frag.getLocalName());
                            unmarshalRecord.setTypeQName(qname);
                        }
                    }
                    returnDescriptor = xmlContext.getDescriptorByGlobalType(frag);
                    if(returnDescriptor == null){
                        if(policy == null || (!policy.isKeepUnknownAsElement() && !policy.isKeepAllAsElement())){
                            Class theClass = unmarshalRecord.getConversionManager().javaType(qname);
                            if(theClass == null){
                                throw XMLMarshalException.unknownXsiTypeValue(schemaType, mapping);
                            }
                        }
                    }
               }
            }
        }
        return returnDescriptor;
    }

    protected void addTypeAttribute(Descriptor descriptor, MarshalRecord marshalRecord, String schemaContext) {
        String typeValue = schemaContext.substring(1);

        String xsiPrefix = null;
        if (descriptor.getNamespaceResolver() != null) {
            xsiPrefix = descriptor.getNamespaceResolver().resolveNamespaceURI(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
        } else {
            xsiPrefix = Constants.SCHEMA_INSTANCE_PREFIX;
            marshalRecord.namespaceDeclaration(xsiPrefix,  javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);

        }
        if (xsiPrefix == null) {
            xsiPrefix = descriptor.getNamespaceResolver().generatePrefix(Constants.SCHEMA_INSTANCE_PREFIX);
            marshalRecord.namespaceDeclaration(xsiPrefix,  javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI);
        }
        marshalRecord.attribute(javax.xml.XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, Constants.SCHEMA_TYPE_ATTRIBUTE, xsiPrefix + Constants.COLON + Constants.SCHEMA_TYPE_ATTRIBUTE, typeValue);
    }

    protected void writeExtraNamespaces(List extraNamespaces, XMLRecord xmlRecord, CoreAbstractSession session) {
        if (extraNamespaces == null) {
            return;
        }
        for (int i = 0, extraNamespacesSize=extraNamespaces.size(); i < extraNamespacesSize; i++) {
            Namespace next = (Namespace)extraNamespaces.get(i);
            String prefix = next.getPrefix();
            if(((MarshalRecord)xmlRecord).hasCustomNamespaceMapper()) {
                prefix = ((MarshalRecord)xmlRecord).getNamespaceResolver().resolveNamespaceURI(next.getNamespaceURI());
            }
           ((MarshalRecord)xmlRecord).namespaceDeclaration(prefix, next.getNamespaceURI());
        }

    }

    protected void setupHandlerForKeepAsElementPolicy(UnmarshalRecord unmarshalRecord, XPathFragment xPathFragment, Attributes atts) {
        SAXFragmentBuilder builder = unmarshalRecord.getFragmentBuilder();
        builder.setOwningRecord(unmarshalRecord);
        builder.setMixedContent(xPathNode.getUnmarshalNodeValue().isMixedContentNodeValue());
        try {
            String namespaceURI = Constants.EMPTY_STRING;
            if (xPathFragment.getNamespaceURI() != null) {
                namespaceURI = xPathFragment.getNamespaceURI();
            }
            String qName = xPathFragment.getLocalName();
            if (xPathFragment.getPrefix() != null) {
                qName = xPathFragment.getPrefix() + unmarshalRecord.getNamespaceSeparator() + qName;
            }

            if(!(unmarshalRecord.getPrefixesForFragment().isEmpty())) {
                for(Entry<String, String> next:((Map<String, String>) unmarshalRecord.getPrefixesForFragment()).entrySet()) {
                    builder.startPrefixMapping(next.getKey(), next.getValue());
                }
            }
            builder.startElement(namespaceURI, xPathFragment.getLocalName(), qName, atts);
            XMLReader xmlReader = unmarshalRecord.getXMLReader();
            xmlReader.setContentHandler(builder);
            xmlReader.setLexicalHandler(null);
        } catch (SAXException ex) {
        }
    }

    protected void setOrAddAttributeValueForKeepAsElement(SAXFragmentBuilder builder, Mapping mapping, XMLConverterMapping converter, UnmarshalRecord unmarshalRecord, boolean isCollection, Object collection) {
        Object node = builder.getNodes().remove(builder.getNodes().size() -1);
        if (converter != null) {
            node = converter.convertDataValueToObjectValue(node, unmarshalRecord.getSession(), unmarshalRecord.getUnmarshaller());
        }

        if (isCollection) {
            if(collection != null){
                unmarshalRecord.addAttributeValue((ContainerValue) this, node, collection);
            }else{
                unmarshalRecord.addAttributeValue((ContainerValue) this, node);
            }
        } else {
            unmarshalRecord.setAttributeValue(node, mapping);
        }
    }

    protected void endElementProcessText(UnmarshalRecord unmarshalRecord, XMLConverterMapping converter, XPathFragment xPathFragment, Object collection) {
        Object value = unmarshalRecord.getCharacters().toString();

        unmarshalRecord.resetStringBuffer();
        if(!unmarshalRecord.isNil()) {
            QName qname = unmarshalRecord.getTypeQName();
            if (qname == null) {
                if(Constants.EMPTY_STRING.equals(value)) {
                    value = null;
                }
            } else {
                ConversionManager conversionManager = unmarshalRecord.getConversionManager();
                if(qname.equals(Constants.QNAME_QNAME)) {
                    value = conversionManager.buildQNameFromString((String)value, unmarshalRecord);
                } else {
                    Class theClass = getClassForQName(qname, conversionManager);
                    if (theClass != null) {
                        value = conversionManager.convertObject(value, theClass, qname);
                    }
                }
            }
            value = converter.convertDataValueToObjectValue(value, unmarshalRecord.getSession(), unmarshalRecord.getUnmarshaller());
            setOrAddAttributeValue(unmarshalRecord, value, xPathFragment, collection);
        }
    }

    protected Class getClassForQName(QName qname, ConversionManager conversionManager){
        CoreField field = getMapping().getField();
        if(field != null){
            return ((Field)field).getJavaClass(qname, conversionManager);
        }
        return conversionManager.javaType(qname);
    }


    protected abstract void setOrAddAttributeValue(UnmarshalRecord unmarshalRecord, Object value, XPathFragment xPathFragment, Object collection);
}
