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.xml.tbs;
20  
21  import java.io.FileOutputStream;
22  import java.io.IOException;
23  import java.io.OutputStream;
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.HashMap;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Set;
31  import java.util.Stack;
32  
33  import net.sf.magicproject.modifier.ModifierType;
34  import net.sf.magicproject.operation.IdOperations;
35  import net.sf.magicproject.token.IdPropertyType;
36  import net.sf.magicproject.token.IdTokens;
37  import net.sf.magicproject.token.IdZones;
38  import net.sf.magicproject.tools.MToolKit;
39  import net.sf.magicproject.tools.PairStringInt;
40  import net.sf.magicproject.ui.component.CardPropertiesPanel;
41  import net.sf.magicproject.xml.XmlAction;
42  import net.sf.magicproject.xml.XmlConfiguration;
43  import net.sf.magicproject.xml.XmlModifier;
44  import net.sf.magicproject.xml.XmlParser;
45  import net.sf.magicproject.xml.XmlTbs;
46  import net.sf.magicproject.xml.XmlTest;
47  import net.sf.magicproject.xml.XmlToMDB;
48  import net.sf.magicproject.xml.XmlTools;
49  import net.sf.magicproject.xml.XmlParser.Node;
50  
51  import org.apache.commons.io.FilenameUtils;
52  
53  /***
54   * This class represents an implementation of the XmlToMDB interface that
55   * converts a XML tbs node to its binary form to the given OutputSource.
56   * 
57   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan</a>
58   * @since 0.82
59   * @since 0.83 damage types are exported
60   */
61  public class Tbs implements XmlToMDB {
62  
63  	/***
64  	 * Converts the given tbs XML node to its binary form writing in the given
65  	 * OutputStream.
66  	 * 
67  	 * @see net.sf.magicproject.token.IdTokens#PLAYER_REGISTER_SIZE
68  	 * @see net.sf.magicproject.stack.phasetype.PhaseType
69  	 * @see net.sf.magicproject.clickable.ability.SystemAbility
70  	 * @see net.sf.magicproject.tools.StatePicture
71  	 * @param node
72  	 *          the XML card structure
73  	 * @param out
74  	 *          outputstream where the card structure will be saved
75  	 * @return the amount of written action in the output.
76  	 * @throws IOException
77  	 *           error during the writting.
78  	 * @see net.sf.magicproject.deckbuilder.MdbLoader#loadMDB(String, int)
79  	 */
80  	public final int buildMdb(Node node, OutputStream out) throws IOException {
81  		final FileOutputStream fileOut = (FileOutputStream) out;
82  		referencedTest = new HashMap<String, Node>();
83  		referencedAbilities = new HashMap<String, Node>();
84  		referencedActions = new HashMap<String, List<Node>>();
85  		referencedAttachments = new HashMap<String, Node>();
86  		referencedNonMacroActions = new HashSet<String>();
87  		referencedNonMacroAttachments = new HashSet<String>();
88  		macroActions = new Stack<List<Node>>();
89  		resolveReferences = false;
90  
91  		MToolKit.writeString(out, node.getAttribute("name"));
92  		System.out.println("Building " + node.getAttribute("name") + " rules...");
93  		MToolKit.writeString(out, node.getAttribute("version"));
94  		MToolKit.writeString(out, node.getAttribute("author"));
95  		MToolKit.writeString(out, node.getAttribute("comment"));
96  
97  		// Write database configuration
98  		final Node database = node.get("database-properties");
99  		Map<String, IdPropertyType> properties = new HashMap<String, IdPropertyType>();
100 		for (java.lang.Object obj : database) {
101 			if (obj instanceof Node) {
102 				Node nodePriv = (Node) obj;
103 				String propertyType = nodePriv.getAttribute("type");
104 				IdPropertyType propertyId;
105 				if (propertyType == null || propertyType.equals(String.class.getName())) {
106 					if ("true".equalsIgnoreCase(nodePriv.getAttribute("translate"))) {
107 						propertyId = IdPropertyType.SIMPLE_TRANSLATABLE_PROPERTY;
108 					} else {
109 						propertyId = IdPropertyType.SIMPLE_PROPERTY;
110 					}
111 				} else if ("java.util.List".equals(propertyType)) {
112 					if ("true".equalsIgnoreCase(nodePriv.getAttribute("translate"))) {
113 						propertyId = IdPropertyType.COLLECTION_TRANSLATABLE_PROPERTY;
114 					} else {
115 						propertyId = IdPropertyType.COLLECTION_PROPERTY;
116 					}
117 				} else {
118 					throw new InternalError("Unknow property type '" + propertyType + "'");
119 				}
120 				properties.put(nodePriv.getAttribute("name"), propertyId);
121 			}
122 		}
123 		out.write(properties.size());
124 		for (java.lang.String propertyName : properties.keySet()) {
125 			properties.get(propertyName).serialize(out);
126 			MToolKit.writeString(out, propertyName);
127 		}
128 
129 		MToolKit.writeString(out, node.getAttribute("art-url"));
130 		MToolKit.writeString(out, node.getAttribute("back-picture"));
131 		MToolKit.writeString(out, node.getAttribute("damage-picture"));
132 		MToolKit.writeString(out, (String) node.get("licence").get(0));
133 
134 		// Manas
135 		final Node manas = node.get("mana-symbols");
136 
137 		// Colored manas
138 		final Node colored = manas.get("colored");
139 		MToolKit.writeString(out, colored.getAttribute("url"));
140 		MToolKit.writeString(out, colored.getAttribute("big-url"));
141 		for (java.lang.Object obj : colored) {
142 			if (obj instanceof Node) {
143 				Node nodePriv = (Node) obj;
144 				out.write(XmlTools.getValue(nodePriv.getAttribute("name")));
145 				MToolKit.writeString(out, nodePriv.getAttribute("picture"));
146 				MToolKit.writeString(out, nodePriv.getAttribute("big-picture")
147 						.toString());
148 			}
149 		}
150 
151 		// Colorless manas
152 		final Node colorless = manas.get("colorless");
153 		MToolKit.writeString(out, colorless.getAttribute("url"));
154 		MToolKit.writeString(out, colorless.getAttribute("big-url"));
155 		MToolKit.writeString(out, colorless.getAttribute("unknown"));
156 		out.write(colorless.getNbNodes());
157 		for (java.lang.Object obj : colorless) {
158 			if (obj instanceof Node) {
159 				final Node nodePriv = (Node) obj;
160 				out.write(Integer.parseInt(nodePriv.getAttribute("amount")));
161 				MToolKit.writeString(out, nodePriv.getAttribute("picture"));
162 			}
163 		}
164 
165 		// Prepare the shortcut to card's bytes offset
166 		final long shortcutCardBytes = fileOut.getChannel().position();
167 		MToolKit.writeInt24(out, 0);
168 
169 		// Write the user defined deck constraints
170 		final Set<String> definedConstraints = new HashSet<String>();
171 		List<Node> deckConstraints = XmlTools.getExternalizableNode(node,
172 				"deck-constraints").getNodes("deck-constraint");
173 		out.write(deckConstraints.size());
174 		for (Node deckConstraint : deckConstraints) {
175 			// Write the constraint key name
176 			String deckName = deckConstraint.getAttribute("name");
177 			MToolKit.writeString(out, deckName);
178 
179 			// Write extend
180 			String extend = deckConstraint.getAttribute("extends");
181 			MToolKit.writeString(out, extend);
182 			if (extend != null && extend.length() > 0
183 					&& !definedConstraints.contains(extend)) {
184 				throw new RuntimeException(
185 						"'"
186 								+ deckName
187 								+ "' is supposed extending '"
188 								+ extend
189 								+ "' but has not been found. Note that declaration order is important.");
190 			}
191 
192 			// Write the constraint
193 			XmlTools.defaultOnMeTag = false;
194 			XmlTest.getTest("test").buildMdb(deckConstraint, out);
195 			definedConstraints.add(deckName);
196 		}
197 		// END OF HEADER
198 
199 		// additional zones
200 		final List<XmlParser.Node> additionalZones = node.get("layouts").get(
201 				"zones").get("additional-zones").getNodes("additional-zone");
202 		out.write(additionalZones.size());
203 		int zoneId = IdZones.FIRST_ADDITIONAL_ZONE;
204 		for (XmlParser.Node additionalZone : additionalZones) {
205 			final String zoneName = additionalZone.getAttribute("name");
206 			if (zoneId > IdZones.LAST_ADDITIONAL_ZONE) {
207 				throw new RuntimeException("Cannot add more additional-zone ("
208 						+ zoneName + "), increase core limitation");
209 			}
210 			XmlTools.zones.put(zoneName, zoneId++);
211 			MToolKit.writeString(out, zoneName);
212 			MToolKit.writeString(out, additionalZone.getAttribute("layout-class"));
213 			MToolKit.writeString(out, additionalZone.getAttribute("constraint-you"));
214 			MToolKit.writeString(out, additionalZone
215 					.getAttribute("constraint-opponent"));
216 		}
217 
218 		// Initial zone id
219 		out.write(XmlTools.getZone(node.get("layouts").get("zones").getAttribute(
220 				"default-zone")));
221 
222 		// the references
223 		final Node references = XmlTools.getExternalizableNode(node, "references");
224 
225 		// the tests references
226 		System.out.println("\tshared tests...");
227 		XmlTools.defaultOnMeTag = true;
228 		final Node tests = references.get("tests");
229 		if (tests == null) {
230 			out.write(0);
231 		} else {
232 			out.write(tests.getNbNodes());
233 			for (java.lang.Object obj : tests) {
234 				if (obj instanceof Node) {
235 					String ref = ((Node) obj).getAttribute("reference-name").toString();
236 					referencedTest.put(ref, (Node) obj);
237 					MToolKit.writeString(out, ref);
238 					for (java.lang.Object objTest : (Node) obj) {
239 						if (objTest instanceof Node) {
240 							final Node node1 = (Node) objTest;
241 							try {
242 								XmlTest.getTest(node1.getTag()).buildMdb(node1, out);
243 							} catch (Throwable ie) {
244 								XmlConfiguration.error++;
245 								System.out.println("\t>> In referenced test '" + ref + "' : "
246 										+ ie.getMessage() + ". Context=" + objTest);
247 							}
248 							break;
249 						}
250 					}
251 				}
252 			}
253 		}
254 
255 		// the action references (not included into MDB)
256 		final Node actions = references.get("actions");
257 		System.out.print("\tactions : references (inlined in MDB)");
258 		if (actions != null) {
259 			for (java.lang.Object obj : actions) {
260 				if (obj instanceof Node) {
261 					final String ref = ((Node) obj).getAttribute("reference-name");
262 					final String globalName = ((Node) obj).getAttribute("name");
263 					// do not accept macro?
264 					if ("false".equals(((Node) obj).getAttribute("macro"))) {
265 						referencedNonMacroActions.add(ref);
266 					}
267 					final List<Node> actionList = new ArrayList<Node>();
268 					boolean firstIsDone = false;
269 					for (java.lang.Object actionI : (Node) obj) {
270 						if (actionI instanceof Node) {
271 							final Node action = (Node) actionI;
272 							// add action to the action list and replace the name of
273 							// sub-actions
274 							if (action.getAttribute("name") == null) {
275 								if (globalName != null) {
276 									if (firstIsDone) {
277 										action.addAttribute(new XmlParser.Attribute("name", "%"
278 												+ globalName));
279 									} else {
280 										action.addAttribute(new XmlParser.Attribute("name",
281 												globalName));
282 										firstIsDone = true;
283 									}
284 								} else if (firstIsDone) {
285 									action
286 											.addAttribute(new XmlParser.Attribute("name", "%" + ref));
287 								} else {
288 									action.addAttribute(new XmlParser.Attribute("name", ref));
289 									firstIsDone = true;
290 								}
291 							} else if (!firstIsDone) {
292 								firstIsDone = true;
293 							}
294 							actionList.add((Node) actionI);
295 						}
296 					}
297 					// add this reference
298 					referencedActions.put(ref, actionList);
299 
300 				}
301 			}
302 		}
303 
304 		// the attachment references (not included into MDB)
305 		final Node attachments = references.get("attachments");
306 		System.out.print(", attachments");
307 		if (attachments != null) {
308 			for (java.lang.Object obj : attachments) {
309 				if (obj instanceof Node) {
310 					final String ref = ((Node) obj).getAttribute("reference-name");
311 					// do not accept macro?
312 					if ("false".equals(((Node) obj).getAttribute("macro"))) {
313 						referencedNonMacroAttachments.add(ref);
314 					}
315 					// add this reference
316 					referencedAttachments.put(ref, (Node) obj);
317 				}
318 			}
319 		}
320 
321 		// action pictures
322 		final Node actionsPictures = node.get("action-pictures");
323 		System.out.print(", pictures");
324 		if (actionsPictures == null) {
325 			out.write(0);
326 			out.write('\0');
327 		} else {
328 			MToolKit.writeString(out, actionsPictures.getAttribute("url"));
329 			out.write(actionsPictures.getNbNodes());
330 			for (java.lang.Object obj : actionsPictures) {
331 				if (obj instanceof Node) {
332 					final Node actionPicture = (Node) obj;
333 					MToolKit.writeString(out, actionPicture.getAttribute("name"));
334 					MToolKit.writeString(out, actionPicture.getAttribute("picture"));
335 				}
336 			}
337 		}
338 
339 		// constraints on abilities linked to action
340 		final Node constraints = node.get("action-constraints");
341 		System.out.println(", constraints");
342 		if (constraints == null) {
343 			out.write(0);
344 		} else {
345 			out.write(constraints.getNbNodes());
346 			for (java.lang.Object obj : constraints) {
347 				if (obj instanceof Node) {
348 					final Node constraint = (Node) obj;
349 					for (java.lang.Object objA : constraint.get("actions")) {
350 						if (objA instanceof Node) {
351 							XmlAction.getAction(((Node) objA).getTag()).buildMdb((Node) objA,
352 									out);
353 							break;
354 						}
355 					}
356 					if ("or".equals(constraint.getAttribute("operation"))) {
357 						out.write(IdOperations.OR);
358 					} else {
359 						out.write(IdOperations.AND);
360 					}
361 					XmlTest.getTest("test").buildMdb(constraint.get("test"), out);
362 				}
363 			}
364 		}
365 
366 		// objects defined in this TBS
367 		System.out.println("\tobjects...");
368 		final List<Node> objects = node.get("objects").getNodes("object");
369 		out.write(objects.size());
370 		for (Node object : objects) {
371 			// write object
372 			final XmlParser.Attribute objectName = new XmlParser.Attribute("name",
373 					object.getAttribute("name"));
374 			boolean onePresent = false;
375 			for (java.lang.Object modifierTmp : object) {
376 				if (modifierTmp instanceof Node) {
377 					// write the 'has-next' flag
378 					if (onePresent) {
379 						out.write(1);
380 					}
381 
382 					// write the object-modifier
383 					final Node modifier = (Node) modifierTmp;
384 					modifier.addAttribute(objectName);
385 					XmlModifier.getModifier(modifier.getTag()).buildMdb(modifier, out);
386 
387 					// Write the 'paint' flag
388 					if (onePresent) {
389 						out.write(0);
390 					} else {
391 						out.write(1);
392 					}
393 					onePresent = true;
394 				}
395 			}
396 			if (!onePresent) {
397 				// no modifier associated to this object, we write a virtual ONE
398 				ModifierType.REGISTER_MODIFIER.serialize(out);
399 				XmlModifier.buildMdbModifier(object, out);
400 
401 				// Write the modified register index && value
402 				XmlTools.writeConstant(out, 0);
403 				XmlTools.writeConstant(out, 0);
404 				out.write(IdOperations.ADD);
405 
406 				// Write the 'paint' flag
407 				out.write(0);
408 			}
409 
410 			// Write the 'has-next' flag
411 			out.write(0);
412 		}
413 
414 		// the abilities references
415 		System.out.println("\tshared abilities...");
416 		Node abilities = references.get("abilities");
417 		out.write(abilities.getNbNodes());
418 		macroActions.push(null);
419 		for (Node ability : abilities.getNodes("ability")) {
420 			String ref = ability.getAttribute("reference-name").toString();
421 			referencedAbilities.put(ref, ability);
422 			MToolKit.writeString(out, ref);
423 			try {
424 				Node node1 = (Node) ability.get(1);
425 				XmlTbs.getTbsComponent(node1.getTag()).buildMdb(node1, out);
426 			} catch (Throwable ie) {
427 				XmlConfiguration.error++;
428 				System.out.println("\t>> Error In referenced ability '" + ref + "' : "
429 						+ ie.getMessage() + "," + ie + ". Context=" + ability);
430 			}
431 		}
432 		macroActions.pop();
433 
434 		// damage types name
435 		System.out.println("\tdamage types...");
436 		Collections.sort(XmlConfiguration.exportedDamageTypes);
437 		int count = XmlConfiguration.exportedDamageTypes.size();
438 		out.write(count);
439 		for (int i = 0; i < count; i++) {
440 			final PairStringInt pair = XmlConfiguration.exportedDamageTypes.get(i);
441 			MToolKit.writeString(out, pair.text);
442 			MToolKit.writeInt16(out, pair.value);
443 		}
444 
445 		/***
446 		 * <ul>
447 		 * CARD'S PART :
448 		 * <li>state pictures
449 		 * <li>tooltip filters
450 		 * <li>exported types name
451 		 * <li>exported sorted properties name
452 		 * <li>implemented cards
453 		 * </ul>
454 		 */
455 
456 		// state pictures
457 		System.out.println("\tstates");
458 		final Node states = node.get("state-pictures");
459 		if (states == null) {
460 			out.write(0);
461 		} else {
462 			out.write(states.getNbNodes());
463 			for (java.lang.Object obj : states) {
464 				if (obj instanceof Node) {
465 					final Node ns = (Node) obj;
466 					MToolKit.writeString(out, ns.getAttribute("picture"));
467 					MToolKit.writeString(out, ns.getAttribute("name"));
468 					MToolKit.writeInt16(out, XmlTools.getInt(ns.getAttribute("state")));
469 					out.write(XmlTools.getInt(ns.getAttribute("index")));
470 					final int x = XmlTools.getInt(ns.getAttribute("x"));
471 					final int y = XmlTools.getInt(ns.getAttribute("y"));
472 					if (MToolKit.getConstant(x) == -1 && MToolKit.getConstant(y) != -1
473 							|| MToolKit.getConstant(x) != -1 && MToolKit.getConstant(y) == -1) {
474 						XmlConfiguration.error++;
475 						System.out
476 								.println("\t>> In state-picture '-1' value is allowed if and only if x AND y have this value.");
477 					}
478 					MToolKit.writeInt16(out, XmlTools.getInt(ns.getAttribute("x")));
479 					MToolKit.writeInt16(out, XmlTools.getInt(ns.getAttribute("y")));
480 					MToolKit.writeInt16(out, XmlTools.getInt(ns.getAttribute("width")));
481 					MToolKit.writeInt16(out, XmlTools.getInt(ns.getAttribute("height")));
482 					XmlTest.getTest("test").buildMdb(node.get("display-test"), out);
483 				}
484 			}
485 		}
486 
487 		// tooltip filters
488 		System.out.println("\ttooltip filters...");
489 		final Node ttFilters = node.get("tooltip-filters");
490 		XmlTools.defaultOnMeTag = false;
491 		if (ttFilters == null) {
492 			out.write(0);
493 		} else {
494 			out.write(ttFilters.getNbNodes());
495 			for (java.lang.Object obj : ttFilters) {
496 				if (obj instanceof Node) {
497 					buildMdbTooltipFilter((Node) obj, out);
498 				}
499 			}
500 		}
501 
502 		// exported types name
503 		System.out.println("\texported type...");
504 		Collections.sort(XmlConfiguration.exportedTypes);
505 		int nbTypes = XmlConfiguration.exportedTypes.size();
506 		out.write(nbTypes);
507 		for (int i = 0; i < nbTypes; i++) {
508 			final PairStringInt pair = XmlConfiguration.exportedTypes.get(i);
509 			MToolKit.writeString(out, pair.text);
510 			MToolKit.writeInt16(out, pair.value);
511 		}
512 
513 		// exported sorted properties name and associated pictures
514 		System.out.println("\tproperties...");
515 		Collections.sort(XmlConfiguration.exportedProperties);
516 		final int nbProperties = XmlConfiguration.exportedProperties.size();
517 		MToolKit.writeInt16(out, nbProperties);
518 		for (int i = 0; i < nbProperties; i++) {
519 			final PairStringInt pair = XmlConfiguration.exportedProperties.get(i);
520 			MToolKit.writeInt16(out, pair.value);
521 			MToolKit.writeString(out, pair.text);
522 		}
523 		MToolKit.writeInt16(out, XmlConfiguration.propertyPictures.size());
524 		for (Integer property : XmlConfiguration.propertyPictures.keySet()) {
525 			MToolKit.writeInt16(out, property.intValue());
526 			MToolKit
527 					.writeString(out, XmlConfiguration.propertyPictures.get(property));
528 		}
529 
530 		/***
531 		 * <ul>
532 		 * STACK MANAGER'S PART :
533 		 * <li>first player registers
534 		 * <li>second player registers
535 		 * <li>abortion zone
536 		 * </ul>
537 		 */
538 		// player registers
539 		System.out.println("\tinitial registers...");
540 		Node registers = node.get("registers-first-player");
541 		final byte[] registersBytes = new byte[IdTokens.PLAYER_REGISTER_SIZE];
542 		if (registers != null) {
543 			final List<Node> list = registers.getNodes("register");
544 			for (Node register : list) {
545 				registersBytes[XmlTools.getInt(register.getAttribute("index"))] = (byte) XmlTools
546 						.getInt(register.getAttribute("value"));
547 			}
548 		}
549 		out.write(registersBytes);
550 		registers = node.get("registers-second-player");
551 		final byte[] registersBytes2 = new byte[IdTokens.PLAYER_REGISTER_SIZE];
552 		if (registers != null) {
553 			final List<Node> list = registers.getNodes("register");
554 			for (Node register : list) {
555 				registersBytes2[XmlTools.getInt(register.getAttribute("index"))] = (byte) XmlTools
556 						.getInt(register.getAttribute("value"));
557 			}
558 		}
559 		out.write(registersBytes2);
560 
561 		/*
562 		 * TODO abortion zone
563 		 */
564 		final Node refAbilities = node.get("abilities");
565 		out.write(XmlTools.getZone(refAbilities.getAttribute("abortionzone")));
566 
567 		// additional costs
568 		System.out.println("\tadditional-costs...");
569 		final List<Node> additionalCosts = node.get("additional-costs").getNodes(
570 				"additional-cost");
571 		out.write(additionalCosts.size());
572 		for (Node additionalCost : additionalCosts) {
573 			XmlTest.getTest("test").buildMdb(additionalCost.get("test"), out);
574 			XmlTbs.writeActionList(additionalCost.get("cost"), out);
575 		}
576 
577 		/***
578 		 * <ul>
579 		 * EVENT MANAGER'S PART :
580 		 * <li>phases
581 		 * <li>turn-structure
582 		 * <li>first phase index
583 		 * </ul>
584 		 */
585 		// phases
586 		System.out.println("\tphases...");
587 		final Node phases = node.get("phases");
588 		out.write(phases.getNbNodes());
589 		for (java.lang.Object obj : phases) {
590 			if (obj instanceof Node) {
591 				buildMdbPhaseType((Node) obj, out);
592 			}
593 		}
594 
595 		// turn structure
596 		final String list = phases.getAttribute("turn-structure");
597 		System.out.println("\tturn structure...");
598 		final String[] arrayid = list.split(" ");
599 		out.write(arrayid.length);
600 		for (String id : arrayid) {
601 			out.write(XmlTools.getAliasValue(id));
602 		}
603 
604 		// first phase index for first turn
605 		out.write(Integer.parseInt(phases.getAttribute("start")));
606 
607 		// state based abilities
608 		System.out.println("\trule abilities...");
609 		out.write(refAbilities.getNbNodes());
610 		for (java.lang.Object obj : refAbilities) {
611 			if (obj instanceof Node) {
612 				try {
613 					XmlTbs.getTbsComponent(((Node) obj).getTag()).buildMdb((Node) obj,
614 							out);
615 				} catch (Throwable ie) {
616 					XmlConfiguration.error++;
617 					System.out.println("\t>> Error in system ability '"
618 							+ ((Node) obj).getAttribute("name") + "' : " + ie.getMessage()
619 							+ ". Context=" + obj);
620 					break;
621 				}
622 			}
623 		}
624 
625 		// static-modifiers
626 		System.out.println("\tstatic-modifiers...");
627 		final Node modifiers = node.get("static-modifiers");
628 		if (modifiers == null) {
629 			out.write(0);
630 		} else {
631 			out.write(modifiers.getNbNodes());
632 			for (java.lang.Object obj : modifiers) {
633 				if (obj instanceof Node) {
634 					XmlModifier.getModifier("static-modifier").buildMdb((Node) obj, out);
635 				}
636 			}
637 		}
638 
639 		// layouts
640 		System.out.println("\tlayouts...");
641 		final Node layouts = node.get("layouts");
642 
643 		// init task pane layout
644 		writeTaskPaneElement(layouts.get("common-panel").get("card-details").get(
645 				"properties"), out);
646 
647 		// Sector of play zone for layouts
648 		List<Node> sectors = layouts.get("zones").get("play").getNodes("sector");
649 		out.write(sectors.size());
650 		for (XmlParser.Node sector : sectors) {
651 			XmlTest.getTest("test").buildMdb(sector, out);
652 			MToolKit.writeString(out, sector.getAttribute("constraint"));
653 		}
654 
655 		// Update the shortcut to the first bytes of cards
656 		final long cardBytesPosition = fileOut.getChannel().position();
657 		fileOut.getChannel().position(shortcutCardBytes);
658 		MToolKit.writeInt24(out, (int)cardBytesPosition);
659 		fileOut.getChannel().position(cardBytesPosition);
660 
661 		// cards bytes + names
662 		resolveReferences = true;
663 		System.out.println("Processing cards...");
664 		String xmlFile = node.getAttribute("xmlFile");
665 		try {
666 			final String baseName = FilenameUtils.getBaseName(xmlFile);
667 			XmlTbs.updateMdb(baseName, out);
668 		} catch (Throwable e2) {
669 			XmlConfiguration.error++;
670 			e2.printStackTrace();
671 			System.out.println("\t>> Error found in cards parsing of rule '"
672 					+ xmlFile + "' : " + e2.getMessage());
673 		}
674 
675 		System.out.println(node.getAttribute("name") + " rules finished");
676 		return 0;
677 	}
678 
679 	private void writeTaskPaneElement(Node node, OutputStream out)
680 			throws IOException {
681 		final List<Node> elements = node.getNodes("menu-element");
682 		final List<Node> attributes = node.getNodes("menu-attribute");
683 		out.write((elements == null ? 0 : elements.size())
684 				+ (attributes == null ? 0 : attributes.size()));
685 		for (java.lang.Object nestedNode : node) {
686 			if (nestedNode instanceof Node) {
687 				final Node task = (Node) nestedNode;
688 				if ("menu-element".equals(task.getTag())) {
689 					out.write(CardPropertiesPanel.NESTED_ELEMENT);
690 					MToolKit.writeString(out, task.getAttribute("name"));
691 					writeTaskPaneElement(task, out);
692 				} else if ("menu-attribute".equals(task.getTag())) {
693 					out.write(CardPropertiesPanel.ATTRIBUTE);
694 					MToolKit.writeString(out, task.getAttribute("type").toLowerCase());
695 					MToolKit.writeString(out, task.getAttribute("name"));
696 					MToolKit.writeString(out, task.getAttribute("value"));
697 				} else {
698 					XmlConfiguration.warning++;
699 					System.out.println("\t== Warning non supported task type : "
700 							+ task.getTag());
701 				}
702 			}
703 		}
704 
705 	}
706 
707 	/***
708 	 * <ul>
709 	 * Structure of stream : Data[size]
710 	 * <li>phase name + '\0' [...]</li>
711 	 * <li>phase identifiant [1]</li>
712 	 * <li>empty stack playable, idCards for current player [2]</li>
713 	 * <li>empty stack playable, idCards for non-current player [2]</li>
714 	 * <li>middle resolution, playable idCards for current player [2]</li>
715 	 * <li>middle resolution, playable idCards for non-current player [2]</li>
716 	 * </ul>
717 	 * 
718 	 * @param node
719 	 *          the XML phase type structure
720 	 * @param out
721 	 *          outputstream where the card structure will be saved
722 	 * @throws IOException
723 	 *           error during the
724 	 * @see net.sf.magicproject.stack.phasetype.PhaseType
725 	 */
726 	public static final void buildMdbPhaseType(Node node, OutputStream out)
727 			throws IOException {
728 		MToolKit.writeString(out, node.getAttribute("name"));
729 		out.write(XmlTools.getAliasValue(node.getAttribute("name")));
730 		MToolKit.writeInt16(out, XmlTools.getIdCards(node
731 				.getAttribute("playable-empty-stack-you")));
732 		MToolKit.writeInt16(out, XmlTools.getIdCards(node
733 				.getAttribute("playable-empty-stack-opponent")));
734 		MToolKit.writeInt16(out, XmlTools.getIdCards(node
735 				.getAttribute("playable-middle-resolution-you")));
736 		MToolKit.writeInt16(out, XmlTools.getIdCards(node
737 				.getAttribute("playable-middle-resolution-opponent")));
738 	}
739 
740 	/***
741 	 * <ul>
742 	 * Structure of stream : Data[size]
743 	 * <li>display powerANDtoughness yes=1,no=0 [1]</li>
744 	 * <li>display states yes=1,no=0 [1]</li>
745 	 * <li>display types yes=1,no=0 [1]</li>
746 	 * <li>display colors yes=1,no=0 [1]</li>
747 	 * <li>display properties yes=1,no=0 [1]</li>
748 	 * <li>display damage yes=1,no=0 [1]</li>
749 	 * <li>filter [...]</li>
750 	 * </ul>
751 	 * 
752 	 * @param node
753 	 *          the XML structure
754 	 * @param out
755 	 *          outputstream where the card structure will be saved
756 	 * @throws IOException
757 	 *           error during the writing.
758 	 */
759 	public static final void buildMdbTooltipFilter(Node node, OutputStream out)
760 			throws IOException {
761 
762 		out.write("true".equals(node.getAttribute("powerANDtoughness")) ? 1 : 0);
763 		out.write("true".equals(node.getAttribute("states")) ? 1 : 0);
764 		out.write("true".equals(node.getAttribute("types")) ? 1 : 0);
765 		out.write("true".equals(node.getAttribute("colors")) ? 1 : 0);
766 		out.write("true".equals(node.getAttribute("properties")) ? 1 : 0);
767 		out.write("true".equals(node.getAttribute("damage")) ? 1 : 0);
768 		XmlTest.getTest("test").buildMdb(node.get("filter"), out);
769 	}
770 
771 	/***
772 	 * Push an action (accepting <code>null</code>) for macro.
773 	 * 
774 	 * @param node
775 	 *          the node to give to the next macro.
776 	 */
777 	public static void pushMacroAction(List<Node> node) {
778 		macroActions.push(node);
779 	}
780 
781 	/***
782 	 * Return the last given action to a macro.
783 	 * 
784 	 * @return the last given action to a macro.
785 	 */
786 	public static List<Node> peekMacroAction() {
787 		return macroActions.peek();
788 	}
789 
790 	/***
791 	 * Remove the last given action to a macro.
792 	 */
793 	public static void popMacroAction() {
794 		macroActions.pop();
795 	}
796 
797 	/***
798 	 * Available ability references of this TBS
799 	 */
800 	public static Map<String, Node> referencedAbilities = null;
801 
802 	/***
803 	 * Available test references of this TBS
804 	 */
805 	public static Map<String, Node> referencedTest = null;
806 
807 	/***
808 	 * Available actions references of this TBS
809 	 */
810 	public static Map<String, List<Node>> referencedActions = null;
811 
812 	/***
813 	 * Available actions references of this TBS do not accepting macro
814 	 */
815 	public static Set<String> referencedNonMacroActions = null;
816 
817 	/***
818 	 * Available attachments references of this TBS do not accepting macro
819 	 */
820 	public static Set<String> referencedNonMacroAttachments = null;
821 
822 	/***
823 	 * Available attachments references of this TBS.
824 	 */
825 	public static Map<String, Node> referencedAttachments = null;
826 
827 	/***
828 	 * Available node for action of macro.
829 	 */
830 	public static Stack<List<Node>> macroActions = null;
831 
832 	/***
833 	 * Are the references must be resolved.
834 	 */
835 	public static boolean resolveReferences;
836 }