/*******************************************************************************
* Copyright (c) 1998, 2008 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
* mmacivor - June 05/2008 - 1.0 - Initial implementation
******************************************************************************/
package org.eclipse.persistence.internal.jaxb;

import org.eclipse.persistence.mappings.AttributeAccessor;
import org.eclipse.persistence.exceptions.DescriptorException;
import org.eclipse.persistence.internal.queries.ContainerPolicy;
import org.eclipse.persistence.oxm.XMLRoot;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;

public class JAXBElementAttributeAccessor extends AttributeAccessor {
	private AttributeAccessor nestedAccessor;
	private ContainerPolicy containerPolicy;
	private boolean isContainer;
	
	public JAXBElementAttributeAccessor(AttributeAccessor nestedAccessor) {
		this.nestedAccessor = nestedAccessor;
		this.isContainer = false;
	}
	public JAXBElementAttributeAccessor(AttributeAccessor nestedAccessor, ContainerPolicy containerPolicy) {
		this.nestedAccessor = nestedAccessor;
		this.containerPolicy = containerPolicy;
		this.isContainer = true;
	}
	
	public Object getAttributeValueFromObject(Object object) {
		Object value = nestedAccessor.getAttributeValueFromObject(object);
		//Swap JAXBElements for XMLRoots
		//May need a better way to do this for perf.
		if(isContainer) {
			Object results = containerPolicy.containerInstance(containerPolicy.sizeFor(value));
			Object iterator = containerPolicy.iteratorFor(value);
			while(containerPolicy.hasNext(iterator)) {
				Object next = containerPolicy.next(iterator, null);
				if(next instanceof JAXBElement) {
					JAXBElement element = (JAXBElement)next;
					XMLRoot root = new XMLRoot();
					root.setLocalName(element.getName().getLocalPart());
					root.setNamespaceURI(element.getName().getNamespaceURI());
					root.setObject(element.getValue());
					containerPolicy.addInto(root, results, null);
				} else {
					containerPolicy.addInto(next, results, null);
				}
			}
			value = results;
		} else {
			if(value instanceof JAXBElement) {
				JAXBElement element = (JAXBElement)value;
				XMLRoot root = new XMLRoot();
				root.setLocalName(element.getName().getLocalPart());
				root.setNamespaceURI(element.getName().getNamespaceURI());
				root.setObject(element.getValue());
				value = root;
			}
		}
		return value;
	}
	
	public void setAttributeValueInObject(Object object, Object value) {
		Object attributeValue = value;
		if(isContainer) {
			Object results = containerPolicy.containerInstance(containerPolicy.sizeFor(attributeValue));
			Object iterator = containerPolicy.iteratorFor(attributeValue);
			while(containerPolicy.hasNext(iterator)) {
				Object next = containerPolicy.next(iterator, null);
				if(next instanceof XMLRoot) {
					XMLRoot root = (XMLRoot)next;
					QName name = new QName(root.getNamespaceURI(), root.getLocalName());
					JAXBElement element = new JAXBElement(name, root.getObject().getClass(), root.getObject());
					containerPolicy.addInto(element, results, null);
				} else {
					containerPolicy.addInto(next, results, null);
				}
			}
			attributeValue = results;
		} else {
			if(attributeValue instanceof XMLRoot) {
				XMLRoot root = (XMLRoot)attributeValue;
				QName name = new QName(root.getNamespaceURI(), root.getLocalName());
				JAXBElement element = new JAXBElement(name, root.getObject().getClass(), root.getObject());
				attributeValue = element;
			}			
		}
		nestedAccessor.setAttributeValueInObject(object, attributeValue);
	}
	
    public void initializeAttributes(Class theJavaClass) throws DescriptorException {
    	nestedAccessor.initializeAttributes(theJavaClass);
    }
	
}
