001 package com.oxygenxml.validate.nvdl;
002
003 import com.thaiopensource.util.Equal;
004
005 import java.util.Vector;
006 import java.util.Enumeration;
007
008 /**
009 * Stores mode usage information.
010 */
011 class ModeUsage {
012 /**
013 * The use mode.
014 */
015 private Mode mode;
016 /**
017 * The current mode used until now.
018 */
019 final Mode currentMode;
020
021 /**
022 * Modes depending on context.
023 */
024 private ContextMap modeMap;
025
026 /**
027 *
028 */
029 private int attributeProcessing = -1;
030
031 /**
032 * Creates a use mode.
033 * @param mode The mode to be used.
034 * @param currentMode The mode used until the new mode.
035 */
036 ModeUsage(Mode mode, Mode currentMode) {
037 this(mode, currentMode, null);
038 }
039
040 /**
041 * Creates a use mode.
042 * @param mode The mode to be used.
043 * @param currentMode The mode used until now.
044 * @param modeMap Modes to be used depending on context.
045 */
046 private ModeUsage(Mode mode, Mode currentMode, ContextMap modeMap) {
047 this.mode = mode;
048 this.currentMode = currentMode;
049 this.modeMap = modeMap;
050 }
051
052 /**
053 * Gets a new mode usage with a different current mode
054 * but with the same mode and modeMap as this one.
055 * @param currentMode The new current mode.
056 * @return A new mode usage with the changed current mode.
057 */
058 ModeUsage changeCurrentMode(Mode currentMode) {
059 return new ModeUsage(mode, currentMode, modeMap);
060 }
061
062 /**
063 * Check to see if this mode usage is equals with another mode usage.
064 */
065 public boolean equals(Object obj) {
066 if (!(obj instanceof ModeUsage))
067 return false;
068 ModeUsage other = (ModeUsage)obj;
069 return this.mode == other.mode && this.currentMode == other.currentMode && Equal.equal(this.modeMap, other.modeMap);
070 }
071
072 /**
073 * Gets a hash code for this mode usage.
074 */
075 public int hashCode() {
076 int hc = mode.hashCode() ^ currentMode.hashCode();
077 if (modeMap != null)
078 hc ^= modeMap.hashCode();
079 return hc;
080 }
081
082 /**
083 * Resolves the Mode.CURRENT to the currentMode for this mode usage.
084 * If not Mode.CURRENT passed as argument then the same mode is returned.
085 * @param mode The mode to be resolved.
086 * @return Either the current mode mode usage or the same mode passed as argument.
087 */
088 private Mode resolve(Mode mode) {
089 if (mode == Mode.CURRENT) {
090 return currentMode;
091 }
092 if (mode.isAnonymous() && !mode.isDefined()) {
093 return currentMode;
094 }
095 return mode;
096 }
097
098 /**
099 * Get the maximum attribute processing value from the default mode and
100 * from all the modes specified in the contexts.
101 * @return The attribute processing value.
102 */
103 int getAttributeProcessing() {
104 if (attributeProcessing == -1) {
105 attributeProcessing = resolve(mode).getAttributeProcessing();
106 if (modeMap != null) {
107 for (Enumeration en = modeMap.values();
108 en.hasMoreElements()
109 && attributeProcessing != Mode.ATTRIBUTE_PROCESSING_FULL;)
110 attributeProcessing = Math.max(resolve((Mode)en.nextElement()).getAttributeProcessing(),
111 attributeProcessing);
112 }
113 }
114 return attributeProcessing;
115 }
116
117 /**
118 * Check if we have context dependent modes.
119 * @return true if the modeMap exists.
120 */
121 boolean isContextDependent() {
122 return modeMap != null;
123 }
124
125 /**
126 * Get the mode to be used for a specific context.
127 * @param context The current context.
128 * @return A mode.
129 */
130 Mode getMode(Vector context) {
131 // first look in the modeMap if exists.
132 if (modeMap != null) {
133 Mode m = (Mode)modeMap.get(context);
134 if (m != null)
135 return resolve(m);
136 }
137 // if no modeMap or no context specific mode found then
138 // return the default mode for this mode usage.
139 return resolve(mode);
140 }
141
142 /**
143 * Adds a new context (isRoot, path --> mode).
144 * @param isRoot Flag indicating that the path starts or not with /
145 * @param names The local names that form the path.
146 * @param mode The mode for this path.
147 * @return true if we do not have a duplicate path.
148 */
149 boolean addContext(boolean isRoot, Vector names, Mode mode) {
150 if (modeMap == null)
151 modeMap = new ContextMap();
152 return modeMap.put(isRoot, names, mode);
153 }
154 }