/*
 * Copyright (C) 2004 Red Hat Inc. All Rights Reserved.
 *
 * The contents of this file are subject to the CCM Public
 * License (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the
 * License at http://www.redhat.com/licenses/ccmpl.html.
 *
 * Software distributed under the License is distributed on an
 * "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
 * or implied. See the License for the specific language
 * governing rights and limitations under the License.
 *
 */
package com.arsdigita.cms.contenttypes;

import org.apache.log4j.Logger;
import com.arsdigita.persistence.metadata.Property;
import java.util.Map;
import java.util.HashMap;
import com.arsdigita.domain.DomainObjectTraversalAdapter;
import com.arsdigita.domain.SimpleDomainObjectTraversalAdapter;
import com.arsdigita.domain.DomainObject;


/**
 * An adapter for content items allowing pluggable
 * assets to extend the traversal.
 */
public class ContentItemTraversalAdapter 
    extends SimpleDomainObjectTraversalAdapter {
    
    private static final Logger s_log = 
        Logger.getLogger(ContentItemTraversalAdapter.class);
    
    private static final Map s_assetAdapters = new HashMap();
    
    public static void registerAssetAdapter(String path,
                                            DomainObjectTraversalAdapter adapter,
                                            String context) {
        if (s_log.isDebugEnabled()) {
            s_log.debug("Registering asset adapter " + path + 
                        " adapter " + adapter.getClass() + 
                        " in context " + context);
        }
        
        Map adapters = (Map)s_assetAdapters.get(context);
        if (adapters == null) {
            adapters = new HashMap();
            s_assetAdapters.put(context, adapters);
        }
        adapters.put(path, adapter);
    }

    public ContentItemTraversalAdapter() {
        super();
    }
        
    public ContentItemTraversalAdapter(SimpleDomainObjectTraversalAdapter adapter) {
        super(adapter);
    }

    /**
     * If the path references an asset, then delegates
     * to the asset's adapter, otherwise delegates to
     * the content item's primary adapter
     */
    public boolean processProperty(DomainObject obj,
                                   String path,
                                   Property prop,
                                   String context) {
        if (s_log.isDebugEnabled()) {
            s_log.debug("Process property " + path);
        }
        String prefix = "/object/";
        int offset = path.indexOf("/", prefix.length());
        if (offset == -1) {
            String base = path.substring(prefix.length());
            Map adapters = (Map)s_assetAdapters.get(context);
            if (adapters != null &&
                adapters.containsKey(base)) {
                if (s_log.isDebugEnabled()) {
                    s_log.debug("Following asset");
                }
                return true;
            } else {
                if (s_log.isDebugEnabled()) {
                    s_log.debug("Root delegate to primary adapter " + base);
                }
                return super.processProperty(obj, path, prop, context);
            }
        } else {
            String base = path.substring(prefix.length(), offset);
            String rest = path.substring(offset + 1);

            Map adapters = (Map)s_assetAdapters.get(context);
            if (adapters != null &&
                adapters.containsKey(base)) {
                DomainObjectTraversalAdapter adapter = (DomainObjectTraversalAdapter)
                    adapters.get(base);
                if (s_log.isDebugEnabled()) {
                    s_log.debug("Delegate to asset adapter " + base + 
                                " " + rest + " " + adapter);
                }
                return adapter.processProperty(obj, "/object/" + rest, prop, context);
            } else {
                if (s_log.isDebugEnabled()) {
                    s_log.debug("Delegate to primary adapter " + base + 
                                " " + rest);
                }
                return super.processProperty(obj, path, prop, context);
            }
        }
    }
}
