/*
 * $Header: /home/cvspublic/jakarta-slide/proposals/tamino/src/store/org/apache/slide/store/tamino/common/XResolver.java,v 1.1 2004/03/25 16:17:59 juergen Exp $
 * $Revision: 1.1 $
 * $Date: 2004/03/25 16:17:59 $
 *
 * ====================================================================
 *
 * Copyright 1999-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.slide.store.tamino.common;

import org.apache.slide.store.tamino.jdomobjects.XUuri;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.util.XAssertionFailed;
import org.apache.slide.util.XException;
import org.apache.slide.util.XUri;

/**
 ** Lookup in Folder tree. Used by the XChildStore to resolve uris. Acts as a fassade for the
 ** XDescriptorsHandler's lookup and create methods. XDescriptorsHandler does not know about
 ** the Resolver.
 **
 ** Synchronization: this class is not thread save. Thats fine because the child store  creates
 ** an new Resolver instance for every "resolve".
 **/
public class XResolver {
    /**
     * Method create
     *
     * @param    handler             an IDescriptorsHandler
     * @param    uriStr              a  String
     *
     * @return   a XResolver
     *
     */
    public static XResolver create(IDescriptorsHandler handler, String uriStr) {
        XUri storeUri;
        XUri uri;

        uri = new XUri(uriStr);
        storeUri = XUuri.extractStoreUri(uri);
        return new XResolver(handler, uri, storeUri.size(), XUuri.getStoreUuri(true, storeUri));
    }

    //--

    private final IDescriptorsHandler handler;
    private final XUri uri;
    private final String uriStr;
    private final int startSegment;
    private final String storeUuri;

    private XResolver(IDescriptorsHandler handler, XUri uri, int startSegment, String storeUuri) {
        this.handler = handler;
        this.uri = uri;
        this.uriStr = uri.toString();
        this.startSegment = startSegment;
        this.storeUuri = storeUuri;
    }

    //--

    public IDescriptors run( int lockType, int parentLockType, boolean create )
        throws XException
    {
        IDescriptors result;

        synchronized (handler) {
            result = resolveBoth( lockType, parentLockType);
            if (create && result == null) {
                result = handler.create(uriStr);
            }
        }
        return result;
    }

    //-- implementation

    /**
     ** Performs both cached and uncached resolve
     **/
    private IDescriptors resolveBoth( int lockType, int parentLockType )
        throws XException
    {
        IDescriptors resolved;
        IDescriptors cached;

        resolved = resolveUncached(lockType, parentLockType);
        cached = handler.lookupUriCache(lockType, uriStr);
        if (resolved != null && cached != null) {
            if (cached != resolved) {
                throw new XAssertionFailed();
            }
        }
        if (resolved == null) {
            resolved = cached;
        }
        return resolved;
    }

    private IDescriptors resolveUncached(int lockType, int parentLockType)
        throws XException
    {
        if (handler.useBinding()) {
            return resolveUncachedWithoutUnlock(lockType, parentLockType);
        } else {
            return handler.lookup( uriStr, uriStr, lockType);
        }
    }

    /**
     ** Worker method to do the actual work.
     **/
    private IDescriptors resolveUncachedWithoutUnlock(int lockType, int parentLockType)
        throws XException
    {
        int i;
        int max;
        IDescriptors desc;
        String segment;
        String uuri;
        ObjectNode objectNode;

        max = uri.size();
        uuri = storeUuri;
        for (i = startSegment; true; i++) {
            desc = handler.lookup(uri.suburi(0, i).toString(),
                                  uuri, (i == max)? lockType : parentLockType);
            if (desc == null || i == max) {
                return desc;
            }
            segment = uri.segment(i);
            objectNode = desc.getUuriObjectNode();
            if (objectNode == null) {
                return null;
            }
            uuri = objectNode.getBindingUuri(segment);
            if (uuri == null) {
                return null;
            }
        }
    }
}


