/*
 * $Header: /home/cvspublic/jakarta-slide/src/share/org/apache/slide/common/ScopeTokenizer.java,v 1.8 2004/11/08 09:31:15 luetzkendorf Exp $
 * $Revision: 1.8 $
 * $Date: 2004/11/08 09:31:15 $
 *
 * ====================================================================
 *
 * Copyright 1999-2002 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.common;

import java.util.StringTokenizer;
import java.util.Vector;
import java.util.Enumeration;
import java.util.NoSuchElementException;

/**
 * Tokenizes a scope.
 * <p/>
 * This tokenizer derives from StringTokenizer and tokenizes a scope in sub scopes.
 * This object is used for Scope matching in the registry. The API of this object
 * is the same as the StringTokenizer API.
 * <p/>
 * Ex : the scope /foo/bar/bar.txt will be tokenized in the following tokens :
 * <li>/foo/bar/bar.txt
 * <li>/foo/bar
 * <li>/foo
 * <li>/
 *
 * @see StringTokenizer
 * @version $Revision: 1.8 $
 */
public final class ScopeTokenizer extends StringTokenizer {
    
    
    // ----------------------------------------------------------- Constructors
    
    
    /**
     * Constructor.
     *
     * @param uri Uri which needs to be tokenized in Scopes.
     */
    public ScopeTokenizer(SlideToken slideToken, Namespace namespace, String uri) {
        super(uri, "/");
        
        // We then build the scopes.
        scopes = new Vector();
        
        // Initializing namespace
        this.slideToken = slideToken;
        this.namespace = namespace;
        
        scopes.insertElementAt("/", 0);
        
        // We parse the token list and build the scope String objects.
        StringBuffer b = new StringBuffer(uri.length());
        while(super.hasMoreTokens()) {
            b.append("/").append(super.nextToken());
            scopes.insertElementAt(b.toString(), 0);
        }
        
        pos = 0;
    }
    
    
    /**
     * Constructor.
     *
     * @param namespace
     * @param uri
     */
    public ScopeTokenizer(Namespace namespace, String uri) {
        this(null, namespace, uri);
    }
    
    
    /**
     * Constructor.
     *
     * @param namespace
     * @param scope
     */
    public ScopeTokenizer(Namespace namespace, Scope scope) {
        this(null, namespace, scope.toString());
    }
    
    
    // ----------------------------------------------------- Instance Variables
    
    
    /**
     * Tokens container.
     */
    private Vector scopes;
    
    
    /**
     * Cursor position in the token container.
     */
    private int pos;
    
    
    /**
     * Namespace.
     */
    private Namespace namespace;
    private SlideToken slideToken;
    
    
    // --------------------------------------------------------- Public Methods
    
    
    /**
     * Get the parent Uri of the top level scope.
     *
     * @return Uri Parent Uri
     */
    public Uri getParentUri() {
        if (scopes.size() <= 1) {
            return null;
        } else {
            return namespace.getUri(slideToken, (String) scopes.elementAt(1));
        }
    }
    
    
    /**
     * True if the ScopeTokenizer contains additional scopes.
     *
     * @return boolean
     */
    public boolean hasMoreElements() {
        return scopes.size() > pos;
    }
    
    
    /**
     * True if the ScopeTokenizer contains additional scopes.
     *
     * @return boolean
     */
    public boolean hasMoreTokens() {
        return hasMoreElements();
    }
    
    
    /**
     * Returns the next Scope as an Object.
     *
     * @return Object
     * @exception NoSuchElementException
     */
    public Object nextElement() throws NoSuchElementException {
        Object obj = null;
        try {
            if (!hasMoreElements()) {
            throw new NoSuchElementException();
            }
            obj = scopes.elementAt(pos);
            pos = pos + 1;
        } catch (ArrayIndexOutOfBoundsException e) {
            // Should NEVER happen.
            e.printStackTrace();
        }
        return obj;
    }
    
    
    /**
     * Returns the next Scope as a String object.
     *
     * @return String
     * @exception NoSuchElementException
     */
    public String nextToken() throws NoSuchElementException {
        return (String) nextElement();
    }
    
    
    /**
     * Returns the next Scope as a Scope object.
     *
     * @return Scope
     * @exception NoSuchElementException
     */
    public Scope nextScope() throws NoSuchElementException {
        return new Scope(nextToken());
    }
    
    
    /**
     * Returns the next Scope as a String object.
     *
     * @param delim
     * @exception NoSuchElementException
     */
    public String nextToken(String delim) throws NoSuchElementException {
        return nextToken();
    }
    
    
    /**
     * Returns the scopes.
     *
     * @return Enumeration
     */
    public Enumeration elements() {
        return scopes.elements();
    }
    
    
    // -------------------------------------------------------- Package Methods
    
    
    /**
     * Get the parsed uri.
     *
     * @return String Uri
     */
    String getUri() {
        if (scopes.size() < 1) {
            return null;
        } else {
            return (String) scopes.elementAt(0);
        }
    }
    
}
