View Javadoc

1   /* 
2    *   Firemox 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   */
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 		// load the registers and place where aborted spells would be placed
230 		StackManager.getInstance().init(dbStream, firstPlayer);
231 
232 		// load phases, turn structure, system rules and static-modifiers
233 		EventManager.init(dbStream, dbFile);
234 
235 		// initialize task pane layout
236 		if (MagicUIComponents.isUILoaded()) {
237 			MagicUIComponents.databasePanel.init(dbStream);
238 		}
239 
240 		// read zone layouts of Play
241 		if (MagicUIComponents.isUILoaded()) {
242 			Play.initSectorConfigurations(dbStream);
243 		}
244 
245 		// Skip card's code.
246 		resetMdb();
247 
248 		/*
249 		 * Return the stream skipping card's code. The current offset corresponds to
250 		 * the beginning of cards references.
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 		// Reset the opened stream
287 		if (lastMdbStream != null && !forceRecheck) {
288 			try {
289 				lastMdbStream.getChannel().position(0);
290 				return lastMdbStream;
291 			} catch (IOException io) {
292 				// Ignore this error
293 			}
294 		}
295 
296 		// Clase the old stream
297 		if (!forceRecheck) {
298 			IOUtils.closeQuietly(lastMdbStream);
299 		}
300 
301 		// Check the MDB last modified date against the XML files
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 		// the database references
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 		// colored mana section
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]) + "'>&nbsp;";
361 		}
362 
363 		// colorless mana section
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 				+ "'>&nbsp;";
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]) + "'>&nbsp;";
378 		}
379 
380 		// Read the card bytes position
381 		firstCardsBytesOffset = MToolKit.readInt24(dbStream);
382 
383 		// the deck constraints
384 		DeckConstraints.init(dbStream);
385 
386 		// read additional zone
387 		ZoneManager.initTbs(dbStream);
388 
389 		// the tests references
390 		TestFactory.init(dbStream);
391 
392 		// the action constraints and picture
393 		ActionFactory.init(dbStream);
394 
395 		// the objects
396 		ObjectFactory.init(dbStream);
397 
398 		// the abilities references
399 		AbilityFactory.init(dbStream);
400 
401 		// read damage type name export
402 		Damage.init(dbStream);
403 
404 		// load state pictures of card,tooltip filters, exported types
405 		CardFactory.init(dbStream);
406 
407 		// Read the card names position
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 		// save phases options
434 		if (EventManager.turnStructure == null) {
435 			// not MDB file loaded
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 		// load phases options
473 		if (MToolKit.tbsName == null) {
474 			// no MDB file loaded
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 }