View Javadoc

1   /*
2    *   Magic-Project is a turn based strategy simulator
3    *   Copyright (C) 2003-2007 Fabrice Daugan
4    *
5    *   This program is free software; you can redistribute it and/or modify it 
6    * under the terms of the GNU General Public License as published by the Free 
7    * Software Foundation; either version 2 of the License, or (at your option) any
8    * later version.
9    *
10   *   This program is distributed in the hope that it will be useful, but WITHOUT 
11   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12   * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more 
13   * details.
14   *
15   *   You should have received a copy of the GNU General Public License along  
16   * with this program; if not, write to the Free Software Foundation, Inc., 
17   * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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 }