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.deckbuilder;
20  
21  import java.awt.Component;
22  import java.io.FileInputStream;
23  import java.io.FileNotFoundException;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Map;
29  
30  import javax.swing.JOptionPane;
31  
32  import net.sf.magicproject.clickable.targetable.card.MCard;
33  import net.sf.magicproject.clickable.targetable.player.Player;
34  import net.sf.magicproject.database.DatabaseCard;
35  import net.sf.magicproject.database.DatabaseFactory;
36  import net.sf.magicproject.network.ConnectionManager;
37  import net.sf.magicproject.network.MInputStream;
38  import net.sf.magicproject.network.NetworkActor;
39  import net.sf.magicproject.token.IdPositions;
40  import net.sf.magicproject.tools.Log;
41  import net.sf.magicproject.tools.MCardCompare;
42  import net.sf.magicproject.tools.MToolKit;
43  import net.sf.magicproject.ui.MListModel;
44  import net.sf.magicproject.ui.MagicUIComponents;
45  import net.sf.magicproject.ui.component.LoaderConsole;
46  import net.sf.magicproject.ui.i18n.LanguageManager;
47  import net.sf.magicproject.zone.MZone;
48  
49  /***
50   * @author <a href="mailto:fabdouglas@users.sourceforge.net">Fabrice Daugan </a>
51   * @since 0.90
52   */
53  public final class DeckReader {
54  
55  	/***
56  	 * Create a new instance of this class.
57  	 */
58  	private DeckReader() {
59  		// nothing to do
60  	}
61  
62  	private static final int DELIM_COMMA = 1;
63  
64  	private static final int DELIM_SPACE2 = 2;
65  
66  	/***
67  	 * Return the deck component corresponding to the given stream.
68  	 * 
69  	 * @param deckStream
70  	 *          the deck stream.
71  	 * @return the deck component corresponding to the given stream.
72  	 */
73  	public static Deck getDeck(MInputStream deckStream) {
74  		final Deck deck = new Deck("unknown");
75  		String line = null;
76  
77  		// list the referenced cards
78  		line = deckStream.readLine();
79  		while (line != null && !"%EOF%".equals(line)) {
80  			// is it a valid line?
81  			if (line.length() != 0 && !line.startsWith("#")) {
82  
83  				// To manage the "card_name;dd" format
84  				int index = line.indexOf("  ");
85  				int format = 0;
86  				if (index == -1) {
87  					// To manage the "dd card_name" format
88  					index = line.indexOf(";");
89  					format = DELIM_COMMA;
90  				} else {
91  					format = DELIM_SPACE2;
92  				}
93  				if (index != -1) {
94  					String croppedLine = (line + " ").substring(index + 1).trim();
95  					String cardName;
96  					int nextIndex = croppedLine.indexOf(";");
97  					int nb = 0;
98  					switch (format) {
99  					case DELIM_COMMA:
100 						cardName = line.substring(0, index).trim();
101 						if (nextIndex == -1) {
102 							nb = Integer.parseInt(croppedLine);
103 						} else {
104 							nb = Integer.parseInt(croppedLine.substring(0, nextIndex).trim());
105 						}
106 						break;
107 					case DELIM_SPACE2:
108 						nb = Integer.parseInt(line.substring(0, index).trim());
109 						if (nextIndex == -1) {
110 							cardName = croppedLine;
111 						} else {
112 							cardName = croppedLine.substring(0, nextIndex);
113 						}
114 						break;
115 					default:
116 						throw new InternalError("Unknown delimiter : '" + format + "'");
117 					}
118 					try {
119 						Map<String, String> properties = null;
120 						if (nextIndex != -1) {
121 							// constraints parsing
122 							properties = new HashMap<String, String>(5);
123 							String[] propertiesArray = croppedLine.substring(nextIndex + 1)
124 									.trim().split(";");
125 							for (String property : propertiesArray) {
126 								property = property.trim();
127 								if (propertiesArray.length > 0) {
128 									int indexOfEqual = property.indexOf("=");
129 									if (indexOfEqual != -1) {
130 										properties.put(property.substring(0, indexOfEqual),
131 												property.substring(indexOfEqual + 1));
132 									} else {
133 										JOptionPane.showMessageDialog(MagicUIComponents.magicForm,
134 												LanguageManager.getString("malformeddeck", line
135 														.substring(0, index)), LanguageManager
136 														.getString("error"), JOptionPane.ERROR_MESSAGE);
137 									}
138 								}
139 							}
140 						}
141 						deck.addCard(cardName, nb, properties);
142 					} catch (NumberFormatException e) {
143 						JOptionPane.showMessageDialog(MagicUIComponents.magicForm,
144 								LanguageManager.getString("malformeddeck", line.substring(0,
145 										index)), LanguageManager.getString("error"),
146 								JOptionPane.ERROR_MESSAGE);
147 					}
148 				}
149 			}
150 			line = deckStream.readLine();
151 		}
152 		return deck;
153 	}
154 
155 	/***
156 	 * Return the deck component corresponding to the given file.
157 	 * 
158 	 * @param parentComponent
159 	 *          determines the <code>Frame</code> in which the dialog is
160 	 *          displayed; if <code>null</code>, or if the
161 	 *          <code>parentComponent</code> has no <code>Frame</code>, a
162 	 *          default <code>Frame</code> is used
163 	 * @param deckFile
164 	 *          the deck file.
165 	 * @return the deck component corresponding to the given file.
166 	 * @throws FileNotFoundException
167 	 */
168 	public static Deck getDeck(Component parentComponent, String deckFile)
169 			throws FileNotFoundException {
170 		if (deckFile.length() == 0) {
171 			if (parentComponent != null) {
172 				JOptionPane.showMessageDialog(parentComponent, LanguageManager
173 						.getString("wiz_network.deck.missed"), LanguageManager
174 						.getString("error"), JOptionPane.WARNING_MESSAGE);
175 			}
176 			return null;
177 		}
178 		final String deckShortFile = MToolKit.getShortDeckFile(deckFile);
179 		final InputStream deckStream = MToolKit.getResourceAsStream(deckShortFile);
180 		if (deckStream == null) {
181 			JOptionPane.showMessageDialog(parentComponent, LanguageManager
182 					.getString("wiz_network.deck.notfound"), LanguageManager
183 					.getString("error"), JOptionPane.WARNING_MESSAGE);
184 			throw new RuntimeException("Could not open deck file '" + deckShortFile
185 					+ "'");
186 		}
187 		return getDeck(new MInputStream(new FileInputStream(deckShortFile), null));
188 	}
189 
190 	/***
191 	 * Fill player's zone with the cards found in InputFile
192 	 * 
193 	 * @param deck
194 	 *          the deck to add.
195 	 * @param dbFile
196 	 *          opened file read containing the available cards
197 	 * @param zone
198 	 *          the destination zone.
199 	 * @param owner
200 	 *          the player owning the created cards.
201 	 * @throws IOException
202 	 *           If some other I/O error occurs
203 	 */
204 	public static void fillZone(Deck deck, FileInputStream dbFile, MZone zone,
205 			Player owner) throws IOException {
206 		// while not EOF
207 		LoaderConsole
208 				.beginTask(
209 						LanguageManager.getString("wiz_network.validatingdeck"),
210 						((ConnectionManager.client == null && !owner.isYou()) || (ConnectionManager.client != null && owner
211 								.isYou())) ? 35 : 65);
212 		owner.setDeck(deck);
213 
214 		// Load cards rules
215 		LoaderConsole
216 				.beginTask(
217 						LanguageManager.getString("wiz_network.loadingcards"),
218 						((ConnectionManager.client == null && !owner.isYou()) || (ConnectionManager.client != null && owner
219 								.isYou())) ? 45 : 75);
220 		MCard lastLoadedCard = null;
221 		for (MCardCompare cardCompare : deck.getCards()) {
222 			final String realCardName = cardCompare.getName();
223 			final int nbCards = cardCompare.getAmount();
224 			Log.debug(cardCompare);
225 			MCard cardRef = null;
226 			if (lastLoadedCard != null
227 					&& realCardName.equals(lastLoadedCard.getName())) {
228 				DatabaseCard database = DatabaseFactory.getDatabase(null,
229 						lastLoadedCard.getCardModel(), cardCompare.getConstraints());
230 				cardRef = new MCard(lastLoadedCard, database);
231 			} else {
232 				dbFile.getChannel().position(cardCompare.getMdbOffset());
233 				cardRef = new MCard(realCardName, dbFile, owner, owner, cardCompare
234 						.getConstraints());
235 				lastLoadedCard = cardRef;
236 			}
237 			cardRef.moveCard(zone.getZoneId(), owner, false, IdPositions.ON_THE_TOP);
238 
239 			// clone the same card
240 			for (int a = nbCards; a-- > 1;) {
241 				new MCard(cardRef, cardRef.getDatabase()).moveCard(zone.getZoneId(),
242 						owner, false, IdPositions.ON_THE_TOP);
243 			}
244 		}
245 
246 	}
247 
248 	/***
249 	 * Read available cards from file and add them to the specified
250 	 * <code>cardNames</code>
251 	 * 
252 	 * @param cardNames
253 	 *          to this list method add card names
254 	 */
255 	public static void readAvailableCards(MListModel<MCardCompare> cardNames) {
256 		final FileInputStream dbStream = MdbLoader.resetMdb();
257 		try {
258 			cardNames.clear();
259 			while (dbStream.available() > 3) {
260 				// reads card name
261 				String cardName = MToolKit.readString(dbStream);
262 
263 				// reads card offset
264 				long offset = MToolKit.readInt24(dbStream);
265 
266 				cardNames.add(new MCardCompare(cardName, offset));
267 			}
268 		} catch (IOException ex2) {
269 			// Ignore this error
270 		}
271 	}
272 
273 	/***
274 	 * Validate a deck read from the given stream.
275 	 * 
276 	 * @param parentComponent
277 	 *          determines the <code>Frame</code> in which the dialog is
278 	 *          displayed; if <code>null</code>, or if the
279 	 *          <code>parentComponent</code> has no <code>Frame</code>, a
280 	 *          default <code>Frame</code> is used
281 	 * @param deck
282 	 * @param deckConstraint
283 	 *          the deck constraint name.
284 	 * @return <code>true</code> if the read deck is valid.
285 	 * @throws IOException
286 	 *           If some other I/O error occurs
287 	 */
288 	public static boolean validateDeck(Component parentComponent, Deck deck,
289 			String deckConstraint) throws IOException {
290 		if (deckConstraint == null) {
291 			return validateDeck(parentComponent, deck, (DeckConstraint) null);
292 		}
293 		return validateDeck(parentComponent, deck, DeckConstraints
294 				.getDeckConstraint(deckConstraint));
295 	}
296 
297 	/***
298 	 * Validate a deck read from the given stream.
299 	 * 
300 	 * @param parentComponent
301 	 *          determines the <code>Frame</code> in which the dialog is
302 	 *          displayed; if <code>null</code>, or if the
303 	 *          <code>parentComponent</code> has no <code>Frame</code>, a
304 	 *          default <code>Frame</code> is used
305 	 * @param deck
306 	 * @param deckConstraint
307 	 *          the deck constraint name.
308 	 * @return <code>true</code> if the read deck is valid.
309 	 * @throws IOException
310 	 *           If some other I/O error occurs
311 	 */
312 	public static boolean validateDeck(Component parentComponent, Deck deck,
313 			DeckConstraint deckConstraint) throws IOException {
314 		final List<String> errors = deck.validate(deckConstraint);
315 		if (!errors.isEmpty()) {
316 			NetworkActor.cancelling = true;
317 			JOptionPane.showMessageDialog(parentComponent, LanguageManager.getString(
318 					"wiz_network.deck.constraint.error", deckConstraint
319 							.getConstraintLocalName())
320 					+ " :\n" + errors.toString(), LanguageManager
321 					.getString("wiz_network.deck.constraint.error.title"),
322 					JOptionPane.ERROR_MESSAGE);
323 			return false;
324 		}
325 		return true;
326 	}
327 }