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   */
20  package net.sf.magicproject.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.magicproject.action.ActionFactory;
31  import net.sf.magicproject.clickable.ability.AbilityFactory;
32  import net.sf.magicproject.clickable.targetable.card.CardFactory;
33  import net.sf.magicproject.clickable.targetable.card.Damage;
34  import net.sf.magicproject.database.DatabaseFactory;
35  import net.sf.magicproject.modifier.ObjectFactory;
36  import net.sf.magicproject.stack.EventManager;
37  import net.sf.magicproject.stack.MPhase;
38  import net.sf.magicproject.stack.StackManager;
39  import net.sf.magicproject.test.TestFactory;
40  import net.sf.magicproject.token.IdCommonToken;
41  import net.sf.magicproject.tools.MToolKit;
42  import net.sf.magicproject.ui.MagicUIComponents;
43  import net.sf.magicproject.ui.i18n.LanguageManager;
44  import net.sf.magicproject.xml.XmlConfiguration;
45  import net.sf.magicproject.zone.Play;
46  import net.sf.magicproject.zone.ZoneManager;
47  
48  import org.apache.commons.io.IOUtils;
49  
50  /***
51   * Set of tools to manipulate the MDB format : load headers, finding cards,...
52   * 
53   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
54   * @since 0.54
55   */
56  public final class MdbLoader {
57  
58  	/***
59  	 * The first available card's name offset.
60  	 */
61  	private static int firstCardsNamesOffset;
62  
63  	/***
64  	 * The first available card's bytes offset.
65  	 */
66  	private static long firstCardsBytesOffset;
67  
68  	/***
69  	 * Create a new instance of this class.
70  	 */
71  	private MdbLoader() {
72  		super();
73  	}
74  
75  	/***
76  	 * Load author, tbs name,... Load the rules of this mdb and set them to the MP
77  	 * environment, set the current offset to the beginning of card section. <br>
78  	 * 
79  	 * @param dbFile
80  	 *          the mdb file containing rules.
81  	 * @param firstPlayer
82  	 *          the index of first player.
83  	 * @return the stream as is, the current offset correponds to the beginning of
84  	 *         cards section.
85  	 * @throws IOException
86  	 *           If some other I/O error occurs
87  	 */
88  	public static FileInputStream loadMDB(String dbFile, int firstPlayer)
89  			throws IOException {
90  		FileInputStream dbStream = loadHeader(dbFile);
91  
92  		// load the registers and place where aborted spells would be placed
93  		StackManager.getInstance().init(dbStream, firstPlayer);
94  
95  		// load phases, turn structure, system rules and static-modifiers
96  		EventManager.init(dbStream, dbFile);
97  
98  		// init task pane layout
99  		MagicUIComponents.databasePanel.init(dbStream);
100 
101 		// read zone layouts of Play
102 		Play.initSectorConfigurations(dbStream);
103 
104 		// Skip card's code.
105 		resetMdb();
106 
107 		/*
108 		 * Return the stream skipping card's code. The current offset correponds to
109 		 * the beginning of cards references.
110 		 */
111 		return dbStream;
112 	}
113 
114 	/***
115 	 * Reset the given MDB stream to the first offset of card references.
116 	 * 
117 	 * @return the stream.
118 	 */
119 	public static FileInputStream resetMdb() {
120 		try {
121 			if (lastMdbStream == null) {
122 				openMdb(MToolKit.mdbFile, false);
123 			}
124 			lastMdbStream.getChannel().position(firstCardsNamesOffset);
125 		} catch (IOException io) {
126 			throw new RuntimeException(io);
127 		}
128 		return lastMdbStream;
129 	}
130 
131 	/***
132 	 * Check the given MDB file and update it if needed. Then open it and return
133 	 * the created stream.
134 	 * 
135 	 * @param dbStream
136 	 *          the mdb file containing rules.
137 	 * @param forceRecheck
138 	 *          if true, all files are checked even if it has already been done.
139 	 * @return return the opened stream as is when file is opened.
140 	 * @throws IOException
141 	 *           If some other I/O error occurs
142 	 */
143 	public static FileInputStream openMdb(String dbStream, boolean forceRecheck)
144 			throws IOException {
145 		// Reset the opened stream
146 		if (lastMdbStream != null && !forceRecheck) {
147 			try {
148 				lastMdbStream.getChannel().position(0);
149 				return lastMdbStream;
150 			} catch (IOException io) {
151 				// Ignore this error
152 			}
153 		}
154 
155 		// Cloase the old stream
156 		if (!forceRecheck) {
157 			IOUtils.closeQuietly(lastMdbStream);
158 		}
159 
160 		// Check the MDB last modified date againts the XML files
161 		final File file = MToolKit.getFile(dbStream);
162 		if (!instanceIsChecked || forceRecheck) {
163 			final long lastModifiedMdb = file == null ? 0 : file.lastModified();
164 			XmlConfiguration.main("-update", MToolKit.tbsName, String
165 					.valueOf(lastModifiedMdb));
166 			if (XmlConfiguration.error == 0)
167 				instanceIsChecked = true;
168 		}
169 		if (file == null) {
170 			lastMdbStream = new FileInputStream(MToolKit.getFile(dbStream));
171 		} else {
172 			lastMdbStream = new FileInputStream(file);
173 		}
174 		return lastMdbStream;
175 	}
176 
177 	/***
178 	 * Load author, tbs name,... Load the rules of this mdb and set them to the MP
179 	 * environment, set the current offset to the begin of card section and return
180 	 * it's position Load settings associated to this mdb. <br>
181 	 * 
182 	 * @param dbFile
183 	 *          the mdb file containing rules.
184 	 * @return return the opened stream as is, the current offset correponds to
185 	 *         the last byte read of the disclaimer/licence section.
186 	 * @throws IOException
187 	 *           If some other I/O error occurs
188 	 */
189 	public static FileInputStream loadHeader(String dbFile) throws IOException {
190 		if (dbFile.equals(lastMdbFile)) {
191 			lastMdbStream.getChannel().position(endOfHeaderOffset);
192 			return lastMdbStream;
193 		}
194 		closeMdb();
195 		final FileInputStream dbStream = openMdb(dbFile, false);
196 		tbsFullName = MToolKit.readString(dbStream);
197 		version = MToolKit.readString(dbStream);
198 		author = MToolKit.readString(dbStream);
199 		moreInfo = MToolKit.readString(dbStream);
200 
201 		// the database references
202 		DatabaseFactory.init(dbStream);
203 
204 		artURL = MToolKit.readString(dbStream);
205 		backPicture = MToolKit.readString(dbStream);
206 		damagePicture = MToolKit.readString(dbStream);
207 		disclaimer = MToolKit.readText(dbStream);
208 
209 		// colored mana section
210 		coloredManaSmlURL = MToolKit.readString(dbStream);
211 		coloredManaBigURL = MToolKit.readString(dbStream);
212 		coloredBigManas = new String[IdCommonToken.COLOR_NAMES.length];
213 		coloredSmlManas = new String[IdCommonToken.COLOR_NAMES.length];
214 		coloredSmlManasHtml = new String[coloredBigManas.length];
215 		for (int i = IdCommonToken.COLOR_NAMES.length; i-- > 1;) {
216 			int index = dbStream.read();
217 			coloredSmlManas[index] = MToolKit.readString(dbStream);
218 			coloredBigManas[index] = MToolKit.readString(dbStream);
219 			coloredSmlManasHtml[index] = "<img src='file:///"
220 					+ MToolKit.getTbsHtmlPicture("mana/colored/small/"
221 							+ coloredSmlManas[index]) + "'>&nbsp;";
222 		}
223 
224 		// colorless mana section
225 		colorlessURL = MToolKit.readString(dbStream);
226 		colorlessBigURL = MToolKit.readString(dbStream);
227 		unknownSmlMana = MToolKit.readString(dbStream);
228 		unknownSmlManaHtml = "<img src='file:///"
229 				+ MToolKit.getTbsHtmlPicture("mana/colorless/small/" + unknownSmlMana)
230 				+ "'>&nbsp;";
231 		colorlessSmlManas = new String[dbStream.read()];
232 		colorlessSmlManasHtml = new String[colorlessSmlManas.length];
233 		for (int i = colorlessSmlManas.length; i-- > 0;) {
234 			int index = dbStream.read();
235 			colorlessSmlManas[index] = MToolKit.readString(dbStream);
236 			colorlessSmlManasHtml[index] = "<img src='file:///"
237 					+ MToolKit.getTbsHtmlPicture("mana/colorless/small/"
238 							+ colorlessSmlManas[index]) + "'>&nbsp;";
239 		}
240 
241 		// Read the card bytes position
242 		firstCardsBytesOffset = MToolKit.readInt24(dbStream);
243 
244 		// the deck constraints
245 		DeckConstraints.init(dbStream);
246 
247 		// read additional zone
248 		ZoneManager.initTbs(dbStream);
249 
250 		// the tests references
251 		TestFactory.init(dbStream);
252 
253 		// the action constraints and picture
254 		ActionFactory.init(dbStream);
255 
256 		// the objects
257 		ObjectFactory.init(dbStream);
258 
259 		// the abilities references
260 		AbilityFactory.init(dbStream);
261 
262 		// read damage type name exportation
263 		Damage.init(dbStream);
264 
265 		// load state pictures of card,tooltip filters, exported types
266 		CardFactory.init(dbStream);
267 
268 		// Read the card names position
269 		endOfHeaderOffset = dbStream.getChannel().position();
270 		dbStream.getChannel().position(firstCardsBytesOffset);
271 		firstCardsNamesOffset = MToolKit.readInt24(dbStream);
272 		dbStream.getChannel().position(endOfHeaderOffset);
273 
274 		lastMdbFile = dbFile;
275 		return dbStream;
276 	}
277 
278 	/***
279 	 * Save the settings corresponding to the current TBS
280 	 */
281 	public static void saveTBSSettings() {
282 		if (MToolKit.mdbFile != null) {
283 			saveTBSSettings(MToolKit.mdbFile.replace(".mdb", ".pref"));
284 		}
285 	}
286 
287 	/***
288 	 * Save the settings corresponding to the current TBS
289 	 * 
290 	 * @param settingFile
291 	 *          the setting file where settings would be saved
292 	 */
293 	private static void saveTBSSettings(String settingFile) {
294 		// save phases options
295 		if (EventManager.turnStructure == null) {
296 			// not mdb file loaded
297 			return;
298 		}
299 		try {
300 			FileOutputStream out = new FileOutputStream(MToolKit.getFile(settingFile));
301 			for (int i = 0; i < EventManager.turnStructure.length; i++) {
302 				MPhase.phases[0][i].saveSettings(out);
303 			}
304 			for (int i = 0; i < EventManager.turnStructure.length; i++) {
305 				MPhase.phases[1][i].saveSettings(out);
306 			}
307 			IOUtils.closeQuietly(out);
308 		} catch (java.io.IOException e) {
309 			JOptionPane.showMessageDialog(MagicUIComponents.magicForm,
310 					LanguageManager.getString("loadtbssettingspb") + " : "
311 							+ e.getMessage(), LanguageManager.getString("error"),
312 					JOptionPane.ERROR_MESSAGE);
313 			System.exit(-1);
314 		}
315 	}
316 
317 	/***
318 	 * Loading the settings corresponding to the current TBS
319 	 */
320 	public static void loadTBSSettings() {
321 		loadTBSSettings(MToolKit.mdbFile.substring(0, MToolKit.mdbFile
322 				.lastIndexOf('.'))
323 				+ ".pref");
324 	}
325 
326 	/***
327 	 * Loading the settings corresponding to the specified TBS
328 	 * 
329 	 * @param settingFile
330 	 *          the setting file where settings have been saved
331 	 */
332 	private static void loadTBSSettings(String settingFile) {
333 		// load phases options
334 		if (MToolKit.tbsName == null) {
335 			// no mdb file loaded
336 			return;
337 		}
338 		try {
339 			InputStream in = MToolKit.getResourceAsStream(settingFile);
340 			for (int i = 0; i < EventManager.turnStructure.length; i++) {
341 				MPhase.phases[0][i].loadSettings(in);
342 			}
343 			for (int i = 0; i < EventManager.turnStructure.length; i++) {
344 				MPhase.phases[1][i].loadSettings(in);
345 			}
346 			IOUtils.closeQuietly(in);
347 		} catch (IOException e) {
348 			JOptionPane.showMessageDialog(MagicUIComponents.magicForm,
349 					LanguageManager.getString("loadtbssettingspb") + " : "
350 							+ e.getMessage(), LanguageManager.getString("error"),
351 					JOptionPane.ERROR_MESSAGE);
352 			System.exit(-1);
353 		}
354 	}
355 
356 	/***
357 	 * The current full name of selected TBS
358 	 */
359 	public static String tbsFullName = null;
360 
361 	/***
362 	 * The current TBS disclaimer
363 	 */
364 	public static String disclaimer = null;
365 
366 	/***
367 	 * The current TBS more information text
368 	 */
369 	public static String moreInfo = null;
370 
371 	/***
372 	 * The current TBS comment
373 	 */
374 	public static String author = null;
375 
376 	/***
377 	 * The ciurrent TBS version
378 	 */
379 	public static String version = null;
380 
381 	/***
382 	 * Indicates where to find the art from a URL
383 	 */
384 	public static String artURL = null;
385 
386 	/***
387 	 * Indicates the picture name of the back picture.
388 	 */
389 	public static String backPicture = null;
390 
391 	/***
392 	 * Indicates the picture name of the damage picture.
393 	 */
394 	public static String damagePicture = null;
395 
396 	/***
397 	 * This is the defined colorless mana file names without basename. The base
398 	 * web basename is <code>colorlessURL</code> and the local basename is
399 	 * <code>tbs/TBS_NAME/images/mana/colorless/</code>
400 	 * 
401 	 * @see #colorlessSmlManas
402 	 */
403 	public static String[] colorlessSmlManas;
404 
405 	/***
406 	 * This the HTML representation of defined small colorless manas.
407 	 * 
408 	 * @see #colorlessSmlManas
409 	 */
410 	public static String[] colorlessSmlManasHtml;
411 
412 	/***
413 	 * This is the filename without basename corresponding to the big colorless
414 	 * picture. The base web basename is <code>colorlessURL</code> and the local
415 	 * basename is <code>tbs/TBS_NAME/images/mana/colorless/big/</code>
416 	 */
417 	public static String colorlessBigURL;
418 
419 	/***
420 	 * This is the defined small colorled mana file names without basename. The
421 	 * base web basename is <code>coloredManaSmlURL</code> and the local
422 	 * basename is <code>tbs/TBS_NAME/images/mana/colored/small/</code>
423 	 * 
424 	 * @see #coloredManaSmlURL
425 	 */
426 	public static String[] coloredSmlManas;
427 
428 	/***
429 	 * This the HTML representation of defined small colorled manas.
430 	 * 
431 	 * @see #colorlessSmlManas
432 	 */
433 	public static String[] coloredSmlManasHtml;
434 
435 	/***
436 	 * This is the defined small colorled mana file names without basename. The
437 	 * base web basename is <code>coloredManaBigURL</code> and the local
438 	 * basename is <code>tbs/TBS_NAME/images/mana/colored/big/</code>
439 	 * 
440 	 * @see #coloredManaBigURL
441 	 */
442 	public static String[] coloredBigManas;
443 
444 	/***
445 	 * This is the web basename where colorless mana pictures can be found.
446 	 */
447 	public static String colorlessURL;
448 
449 	/***
450 	 * This is the web basename where small colorled mana pictures can be found.
451 	 */
452 	public static String coloredManaSmlURL;
453 
454 	/***
455 	 * This is the web basename where big colorled mana pictures can be found.
456 	 */
457 	public static String coloredManaBigURL;
458 
459 	/***
460 	 * The picture used for unknown mana cost value.
461 	 */
462 	public static String unknownSmlManaHtml;
463 
464 	/***
465 	 * The picture used for unknown mana cost value.
466 	 */
467 	public static String unknownSmlMana;
468 
469 	/***
470 	 * The offset position of end of header.
471 	 */
472 	private static long endOfHeaderOffset;
473 
474 	/***
475 	 * The last loaded Mdb File. Is <code>null</code> while no Mdb has been
476 	 * loaded..
477 	 */
478 	private static String lastMdbFile;
479 
480 	/***
481 	 * Flag indicating if the XML file have benn checked or not for this instance.
482 	 */
483 	private static boolean instanceIsChecked = false;
484 
485 	/***
486 	 * The last opened stream of the current MDB.
487 	 */
488 	public static FileInputStream lastMdbStream;
489 
490 	/***
491 	 * Close the current TBS.
492 	 */
493 	public static void closeMdb() {
494 		IOUtils.closeQuietly(lastMdbStream);
495 		lastMdbStream = null;
496 		lastMdbFile = null;
497 	}
498 
499 }