1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package net.sf.magicproject.token;
20
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.io.OutputStream;
24 import java.util.Arrays;
25 import java.util.HashMap;
26 import java.util.Map;
27
28 import net.sf.magicproject.clickable.ability.Ability;
29 import net.sf.magicproject.clickable.targetable.Targetable;
30 import net.sf.magicproject.event.context.ContextEventListener;
31 import net.sf.magicproject.stack.StackManager;
32 import net.sf.magicproject.test.TestOn;
33 import net.sf.magicproject.tools.MToolKit;
34 import net.sf.magicproject.xml.XmlTools;
35
36 import org.apache.commons.lang.ArrayUtils;
37
38 /***
39 * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
40 * @since 0.93
41 */
42 public class Register {
43
44 /***
45 * Create a new instance of this class.
46 *
47 * @param on
48 */
49 public Register(TestOn on) {
50 this.on = on;
51 this.ordinal = on.ordinal();
52 }
53
54 /***
55 * Create a new instance of this class.
56 *
57 * @param ordinal
58 */
59 public Register(int ordinal) {
60 this.on = null;
61 this.ordinal = ordinal;
62 }
63
64 /***
65 * Returns the integer value of this expression
66 *
67 * @param ability
68 * is the ability owning this test. The card component of this
69 * ability should correspond to the card owning this test too.
70 * @param tested
71 * the tested card
72 * @param context
73 * is the context attached to this test.
74 * @param index
75 * the index value access.
76 * @return the integer value of this expression
77 */
78 public int getValue(Ability ability, Targetable tested,
79 ContextEventListener context, int index) {
80 if (on != null)
81 return on.getTargetable(ability, tested).getValue(index);
82 switch (ordinal) {
83 case IdTokens.STACK:
84 return StackManager.registers[index];
85 case IdTokens.STATIC_REGISTER:
86 return MCommonVars.registers[index];
87 case IdTokens.REQUIRED_MANA:
88 if (index == IdTokens.MANA_POOL) {
89 return MToolKit.manaPool(StackManager.actionManager.requiredMana);
90 }
91 return StackManager.actionManager.requiredMana[index];
92 default:
93 throw new InternalError("unknown idToken : " + index);
94 }
95 }
96
97 /***
98 * Is this register is plugged on a targetable component.
99 *
100 * @return true if this register is plugged on a targetable component.
101 */
102 public boolean isTargetable() {
103 return on != null;
104 }
105
106 /***
107 * Is this register is plugged on a set of targetable component.
108 *
109 * @return true if this register is plugged on a set of targetable component.
110 */
111 public boolean isGlobal() {
112 return on == null;
113 }
114
115 /***
116 * Write this enum to the given outputstream.
117 *
118 * @param out
119 * the stream ths enum would be written.
120 */
121 public void serialize(OutputStream out) {
122 if (!canBePreempted())
123 XmlTools.testCanBePreempted = false;
124 MToolKit.writeInt16(out, ordinal);
125 }
126
127 /***
128 * Read and return the enum from the given inputstream.
129 *
130 * @param input
131 * the stream containing the enum to read.
132 * @return the enum from the given inputstream.
133 * @throws IOException
134 * If some other I/O error occurs
135 */
136 public static Register deserialize(InputStream input) throws IOException {
137 return deserialize(MToolKit.readInt16(input));
138 }
139
140 /***
141 * Read and return the enum from the given inputstream.
142 *
143 * @param ordinal
144 * the key.
145 * @return the enum from the given key.
146 */
147 public static Register deserialize(int ordinal) {
148 if (values == null)
149 values = new HashMap<Integer, Register>();
150 Register register = values.get(ordinal);
151 if (register == null) {
152 if (ordinal < TestOn.values().length) {
153 register = new Register(TestOn.values()[ordinal]);
154 } else {
155 register = new Register(ordinal);
156 }
157 values.put(ordinal, register);
158 }
159 return register;
160 }
161
162 /***
163 * Return null of enum value corresponding to the given Xsd name.
164 *
165 * @param xsdName
166 * the Xsd name of this Register.
167 * @return null of enum value corresponding to the given Xsd name.
168 */
169 public static Register valueOfXsd(String xsdName) {
170 TestOn on = TestOn.valueOfXsd(xsdName);
171 if (on != null) {
172 return new Register(on);
173 }
174 final int index = Arrays.binarySearch(REGISTER_NAMES, xsdName);
175 if (index >= 0)
176 return Register.deserialize(REGISTER_VALUES[index]);
177 return null;
178 }
179
180 /***
181 * Return the ID of this register.
182 *
183 * @return the ID of this register.
184 */
185 public int ordinal() {
186 return ordinal;
187 }
188
189 /***
190 * Return the component associated to this register. May be null.
191 *
192 * @return the component associated to this register. May be null.
193 */
194 public TestOn getTargetable() {
195 return on;
196 }
197
198 /***
199 * Return true if the associated value can be evaluated without ability
200 * context.
201 *
202 * @return true if the associated value can be evaluated without ability
203 * context.
204 */
205 public boolean canBePreempted() {
206 if (ordinal == IdTokens.STACK)
207 return false;
208 return on == null || on.canBePreempted();
209 }
210
211 @Override
212 public String toString() {
213 if (on != null)
214 return on.toString();
215 int index = ArrayUtils.indexOf(REGISTER_VALUES, ordinal);
216 if (index != -1)
217 return REGISTER_NAMES[index];
218 return "?";
219 }
220
221 /***
222 * Accessible register names. <br>
223 * Preserve alphabetical order of this array.
224 */
225 public static final String[] REGISTER_NAMES = { "ability", "card",
226 "dealtable", "game.static", "player", "private-object", "required-mana",
227 "stack", "target" };
228
229 /***
230 * Accessible register values. <br>
231 * Preserve order of this array to suit to the <code>REGISTER_NAMES</code>'s
232 * order.
233 */
234 public static final int[] REGISTER_VALUES = { IdTokens.DELAYED_REGISTERS,
235 IdTokens.CARD, IdTokens.DEALTABLE, IdTokens.STATIC_REGISTER,
236 IdTokens.PLAYER, IdTokens.PRIVATE_NAMED_TARGETABLE,
237 IdTokens.REQUIRED_MANA, IdTokens.STACK, IdTokens.TARGET };
238
239 /***
240 * The register may be identified to a player or a card. Is <code>null</code>
241 * if represents anything else such as stack, game register,...
242 */
243 private final TestOn on;
244
245 /***
246 * This values is equals to the TestOn ordinal when is not <code>null</code>,
247 * or represents the stack, game register,... identifier.
248 */
249 private final int ordinal;
250
251 /***
252 * Differents cached instances of this class.
253 */
254 private static Map<Integer, Register> values;
255 }