/*******************************************************************************
 * Copyright (c) 2011, 2013 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 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:
 *      bdoughan - initial implementation 
 *      tware - initial unmarshall method
 ******************************************************************************/
package org.eclipse.persistence.jpa.rs.util.xmladapters;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.bind.annotation.adapters.XmlAdapter;

import org.eclipse.persistence.config.CacheUsage;
import org.eclipse.persistence.config.QueryHints;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.internal.dynamic.DynamicEntityImpl;
import org.eclipse.persistence.jpa.rs.PersistenceContext;
import org.eclipse.persistence.jpa.rs.util.IdHelper;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.queries.FetchGroup;

/**
 * Used with JAXB to convert from a URL representing an relationship to an object
 * It provides functionality at marshall and unmarshall time
 * 
 * At marshall time, the target of a relationship will be marshalled as a URL that could be
 * used to find the object through a REST service
 * 
 * At unmarsall time, the URL will be deconstructed and used to find the object in JPA.
 * 
 * @author tware
 *
 */
public class LinkAdapter extends XmlAdapter<String, Object> {

    private String baseURI = null;
    protected PersistenceContext context;

    public LinkAdapter() {
    }

    public LinkAdapter(String baseURI, PersistenceContext context) {
        this.baseURI = baseURI;
        this.context = context;
    }
    
    @Override
    public Object unmarshal(String v) throws Exception {
        if (v.equals("")){
            return null;
        }
        String fixedString = v.replace("\\/", "/");
        int lastSlash = fixedString.lastIndexOf('/');
        String entityType = fixedString.substring((baseURI + context.getName() + "/entity/" ).length(), lastSlash);
        String entityId = fixedString.substring(lastSlash + 1);
        ClassDescriptor descriptor = context.getDescriptor(entityType);
        Object id = IdHelper.buildId(context, descriptor.getAlias(), entityId);
        
        return constructObjectForId(entityType, id);
    }

    protected Object constructObjectForId(String entityType, Object id){

        FetchGroup fetchGroup = new FetchGroup();
        ClassDescriptor descriptor = context.getDescriptor(entityType);
        List<DatabaseMapping> pkMappings = descriptor.getObjectBuilder().getPrimaryKeyMappings();
        for (DatabaseMapping mapping: pkMappings){
            fetchGroup.addAttribute(mapping.getAttributeName());
        }
        Map<String, Object> properties = new HashMap<String, Object>();
        properties.put(QueryHints.FETCH_GROUP, fetchGroup);
        properties.put(QueryHints.CACHE_USAGE, CacheUsage.CheckCacheOnly);
        Object entity = context.find(null, entityType, id, properties);
        
        if (entity == null){
            return IdHelper.buildObjectShell(context, entityType, id);
        }
        return entity;
    }
    
    @Override
    public String marshal(Object v) throws Exception {
        if (null == v) {
            return null;
        }

        String href = null;
        String version = context.getVersion();

        if (version != null) {
            href = baseURI + version + "/" + context.getName() + "/entity/" + v.getClass().getSimpleName() + "/"
                    + IdHelper.stringifyId((DynamicEntityImpl) v, ((DynamicEntityImpl) v).getType().getName(), context);
        } else {
            href = baseURI + context.getName() + "/entity/" + v.getClass().getSimpleName() + "/"
                    + IdHelper.stringifyId((DynamicEntityImpl) v, ((DynamicEntityImpl) v).getType().getName(), context);
        }
        return href;
    }
}
