1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package net.sf.firemox.deckbuilder;
21
22 import java.io.File;
23 import java.io.FileInputStream;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.InputStream;
27
28 import javax.swing.JOptionPane;
29
30 import net.sf.firemox.action.ActionFactory;
31 import net.sf.firemox.clickable.ability.AbilityFactory;
32 import net.sf.firemox.clickable.target.card.CardFactory;
33 import net.sf.firemox.clickable.target.card.Damage;
34 import net.sf.firemox.database.DatabaseFactory;
35 import net.sf.firemox.modifier.model.ObjectFactory;
36 import net.sf.firemox.stack.EventManager;
37 import net.sf.firemox.stack.MPhase;
38 import net.sf.firemox.stack.StackManager;
39 import net.sf.firemox.test.TestFactory;
40 import net.sf.firemox.token.IdCommonToken;
41 import net.sf.firemox.token.IdConst;
42 import net.sf.firemox.tools.Log;
43 import net.sf.firemox.tools.MToolKit;
44 import net.sf.firemox.ui.MagicUIComponents;
45 import net.sf.firemox.ui.i18n.LanguageManager;
46 import net.sf.firemox.ui.i18n.LanguageManagerMDB;
47 import net.sf.firemox.xml.XmlConfiguration;
48 import net.sf.firemox.zone.Play;
49 import net.sf.firemox.zone.ZoneManager;
50
51 import org.apache.commons.io.IOUtils;
52
53 /***
54 * Set of tools to manipulate the MDB format : load headers, finding cards,...
55 *
56 * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
57 * @since 0.54
58 */
59 public final class MdbLoader {
60
61 /***
62 * The first available card's name offset.
63 */
64 private static int firstCardsNamesOffset;
65
66 /***
67 * The first available card's bytes offset.
68 */
69 private static long firstCardsBytesOffset;
70
71 /***
72 * The current full name of selected TBS
73 */
74 private static String tbsFullName = null;
75
76 /***
77 * The current TBS disclaimer
78 */
79 private static String disclaimer = null;
80
81 /***
82 * The current TBS more information text
83 */
84 private static String moreInfo = null;
85
86 /***
87 * The current TBS comment
88 */
89 private static String author = null;
90
91 /***
92 * The current TBS version
93 */
94 private static String version = null;
95
96 /***
97 * Indicates where to find the art from a URL
98 */
99 private static String artURL = null;
100
101 /***
102 * Indicates the picture name of the back picture.
103 */
104 public static String backPicture = null;
105
106 /***
107 * Indicates the picture name of the damage picture.
108 */
109 public static String damagePicture = null;
110
111 /***
112 * This is the defined colorless mana file names without base name. The base
113 * web base name is <code>colorlessURL</code> and the local base name is
114 * <code>tbs/TBS_NAME/images/mana/colorless/</code>
115 *
116 * @see #colorlessSmlManas
117 */
118 public static String[] colorlessSmlManas;
119
120 /***
121 * This the HTML representation of defined small colorless manas.
122 *
123 * @see #colorlessSmlManas
124 */
125 public static String[] colorlessSmlManasHtml;
126
127 /***
128 * This is the filename without base name corresponding to the big colorless
129 * picture. The base web base name is <code>colorlessURL</code> and the
130 * local base name is <code>tbs/TBS_NAME/images/mana/colorless/big/</code>
131 */
132 public static String colorlessBigURL;
133
134 /***
135 * This is the defined small colored mana file names without base name. The
136 * base web base name is <code>coloredManaSmlURL</code> and the local base
137 * name is <code>tbs/TBS_NAME/images/mana/colored/small/</code>
138 *
139 * @see #coloredManaSmlURL
140 */
141 public static String[] coloredSmlManas;
142
143 /***
144 * This the HTML representation of defined small colored manas.
145 *
146 * @see #colorlessSmlManas
147 */
148 public static String[] coloredSmlManasHtml;
149
150 /***
151 * This is the defined small colored mana file names without base name. The
152 * base web base name is <code>coloredManaBigURL</code> and the local base
153 * name is <code>tbs/TBS_NAME/images/mana/colored/big/</code>
154 *
155 * @see #coloredManaBigURL
156 */
157 public static String[] coloredBigManas;
158
159 /***
160 * This is the web base name where colorless mana pictures can be found.
161 */
162 public static String colorlessURL;
163
164 /***
165 * This is the web base name where small colored mana pictures can be found.
166 */
167 public static String coloredManaSmlURL;
168
169 /***
170 * This is the web base name where big colored mana pictures can be found.
171 */
172 public static String coloredManaBigURL;
173
174 /***
175 * The picture used for unknown mana cost value.
176 */
177 public static String unknownSmlManaHtml;
178
179 /***
180 * The picture used for unknown mana cost value.
181 */
182 public static String unknownSmlMana;
183
184 /***
185 * The offset position of end of header.
186 */
187 private static long endOfHeaderOffset;
188
189 /***
190 * The last loaded MDB File. Is <code>null</code> while no MDB has been
191 * loaded..
192 */
193 private static String lastMdbFile;
194
195 /***
196 * Flag indicating if the XML file have been checked or not for this instance.
197 */
198 private static boolean instanceIsChecked = false;
199
200 /***
201 * The last opened stream of the current MDB.
202 */
203 private static FileInputStream lastMdbStream;
204
205 /***
206 * Create a new instance of this class.
207 */
208 private MdbLoader() {
209 super();
210 }
211
212 /***
213 * Load author, tbs name,... Load the rules of this MDB and set them to the MP
214 * environment, set the current offset to the beginning of card section. <br>
215 *
216 * @param dbFile
217 * the MDB file containing rules.
218 * @param firstPlayer
219 * the index of first player.
220 * @return the stream as is, the current offset corresponds to the beginning
221 * of cards section.
222 * @throws IOException
223 * If some other I/O error occurs
224 */
225 public static FileInputStream loadMDB(String dbFile, int firstPlayer)
226 throws IOException {
227 FileInputStream dbStream = loadHeader(dbFile);
228
229
230 StackManager.getInstance().init(dbStream, firstPlayer);
231
232
233 EventManager.init(dbStream, dbFile);
234
235
236 if (MagicUIComponents.isUILoaded()) {
237 MagicUIComponents.databasePanel.init(dbStream);
238 }
239
240
241 if (MagicUIComponents.isUILoaded()) {
242 Play.initSectorConfigurations(dbStream);
243 }
244
245
246 resetMdb();
247
248
249
250
251
252 return dbStream;
253 }
254
255 /***
256 * Reset the given MDB stream to the first offset of card references.
257 *
258 * @return the stream.
259 */
260 public static FileInputStream resetMdb() {
261 try {
262 if (lastMdbStream == null) {
263 openMdb(MToolKit.mdbFile, false);
264 }
265 lastMdbStream.getChannel().position(firstCardsNamesOffset);
266 } catch (IOException io) {
267 throw new RuntimeException(io);
268 }
269 return lastMdbStream;
270 }
271
272 /***
273 * Check the given MDB file and update it if needed. Then open it and return
274 * the created stream.
275 *
276 * @param mdbFile
277 * the MDB file containing rules.
278 * @param forceRecheck
279 * if true, all files are checked even if it has already been done.
280 * @return return the opened stream as is when file is opened.
281 * @throws IOException
282 * If some other I/O error occurs
283 */
284 public static FileInputStream openMdb(String mdbFile, boolean forceRecheck)
285 throws IOException {
286
287 if (lastMdbStream != null && !forceRecheck) {
288 try {
289 lastMdbStream.getChannel().position(0);
290 return lastMdbStream;
291 } catch (IOException io) {
292
293 }
294 }
295
296
297 if (!forceRecheck) {
298 IOUtils.closeQuietly(lastMdbStream);
299 }
300
301
302 final File file = MToolKit.getFile(mdbFile);
303 if (!instanceIsChecked || forceRecheck) {
304 XmlConfiguration.main("-g", MToolKit.tbsName);
305 if (!XmlConfiguration.hasError())
306 instanceIsChecked = true;
307 }
308 if (file == null) {
309 lastMdbStream = new FileInputStream(MToolKit.getFile(mdbFile));
310 } else {
311 lastMdbStream = new FileInputStream(file);
312 }
313 return lastMdbStream;
314 }
315
316 /***
317 * Load author, tbs name,... Load the rules of this MDB and set them to the MP
318 * environment, set the current offset to the begin of card section and return
319 * it's position Load settings associated to this MDB. <br>
320 *
321 * @param dbFile
322 * the MDB file containing rules.
323 * @return return the opened stream as is, the current offset corresponds to
324 * the last byte read of the disclaimer/license section.
325 * @throws IOException
326 * If some other I/O error occurs
327 */
328 public static FileInputStream loadHeader(String dbFile) throws IOException {
329 if (dbFile.equals(lastMdbFile)) {
330 lastMdbStream.getChannel().position(endOfHeaderOffset);
331 return lastMdbStream;
332 }
333 closeMdb();
334 final FileInputStream dbStream = openMdb(dbFile, false);
335 tbsFullName = MToolKit.readString(dbStream);
336 version = MToolKit.readString(dbStream);
337 author = MToolKit.readString(dbStream);
338 moreInfo = MToolKit.readString(dbStream);
339
340
341 DatabaseFactory.init(dbStream);
342
343 artURL = MToolKit.readString(dbStream);
344 backPicture = MToolKit.readString(dbStream);
345 damagePicture = MToolKit.readString(dbStream);
346 disclaimer = MToolKit.readText(dbStream).trim();
347
348
349 coloredManaSmlURL = MToolKit.readString(dbStream);
350 coloredManaBigURL = MToolKit.readString(dbStream);
351 coloredBigManas = new String[IdCommonToken.COLOR_NAMES.length];
352 coloredSmlManas = new String[IdCommonToken.COLOR_NAMES.length];
353 coloredSmlManasHtml = new String[coloredBigManas.length];
354 for (int i = IdCommonToken.COLOR_NAMES.length; i-- > 1;) {
355 int index = dbStream.read();
356 coloredSmlManas[index] = MToolKit.readString(dbStream);
357 coloredBigManas[index] = MToolKit.readString(dbStream);
358 coloredSmlManasHtml[index] = "<img src='file:///"
359 + MToolKit.getTbsHtmlPicture("mana/colored/small/"
360 + coloredSmlManas[index]) + "'> ";
361 }
362
363
364 colorlessURL = MToolKit.readString(dbStream);
365 colorlessBigURL = MToolKit.readString(dbStream);
366 unknownSmlMana = MToolKit.readString(dbStream);
367 unknownSmlManaHtml = "<img src='file:///"
368 + MToolKit.getTbsHtmlPicture("mana/colorless/small/" + unknownSmlMana)
369 + "'> ";
370 colorlessSmlManas = new String[dbStream.read()];
371 colorlessSmlManasHtml = new String[colorlessSmlManas.length];
372 for (int i = colorlessSmlManas.length; i-- > 0;) {
373 int index = dbStream.read();
374 colorlessSmlManas[index] = MToolKit.readString(dbStream);
375 colorlessSmlManasHtml[index] = "<img src='file:///"
376 + MToolKit.getTbsHtmlPicture("mana/colorless/small/"
377 + colorlessSmlManas[index]) + "'> ";
378 }
379
380
381 firstCardsBytesOffset = MToolKit.readInt24(dbStream);
382
383
384 DeckConstraints.init(dbStream);
385
386
387 ZoneManager.initTbs(dbStream);
388
389
390 TestFactory.init(dbStream);
391
392
393 ActionFactory.init(dbStream);
394
395
396 ObjectFactory.init(dbStream);
397
398
399 AbilityFactory.init(dbStream);
400
401
402 Damage.init(dbStream);
403
404
405 CardFactory.init(dbStream);
406
407
408 endOfHeaderOffset = dbStream.getChannel().position();
409 dbStream.getChannel().position(firstCardsBytesOffset);
410 firstCardsNamesOffset = MToolKit.readInt24(dbStream);
411 dbStream.getChannel().position(endOfHeaderOffset);
412
413 lastMdbFile = dbFile;
414 return dbStream;
415 }
416
417 /***
418 * Save the settings corresponding to the current TBS
419 */
420 public static void saveTBSSettings() {
421 if (MToolKit.mdbFile != null) {
422 saveTBSSettings(MToolKit.mdbFile.replace(".mdb", ".pref"));
423 }
424 }
425
426 /***
427 * Save the settings corresponding to the current TBS
428 *
429 * @param settingFile
430 * the setting file where settings would be saved
431 */
432 private static void saveTBSSettings(String settingFile) {
433
434 if (EventManager.turnStructure == null) {
435
436 return;
437 }
438 try {
439 FileOutputStream out = new FileOutputStream(MToolKit.getFile(settingFile));
440 for (int i = 0; i < EventManager.turnStructure.length; i++) {
441 MPhase.phases[0][i].saveSettings(out);
442 }
443 for (int i = 0; i < EventManager.turnStructure.length; i++) {
444 MPhase.phases[1][i].saveSettings(out);
445 }
446 IOUtils.closeQuietly(out);
447 } catch (java.io.IOException e) {
448 JOptionPane.showMessageDialog(MagicUIComponents.magicForm,
449 LanguageManager.getString("loadtbssettingspb") + " : "
450 + e.getMessage(), LanguageManager.getString("error"),
451 JOptionPane.ERROR_MESSAGE);
452 System.exit(1);
453 }
454 }
455
456 /***
457 * Loading the settings corresponding to the current TBS
458 */
459 public static void loadTBSSettings() {
460 loadTBSSettings(MToolKit.mdbFile.substring(0, MToolKit.mdbFile
461 .lastIndexOf('.'))
462 + ".pref");
463 }
464
465 /***
466 * Loading the settings corresponding to the specified TBS
467 *
468 * @param settingFile
469 * the setting file where settings have been saved
470 */
471 private static void loadTBSSettings(String settingFile) {
472
473 if (MToolKit.tbsName == null) {
474
475 return;
476 }
477 try {
478 InputStream in = MToolKit.getResourceAsStream(settingFile);
479 for (int i = 0; i < EventManager.turnStructure.length; i++) {
480 MPhase.phases[0][i].loadSettings(in);
481 }
482 for (int i = 0; i < EventManager.turnStructure.length; i++) {
483 MPhase.phases[1][i].loadSettings(in);
484 }
485 IOUtils.closeQuietly(in);
486 } catch (IOException e) {
487 JOptionPane.showMessageDialog(MagicUIComponents.magicForm,
488 LanguageManager.getString("loadtbssettingspb") + " : "
489 + e.getMessage(), LanguageManager.getString("error"),
490 JOptionPane.ERROR_MESSAGE);
491 System.exit(1);
492 }
493 }
494
495 /***
496 * Close the current TBS.
497 */
498 public static void closeMdb() {
499 IOUtils.closeQuietly(lastMdbStream);
500 lastMdbStream = null;
501 lastMdbFile = null;
502 }
503
504 /***
505 * Return the first available card's bytes offset.
506 *
507 * @return the first available card's bytes offset.
508 */
509 public static long getFirstCardsBytesOffset() {
510 return firstCardsBytesOffset;
511 }
512
513 /***
514 * Return full name of selected TBS.
515 *
516 * @return full name of selected TBS.
517 */
518 public static String getTbsFullName() {
519 return tbsFullName;
520 }
521
522 /***
523 * Return the current TBS disclaimer.
524 *
525 * @return the disclaimer.
526 */
527 public static String getDisclaimer() {
528 return disclaimer;
529 }
530
531 /***
532 * Return the current TBS more information text.
533 *
534 * @return the current TBS more information text.
535 */
536 public static String getMoreInfo() {
537 return moreInfo;
538 }
539
540 /***
541 * Return the current TBS comment.
542 *
543 * @return the current TBS comment.
544 */
545 public static String getAuthor() {
546 return author;
547 }
548
549 /***
550 * Return The current TBS version.
551 *
552 * @return The current TBS version.
553 */
554 public static String getVersion() {
555 return version;
556 }
557
558 /***
559 * Indicates where to find the art from a URL.
560 *
561 * @return the URL art.
562 */
563 public static String getArtURL() {
564 return artURL;
565 }
566
567 /***
568 * Return the last opened stream of the current MDB.
569 *
570 * @return the last opened stream of the current MDB.
571 */
572 public static FileInputStream getLastMdbStream() {
573 return lastMdbStream;
574 }
575
576 /***
577 * Set the current TBS name. Calling this method cause the mana symbols to be
578 * downloaded if it's not yet done.
579 *
580 * @param tbsName
581 * the TBS to define as current.
582 */
583 public static void setToolKitMdb(String tbsName) {
584 if (MToolKit.tbsName == null || !MToolKit.tbsName.equals(tbsName)) {
585 MToolKit.tbsName = tbsName;
586 MToolKit.mdbFile = IdConst.TBS_DIR + "/" + tbsName + "/" + tbsName
587 + ".mdb";
588 LanguageManagerMDB.setMdb(tbsName);
589 MToolKit.translator = null;
590 try {
591 loadHeader(MToolKit.mdbFile);
592 } catch (IOException e) {
593 Log.warn("the MDB file '" + MToolKit.mdbFile
594 + "' associated to the TBS '" + tbsName
595 + "' is not built correctly");
596 }
597 }
598 }
599
600 }