001    package com.thaiopensource.validate.nrl;
002    
003    import com.thaiopensource.util.Equal;
004    
005    import java.util.Vector;
006    import java.util.Hashtable;
007    import java.util.Enumeration;
008    import java.util.NoSuchElementException;
009    
010    class ContextMap {
011      private Object rootValue;
012      private Object otherValue;
013      private final Hashtable nameTable = new Hashtable();
014    
015      Object get(Vector context) {
016        return get(context, context.size());
017      }
018    
019      boolean put(boolean isRoot, Vector names, Object value) {
020        return put(isRoot, names, names.size(), value);
021      }
022    
023      private Object get(Vector context, int len) {
024        if (len > 0) {
025          ContextMap nestedMap = (ContextMap)nameTable.get(context.elementAt(len - 1));
026          if (nestedMap != null) {
027            Object value = nestedMap.get(context, len - 1);
028            if (value != null)
029              return value;
030          }
031        }
032        if (rootValue != null && len == 0)
033          return rootValue;
034        return otherValue;
035      }
036    
037      private boolean put(boolean isRoot, Vector names, int len, Object value) {
038        if (len == 0) {
039          if (isRoot) {
040            if (rootValue != null)
041              return false;
042            rootValue = value;
043          }
044          else {
045            if (otherValue != null)
046              return false;
047            otherValue = value;
048          }
049          return true;
050        }
051        else {
052          Object name = names.elementAt(len - 1);
053          ContextMap nestedMap = (ContextMap)nameTable.get(name);
054          if (nestedMap == null) {
055            nestedMap = new ContextMap();
056            nameTable.put(name, nestedMap);
057          }
058          return nestedMap.put(isRoot, names, len - 1, value);
059        }
060      }
061    
062      public boolean equals(Object obj) {
063        if (!(obj instanceof ContextMap))
064          return false;
065        ContextMap other = (ContextMap)obj;
066        if (!Equal.equal(this.rootValue, other.rootValue)
067            || !Equal.equal(this.otherValue, other.otherValue))
068          return false;
069        // We want jing to work with JDK 1.1 so we cannot use Hashtable.equals
070        if (this.nameTable.size() != other.nameTable.size())
071          return false;
072        for (Enumeration e = nameTable.keys(); e.hasMoreElements();) {
073          Object key = e.nextElement();
074          if (!nameTable.get(key).equals(other.nameTable.get(key)))
075            return false;
076        }
077        return true;
078      }
079    
080      public int hashCode() {
081        int hc = 0;
082        if (rootValue != null)
083          hc ^= rootValue.hashCode();
084        if (otherValue != null)
085          hc ^= otherValue.hashCode();
086        for (Enumeration e = nameTable.keys(); e.hasMoreElements();) {
087          Object key = e.nextElement();
088          hc ^= key.hashCode();
089          hc ^= nameTable.get(key).hashCode();
090        }
091        return hc;
092      }
093    
094      static private class Enumerator implements Enumeration {
095        private Object rootValue;
096        private Object otherValue;
097        private Enumeration subMapValues;
098        private final Enumeration subMaps;
099    
100        private Enumerator(ContextMap map) {
101          rootValue = map.rootValue;
102          otherValue = map.otherValue;
103          subMaps = map.nameTable.elements();
104        }
105    
106        private void prep() {
107          while ((subMapValues == null || !subMapValues.hasMoreElements()) && subMaps.hasMoreElements())
108            subMapValues = ((ContextMap)subMaps.nextElement()).values();
109        }
110    
111        public boolean hasMoreElements() {
112          prep();
113          return rootValue != null || otherValue != null || (subMapValues != null && subMapValues.hasMoreElements());
114        }
115    
116        public Object nextElement() {
117          if (rootValue != null) {
118            Object tem = rootValue;
119            rootValue = null;
120            return tem;
121          }
122          if (otherValue != null) {
123            Object tem = otherValue;
124            otherValue = null;
125            return tem;
126          }
127          prep();
128          if (subMapValues == null)
129            throw new NoSuchElementException();
130          return subMapValues.nextElement();
131        }
132      }
133    
134      Enumeration values() {
135        return new Enumerator(this);
136      }
137    }