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 }