/**
 * 
 */


package gov.va.med.cds.persistence.hibernate;


import java.util.List;

import org.dom4j.Element;
import org.hibernate.Session;


/**
 * @author DNS   egberb
 *
 */
public class Dom4JElementMergeWritableHibernatePersistenceManager
    extends
        WriteableHibernatePersistenceManager
{
	
	HibernateEntityLocatorInterface<Element> updateEntityLocator = null;
	
    @Override
    protected void updateData( Session session, Object aObject )
        throws InstantiationException,
            IllegalAccessException
    {
        if ( aObject instanceof Element )
        {
            // get the id of the entity to be updated.
            Element unmanagedEntity = ( Element )aObject;
            Element managedEntity = updateEntityLocator.find( session, unmanagedEntity );

            if ( managedEntity != null )
            {
                mergeElements( unmanagedEntity, managedEntity );
            }
            else
            {
                throw new IllegalAccessException( String.format( "Update operation attempted on non-managed entity. Entity ID: %s.", unmanagedEntity.asXML() ) );
            }
        }
        else
        {
            session.merge( aObject );
        }
    }


    @SuppressWarnings( "unchecked" )
    private void mergeElements( Element from, Element to )
    {
        for ( Element fromChild : ( List<Element> )from.elements() )
        {
            Element toChild = to.element( fromChild.getName() );
            if ( toChild != null )
            {
                if ( toChild.elements().size() > 0 )
                {
                    mergeElements( fromChild, toChild );
                }
                else
                {
                    toChild.detach();
                    to.add( ( Element )fromChild.clone() );
                }
            }
            else
            {
                to.add( ( Element )fromChild.clone() );
            }
        }
    }
    
    public void setUpdateEntityLocator(
			HibernateEntityLocatorInterface<Element> updateEntityLocator) {
		this.updateEntityLocator = updateEntityLocator;
	}
}