/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.jackrabbit.core.xml;

import org.apache.jackrabbit.spi.commons.namespace.NamespaceResolver;

import javax.jcr.NamespaceException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Hierarchically scoped namespace resolver. Each NamespaceContext instance
 * contains an immutable set of namespace mappings and a reference (possibly
 * <code>null</code>) to a parent NamespaceContext. Namespace resolution is
 * performed by first looking at the local namespace mappings and then using
 * the parent resolver if no local match is found.
 * <p>
 * The local namespace mappings are stored internally as two hash maps, one
 * that maps the namespace prefixes to namespace URIs and another that contains
 * the reverse mapping.
 */
class NamespaceContext implements NamespaceResolver {

    /**
     * The parent namespace context.
     */
    private final NamespaceContext parent;

    /**
     * The namespace prefix to namespace URI mapping.
     */
    private final Map prefixToURI;

    /**
     * The namespace URI to namespace prefix mapping.
     */
    private final Map uriToPrefix;

    /**
     * Creates a NamespaceContext instance with the given parent context
     * and local namespace mappings.
     *
     * @param parent parent context
     * @param mappings local namespace mappings (prefix -> URI)
     */
    public NamespaceContext(NamespaceContext parent, Map mappings) {
        this.parent = parent;
        this.prefixToURI = new HashMap();
        this.uriToPrefix = new HashMap();

        Iterator iterator = mappings.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry mapping = (Map.Entry) iterator.next();
            prefixToURI.put(mapping.getKey(), mapping.getValue());
            uriToPrefix.put(mapping.getValue(), mapping.getKey());
        }
    }

    /**
     * Returns the parent namespace context.
     *
     * @return parent namespace context
     */
    public NamespaceContext getParent() {
        return parent;

    }
    //------------------------------------------------< NamespaceResolver >

    /**
     * Returns the namespace URI mapped to the given prefix.
     *
     * @param prefix namespace prefix
     * @return namespace URI
     * @throws NamespaceException if the prefix is not mapped
     */
    public String getURI(String prefix) throws NamespaceException {
        String uri = (String) prefixToURI.get(prefix);
        if (uri != null) {
            return uri;
        } else if (parent != null) {
            return parent.getURI(prefix);
        } else {
            throw new NamespaceException("Unknown prefix: " + prefix);
        }
    }

    /**
     * Returns the namespace prefix mapped to the given URI.
     *
     * @param uri namespace URI
     * @return namespace prefix
     * @throws NamespaceException if the URI is not mapped
     */
    public String getPrefix(String uri) throws NamespaceException {
        String prefix = (String) uriToPrefix.get(uri);
        if (prefix != null) {
            return prefix;
        } else if (parent != null) {
            return parent.getPrefix(uri);
        } else {
            throw new NamespaceException("Unknown URI: " + uri);
        }
    }
}

@@ -3193,32 +3193,111 @@
 paceException %7B%0A
+        NamespaceContext current = this;%0A        while (current != null) %7B%0A    
         String u
@@ -3310,16 +3310,24 @@
 String) 
+current.
 prefixTo
@@ -3347,24 +3347,28 @@
 x);%0A        
+    
 if (uri != n
@@ -3366,32 +3366,36 @@
 (uri != null) %7B%0A
+    
             retu
@@ -3414,100 +3414,62 @@
     
-%7D else if (parent != null) %7B%0A            return parent.getURI(prefix);%0A        %7D else %7B%0A    
+    %7D%0A            current = current.parent;%0A        %7D%0A
     
@@ -3531,26 +3531,16 @@
 refix);%0A
-        %7D%0A
     %7D%0A%0A 
@@ -3805,32 +3805,111 @@
 paceException %7B%0A
+        NamespaceContext current = this;%0A        while (current != null) %7B%0A    
         String p
@@ -3925,16 +3925,24 @@
 String) 
+current.
 uriToPre
@@ -3951,24 +3951,28 @@
 x.get(uri);%0A
+    
         if (
@@ -3993,32 +3993,36 @@
 ) %7B%0A            
+    
 return prefix;%0A 
@@ -4032,100 +4032,62 @@
     
-%7D else if (parent != null) %7B%0A            return parent.getPrefix(uri);%0A        %7D else %7B%0A    
+    %7D%0A            current = current.parent;%0A        %7D%0A
     
@@ -4143,26 +4143,16 @@
 + uri);%0A
-        %7D%0A
     %7D%0A%7D%0A

make NamespaceContext#getPrefix(java.lang.String) iterative instead of recursive