/*
 * Copyright (C) 2003-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.dispatcher;

import com.arsdigita.cms.ContentBundle;
import com.arsdigita.cms.ContentItem;
import com.arsdigita.cms.ContentSection;

import com.arsdigita.kernel.ACSObject;
import com.arsdigita.kernel.URLFinder;
import com.arsdigita.kernel.URLFinderNotFoundException;
import com.arsdigita.kernel.URLService;
import com.arsdigita.kernel.NoValidURLException;

import com.arsdigita.domain.DomainObjectFactory;
import com.arsdigita.domain.DomainServiceInterfaceExposer;
import com.arsdigita.domain.DataObjectNotFoundException;

import com.arsdigita.categorization.Category;

import com.arsdigita.persistence.DataAssociation;
import com.arsdigita.persistence.DataAssociationCursor;
import com.arsdigita.persistence.OID;

import com.arsdigita.web.URL;
import com.arsdigita.web.ParameterMap;

import org.apache.log4j.Logger;

public class ItemURLFinder implements URLFinder {
    
    private static final Logger s_log = Logger.getLogger(ItemURLFinder.class);

    public String find(OID oid,String context) throws NoValidURLException {
        if (s_log.isDebugEnabled()) {
            s_log.debug("Locating " + oid + " in " + context);
        }

        ContentItem item;
        try {
            item = (ContentItem)DomainObjectFactory
                .newInstance(oid);
        } catch (DataObjectNotFoundException ex) {
            throw new NoValidURLException(
                "cannot instantiate item " + oid + 
                " message: " + ex.getMessage()
            );
        }
              
        if (ContentItem.LIVE.equals(context)) {
            if (item.isLive()) {
                if (!item.isLiveVersion()) {
                    item = item.getLiveVersion();
                    if (s_log.isDebugEnabled()) {
                        s_log.debug("Switched to live version " + item);
                    }
                }
            } else {
                s_log.debug("Item was not live");
                throw new NoValidURLException(
                    "item " + oid + " is not live"
                );
            }
        }
        
        return find(item, context);
    }
    
    public String find(OID oid) 
        throws NoValidURLException {
        if (s_log.isDebugEnabled()) {
            s_log.debug("Locating " + oid);
        }
        
        ContentItem item;
        try {
            item = (ContentItem)DomainObjectFactory
                .newInstance(oid);
        } catch (DataObjectNotFoundException ex) {
            throw new NoValidURLException(
                "cannot instantiate item " + oid + 
                " message: " + ex.getMessage()
            );
        }
        
        if (s_log.isDebugEnabled()) {
            s_log.debug("Item version is " + item.getVersion());
        }

        // Revert to the behavior before change# 41315.  Clients relied on the behavior that
        // links with no context defaulted to the live version (if one existed).  Changing
        // that behavior broke a lot of links in static content that couldn't easily be updated.
        // This change restores the old behavior.  We don't get a regression of bz 116226
        // (which bz 41315 was intended to fix) because the CMS search.xsl has been updated to 
        // append "&context=draft" to the search results.  The CMS DHTML editor has also been 
        // updated to append generated links with "&context=live".  If at some point in the future
        // all unqualified links have been removed, then this fix could be removed as well.
        if (item.isLive() && !item.isLiveVersion()) {
            item = item.getLiveVersion();
            if (s_log.isDebugEnabled()) {
                s_log.debug("Switched to live version " + item);
            }
        }

        return find(item, item.getVersion());
    }

    private String find(ContentItem item,
                        String context) {
        ContentSection section = item.getContentSection();
        ItemResolver resolver = section.getItemResolver();

        // If the ContentItem is an index object for a Category, redirect
        // to the URL for that Category instead of the item.
        ACSObject parent = item.getParent();
        ContentBundle bundle = null;
        if (parent instanceof ContentBundle) {
            bundle = (ContentBundle) ((ContentBundle) parent).getDraftVersion();
        }
        if (bundle != null) {
            DataAssociationCursor categories = 
                ((DataAssociation) DomainServiceInterfaceExposer.
                 get(bundle, Category.CATEGORIES)).cursor();
            categories.addEqualsFilter("link." + Category.IS_INDEX, Boolean.TRUE);
            
            if (categories.next()) {
                Category indexCat = (Category) DomainObjectFactory.
                    newInstance(categories.getDataObject());
                categories.close();
                try {
                    if (s_log.isDebugEnabled()) {
                        s_log.debug(item + " is a Category index item.  Resolving URL for " +
                                    indexCat);
                    }
                    return URLService.locate(indexCat.getOID(), context);
                } catch (URLFinderNotFoundException ufnfe) {
                    if (s_log.isDebugEnabled()) {
                        s_log.debug("Could not find URLFinder for " + indexCat +
                                    ", continuing with URL resolution for " + item,
                                    ufnfe);
                    }
                } catch (NoValidURLException nvue) {
                    if (s_log.isDebugEnabled()) {
                        s_log.debug("Could not find valid URL for " + indexCat +
                                    ", continuing with URL resolution for " + item,
                                    nvue);
                    }
                }                                
            }
        }
        

        String url = resolver.generateItemURL(null, item, section, context);
        
        if (s_log.isDebugEnabled()) {
            s_log.debug("Resolved " + item + " in " + context + " to " + url);
        }
        
        final int sep = url.indexOf('?');
        URL destination = null;
        
        if (sep == -1) {
            destination = URL.there(url, null);
        } else {
            final ParameterMap params = ParameterMap.fromString
                (url.substring(sep + 1));
            
            destination = URL.there(url.substring(0, sep), params);
        }
        
        if (s_log.isDebugEnabled()) {
            s_log.debug("After munging, destination is " + destination);
        }            
        
        return destination.toString();
    }
}
