1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.cb.jset.client.model;
21
22 import org.apache.log4j.Logger;
23 import org.cb.jset.JSetCard;
24 import org.cb.jset.CardProperties;
25 import org.cb.jset.CardSet;
26 import org.cb.jset.BoardException;
27 import org.cb.cardboard.AbstractCardBoardModel;
28 import org.cb.cardboard.Card;
29 import org.cb.cardboard.CardBoardEvent;
30
31 import java.util.Collections;
32 import java.util.List;
33 import java.util.ArrayList;
34 import java.io.Serializable;
35
36
37 /***
38 * A client BoardImpl is a special board that also keeps track of card layout, especially the empty spaces.
39 *
40 *
41 * Note: implementation not yet multithread safe (FIXME)
42 * @author jerome@coffeebreaks.org - last modified by $LastChangedBy: jerome $
43 * @version $Id: JSetClientBoardModel.java 129 2004-04-15 05:00:43Z jerome $
44 */
45 public class JSetClientBoardModel extends AbstractCardBoardModel implements SetGameClientBoard, Serializable
46 {
47 private transient final Logger _logger = Logger.getLogger(JSetClientBoardModel.class);
48
49 /*** A List of JSetCard elements representing the cards on the board. */
50 private final List _cards = new ArrayList();
51
52 /***
53 * Clear the board.
54 */
55 public void clear()
56 {
57 int size = _cards.size();
58 _cards.clear();
59
60 fireIntervalRemoved(0, size - 1);
61 }
62
63 /***
64 * @return the number of spaces used by cards on the board. Unused spaces are taken into account.
65 * @see #getNbCards() for the exact number of cards on the board.
66 */
67 public int getSize()
68 {
69 return _cards.size();
70 }
71
72 /***
73 * Return the Card element specified by the index on the board.
74 * @param index
75 * @return the Card element or <code>null</code> if the space on the board is empty at that position.
76 */
77 public Card getElementAt(final int index)
78 {
79 return (Card) _cards.get(index);
80 }
81
82 /***
83 * @return The cards in the board. May contain some <code>null</code> to represent the empty spaces.
84 */
85 public List getElements()
86 {
87 return Collections.unmodifiableList(_cards);
88 }
89
90 /***
91 * @return the number of cards on the board.
92 * @see #getSize() which takes into account the number of cards plus the empty spaces.
93 */
94 public int getNbCards()
95 {
96 int lNbCards = 0;
97 for (int i = 0; i < _cards.size(); i++)
98 {
99 final Card card = (Card) _cards.get(i);
100 if (card != null)
101 {
102 lNbCards++;
103 }
104 }
105 return lNbCards;
106 }
107
108 /***
109 * Add the specified cards onto the board.
110 * @param cards the cards to add.
111 * @throws NullPointerException if <code>cards</code> is <code>null</code> or if an element in the array is <code>null</code>.
112 */
113 public void addCards(final CardProperties[] cards)
114 {
115 logCards("before adding: " + CardProperties.toString(cards));
116
117 int indexOfCardsToAdd = 0;
118 int indexInCardsList = 0;
119
120
121 final List indexesOfCardsChanged = new ArrayList();
122 cardsToAdd:
123
124 for (; indexInCardsList < _cards.size() && indexOfCardsToAdd < cards.length; indexInCardsList++)
125 {
126 final JSetCard oldCard = (JSetCard) _cards.get(indexInCardsList);
127 if (oldCard == null)
128 {
129 final CardProperties cardProperties = cards[indexOfCardsToAdd++];
130 final Card newCard = new org.cb.jset.JSetCard(cardProperties);
131 _cards.set(indexInCardsList, newCard);
132 indexesOfCardsChanged.add(new Integer(indexInCardsList));
133 continue cardsToAdd;
134 }
135 }
136 if (indexesOfCardsChanged.size() > 0)
137 {
138 fireContentsChanged(indexesOfCardsChanged);
139 }
140 if (indexOfCardsToAdd < cards.length)
141 {
142 final int firstListIndex = indexInCardsList;
143 int lastListIndex = 0;
144 for (; indexOfCardsToAdd < cards.length; indexOfCardsToAdd++)
145 {
146 final CardProperties cardProperties = cards[indexOfCardsToAdd];
147 final Card card = new org.cb.jset.JSetCard(cardProperties);
148 _cards.add(indexInCardsList++, card);
149 lastListIndex = indexInCardsList;
150 }
151 fireIntervalAdded(firstListIndex, (lastListIndex - 1));
152 }
153 logCards("after adding: " + CardProperties.toString(cards));
154 }
155
156 /***
157 * Remove the specified matching set from the board.
158 * @param set the set to remove
159 * @throws BoardException when something fails
160 */
161 public void removeSet(final CardSet set) throws BoardException
162 {
163 logCards("before matching: " + CardProperties.toString(set.getCards()));
164 final CardProperties[] cards = set.getCards();
165
166 final int[] indexesOnBoard = new int[cards.length];
167 for (int i = 0; i < indexesOnBoard.length; i++)
168 {
169 final int index = _cards.indexOf(new org.cb.jset.JSetCard(CardProperties.findCard(cards[i])));
170 if (index == -1)
171 {
172 _logger.debug("JSetCard " + cards[i] + " not found. Listing contents of board...");
173 logCards("");
174 throw new BoardException("JSetCard " + cards[i] + " not found.");
175 }
176 indexesOnBoard[i] = index;
177 }
178
179 for (int i = 0; i < indexesOnBoard.length; i++)
180 {
181 final int lIndex = indexesOnBoard[i];
182 _cards.set(lIndex, null);
183 fireIntervalRemoved(lIndex, lIndex);
184 }
185 logCards("after matching: " + CardProperties.toString(set.getCards()));
186 }
187
188 private void logCards(final String message)
189 {
190 _logger.debug("Logging cards: " + message);
191 for (int j = 0; j < _cards.size(); j++)
192 {
193 final org.cb.jset.JSetCard card = (org.cb.jset.JSetCard) _cards.get(j);
194 _logger.debug("[" + j + "]:" + card);
195 }
196 }
197
198 private void fireContentsChanged(final List indexes)
199 {
200 final CardBoardEvent event = new CardBoardEvent(this, indexes);
201 fireContentsChanged(event);
202 }
203
204 private void fireIntervalAdded(final int firstIndex, final int lastIndex)
205 {
206 final CardBoardEvent event = new CardBoardEvent(this, CardBoardEvent.INTERVAL_ADDED, firstIndex, lastIndex);
207 fireIntervalAdded(event);
208 }
209
210 private void fireIntervalRemoved(final int firstIndex, final int lastIndex)
211 {
212 final CardBoardEvent event = new CardBoardEvent(this, CardBoardEvent.INTERVAL_REMOVED, firstIndex, lastIndex);
213 fireIntervalRemoved(event);
214 }
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230 }