1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package aigames.soccer.observer;
21
22 import aigames.soccer.InvalidMoveException;
23 import aigames.soccer.Move;
24
25 import aigames.soccer.field.BasicGameField;
26 import aigames.soccer.field.FieldPoint;
27 import aigames.soccer.field.GameField;
28 import aigames.soccer.field.constructor.Constructor;
29 import aigames.soccer.field.constructor.StandardConstructor;
30
31 import foxtrot.Task;
32 import foxtrot.Worker;
33
34 import org.apache.log4j.BasicConfigurator;
35 import org.apache.log4j.Level;
36 import org.apache.log4j.LogManager;
37 import org.apache.log4j.Logger;
38
39 import org.dom4j.Document;
40 import org.dom4j.Element;
41 import org.dom4j.Node;
42
43 import java.awt.Color;
44 import java.awt.Dimension;
45 import java.awt.Graphics;
46 import java.awt.Image;
47 import java.awt.Insets;
48 import java.awt.Point;
49
50 import java.text.DateFormat;
51 import java.text.ParseException;
52 import java.text.SimpleDateFormat;
53
54 import java.util.Date;
55 import java.util.Iterator;
56 import java.util.List;
57 import java.util.Vector;
58
59 import javax.swing.Box;
60 import javax.swing.BoxLayout;
61 import javax.swing.JFrame;
62
63
64 /***
65 * The observer main class.
66 * @version $Id: Observer.java,v 1.15 2004/05/08 21:55:28 mwerla Exp $
67 */
68 public class Observer extends JFrame {
69 private static Logger logger = Logger.getLogger(Observer.class);
70 private static Color bgColor = new Color(0, 204, 0);
71 private Communication comm = new Communication();
72 private Thread commThread = null;
73 private GameField field;
74 private int scale;
75 private int[] translate = new int[2];
76 private int turn;
77 private String player1Name;
78 private String player2Name;
79 private Date player1Time;
80 private Date player2Time;
81 private DateFormat df = new SimpleDateFormat("HH:mm:ss");
82 private javax.swing.JPanel jContentPane = null;
83 private javax.swing.JPanel leftPanel = null;
84 private FieldPanel fieldPanel = null;
85 private aigames.soccer.observer.PlayerPanel player1Panel = null;
86 private aigames.soccer.observer.PlayerPanel player2Panel = null;
87 private aigames.soccer.observer.OptionsPane optionsPane = null;
88
89 /***
90 * This is the default constructor.
91 */
92 public Observer() {
93 super();
94 initialize();
95 comm.setObserver(this);
96 }
97
98 /***
99 * The observer main function.
100 * @param args
101 */
102 public static void main(String[] args) {
103 BasicConfigurator.configure();
104 LogManager.getRootLogger().setLevel(Level.INFO);
105
106 Observer frame = new Observer();
107 }
108
109 /***
110 * This method initializes this.
111 */
112 private void initialize() {
113 this.setSize(750, 400);
114 this.setContentPane(getJContentPane());
115 this.setTitle("Soccer Observer");
116 this.setVisible(true);
117 this.addWindowListener(new java.awt.event.WindowAdapter() {
118 public void windowClosing(java.awt.event.WindowEvent e) {
119 System.exit(0);
120 }
121 });
122 }
123
124 /***
125 * This method initializes jContentPane.
126 * @return javax.swing.JPanel
127 */
128 private javax.swing.JPanel getJContentPane() {
129 if (jContentPane == null) {
130 jContentPane = new javax.swing.JPanel();
131 jContentPane.setLayout(new java.awt.BorderLayout());
132 jContentPane.add(getLeftPanel(), java.awt.BorderLayout.WEST);
133 jContentPane.add(getFieldPanel(), java.awt.BorderLayout.CENTER);
134 }
135
136 return jContentPane;
137 }
138
139 /***
140 * This method initializes jPanel.
141 * @return javax.swing.JPanel
142 */
143 private javax.swing.JPanel getLeftPanel() {
144 if (leftPanel == null) {
145 leftPanel = new javax.swing.JPanel();
146 leftPanel.setLayout(new BoxLayout(leftPanel, BoxLayout.PAGE_AXIS));
147 leftPanel.add(getPlayer1Panel(), null);
148 leftPanel.add(Box.createRigidArea(new Dimension(0, 2)));
149 leftPanel.add(getPlayer2Panel(), null);
150 leftPanel.add(Box.createVerticalGlue());
151 leftPanel.add(getOptionsPane(), null);
152 leftPanel.setBackground(bgColor);
153 }
154
155 return leftPanel;
156 }
157
158 /***
159 * This method initializes player1Panel.
160 * @return aigames.soccer.observer.PlayerPanel
161 */
162 private aigames.soccer.observer.PlayerPanel getPlayer1Panel() {
163 if (player1Panel == null) {
164 player1Panel = new aigames.soccer.observer.PlayerPanel();
165 }
166
167 return player1Panel;
168 }
169
170 /***
171 * This method initializes player2Panel.
172 * @return aigames.soccer.observer.PlayerPanel
173 */
174 private aigames.soccer.observer.PlayerPanel getPlayer2Panel() {
175 if (player2Panel == null) {
176 player2Panel = new aigames.soccer.observer.PlayerPanel();
177 }
178
179 return player2Panel;
180 }
181
182 /***
183 * This method initializes optionsPane.
184 * @return aigames.soccer.observer.OptionsPane
185 */
186 private aigames.soccer.observer.OptionsPane getOptionsPane() {
187 if (optionsPane == null) {
188 optionsPane = new aigames.soccer.observer.OptionsPane();
189 optionsPane.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
190 public void propertyChange(java.beans.PropertyChangeEvent e) {
191 if (e.getPropertyName().equals("connected")) {
192 connect(e.getNewValue());
193 } else if (e.getPropertyName().equals("selected")) {
194 selectGame();
195 }
196 }
197 });
198 }
199
200 return optionsPane;
201 }
202
203 /***
204 * This method initializes fieldPanel.
205 * @return javax.swing.JPanel
206 */
207 private javax.swing.JPanel getFieldPanel() {
208 if (fieldPanel == null) {
209 fieldPanel = new FieldPanel();
210
211 Dimension size = fieldPanel.getPreferredSize();
212 size.width += 20;
213 fieldPanel.setMaximumSize(size);
214 fieldPanel.setBackground(bgColor);
215 }
216
217 return fieldPanel;
218 }
219
220 /***
221 * Connection/disconnection event handler.
222 * @param value True for connection, false for disconnection.
223 */
224 private void connect(Object value) {
225 if (value.toString().equals("true")) {
226
227 String[] gamesList = null;
228
229 try {
230 gamesList = (String[]) Worker.post(new Task() {
231 public Object run() throws Exception {
232 comm.connect(optionsPane.getIp(),
233 optionsPane.getPort());
234 comm.sayHello("JavaObserver");
235
236 return comm.getGamesList();
237 }
238 });
239 } catch (Exception e) {
240
241 optionsPane.setConnected(false);
242
243 return;
244 }
245
246 optionsPane.setGamesList(gamesList);
247 optionsPane.setConnected(true);
248 } else {
249 comm.shutdown();
250
251 if (null != commThread) {
252 try {
253 commThread.interrupt();
254
255 while (commThread.isAlive()) {
256 Thread.sleep(100);
257 }
258 } catch (InterruptedException e) {
259
260
261 }
262 }
263
264 commThread = null;
265
266 try {
267 comm.disconnect();
268 optionsPane.setConnected(false);
269 } catch (Exception e) {
270
271 }
272 }
273 }
274
275 private void selectGame() {
276
277 optionsPane.setSelected(true);
278 player1Time = null;
279 player1Panel.setPlayerName("PlayerName");
280 player1Panel.setMovesAverage(0);
281 player1Panel.setMovesTotal(0);
282 player1Panel.setTime("00:00:00");
283 player2Panel.setPlayerName("PlayerName");
284 player2Time = null;
285 player2Panel.setMovesAverage(0);
286 player2Panel.setMovesTotal(0);
287 player2Panel.setTime("00:00:00");
288 commThread = new Thread(comm);
289 commThread.start();
290 }
291
292 /***
293 * Process a message and updates the field.
294 * @param doc dom4j Document
295 */
296 public void processMessage(Document doc) {
297 int playersCount = 0;
298 String type = doc.valueOf("//message/@type");
299
300 if (type.equals("log")) {
301 Element root = doc.getRootElement();
302
303 for (Iterator i = root.elementIterator(); i.hasNext();) {
304 Element element = (Element) i.next();
305 String name = element.getName();
306
307 if ("name".equals(name)) {
308 String player = element.getText();
309
310 if (1 == ++playersCount) {
311 player1Panel.setPlayerName(player);
312 player1Name = player;
313 } else {
314 player2Panel.setPlayerName(player);
315 player2Name = player;
316 }
317 } else if ("map".equals(name)) {
318 int width = Integer.parseInt(element.attributeValue("width"));
319 int height = Integer.parseInt(element.attributeValue(
320 "height"));
321 int goal = Integer.parseInt(element.attributeValue("goal"));
322
323 Constructor fieldConstructor = null;
324
325 try {
326 fieldConstructor = new StandardConstructor(width,
327 height, goal);
328 } catch (IllegalArgumentException e) {
329 logger.error("configuration: " + e.getMessage());
330 }
331
332 field = new BasicGameField(fieldConstructor);
333 field.startGame();
334 } else if ("begin".equals(name)) {
335 String firstPlayer = element.getText();
336 turn = 1;
337
338 if (firstPlayer.equals(player2Name)) {
339 turn = 2;
340 }
341 } else if ("move".equals(name)) {
342 try {
343 setTime(element.attributeValue("time"));
344 } catch (ParseException e) {
345 logger.error("time parsing: " + e.getMessage());
346 }
347
348 markMove(element);
349 } else if ("error".equals(name)) {
350
351 } else if ("winner".equals(name)) {
352 String winner = element.getText();
353
354
355 connect("false");
356 }
357 }
358
359 drawField();
360 } else {
361 logger.error("Incorrect message type: " + type);
362 }
363 }
364
365 private void setTime(String time) throws ParseException {
366 if (1 == turn) {
367 if (null == player1Time) {
368 player1Time = df.parse(time);
369 } else {
370 long diff = df.parse(time).getTime() - player1Time.getTime();
371 Date date = new Date(diff - (3600 * 1000));
372 player1Panel.setTime(df.format(date));
373 }
374 } else if (2 == turn) {
375 if (null == player2Time) {
376 player2Time = df.parse(time);
377 } else {
378 long diff = df.parse(time).getTime() - player2Time.getTime();
379 Date date = new Date(diff - (3600 * 1000));
380 player2Panel.setTime(df.format(date));
381 }
382 }
383 }
384
385 private void markMove(Node node) {
386 List directionsList = node.selectNodes("//type");
387 Vector movesVector = new Vector();
388
389 for (Iterator j = directionsList.iterator(); j.hasNext();) {
390 Node directionNode = (Node) j.next();
391 movesVector.add(new Integer(directionNode.getText()));
392 }
393
394 try {
395 Move move = new Move((Integer[]) movesVector.toArray(new Integer[0]));
396 field.makeMove(move, turn);
397 } catch (InvalidMoveException e) {
398 logger.error("Invalid move.");
399 }
400
401
402 if (1 == turn) {
403 player1Panel.setMovesAverage(field.getAvgMoveLength(1));
404 player1Panel.setMovesTotal(field.getNumberOfMoves(1));
405 } else {
406 player2Panel.setMovesAverage(field.getAvgMoveLength(2));
407 player2Panel.setMovesTotal(field.getNumberOfMoves(2));
408 }
409
410
411 if (1 == turn) {
412 turn = 2;
413 } else if (2 == turn) {
414 turn = 1;
415 }
416 }
417
418 private void drawField() {
419 Insets insets = fieldPanel.getInsets();
420 int imageWidth = fieldPanel.getWidth() - insets.left - insets.right;
421 int imageHeight = fieldPanel.getHeight() - insets.top - insets.bottom;
422
423 Image buffer = createImage(imageWidth, imageHeight);
424 Graphics g = buffer.getGraphics();
425
426 int fieldWidth = field.getMaximumXIndex();
427 int fieldHeight = field.getMaximumYIndex();
428
429 int scaleX = imageWidth / fieldWidth;
430 int scaleY = imageHeight / fieldHeight;
431 translate[0] = 0;
432 translate[1] = 0;
433
434 if (scaleX > scaleY) {
435 scale = scaleY;
436 translate[0] = (imageWidth - (fieldWidth * scaleY)) / 2;
437 } else if (scaleX > scaleY) {
438 scale = scaleX;
439 translate[1] = (imageHeight - (fieldHeight * scaleY)) / 2;
440 }
441
442 for (int x = 0; x <= fieldWidth; ++x) {
443 for (int y = 0; y <= fieldHeight; ++y) {
444 FieldPoint p = field.getFieldPoint(x, y);
445
446 for (int i = 1; i < 5; ++i) {
447 Point begin = new Point(x, y);
448 Point end = (Point) begin.clone();
449 int[] v = Move.getTranslation(new Integer(i));
450 end.translate(v[0], v[1]);
451
452 begin.x *= scale;
453 begin.y *= scale;
454 end.x *= scale;
455 end.y *= scale;
456 begin.translate(translate[0], translate[1]);
457 end.translate(translate[0], translate[1]);
458
459 drawLine(begin, end, p.getEdgeColor(i), g);
460 }
461 }
462 }
463
464 fieldPanel.setImage(buffer);
465 fieldPanel.repaint();
466 }
467
468 private void drawLine(Point begin, Point end, int edgeColor, Graphics g) {
469 Color color = null;
470
471 if (-2 == edgeColor) {
472 return;
473 } else if (-1 == edgeColor) {
474 color = new Color(0, 0, 0);
475 } else if (0 == edgeColor) {
476
477 color = bgColor;
478 } else if (1 == edgeColor) {
479 color = new Color(255, 0, 0);
480 } else if (2 == edgeColor) {
481 color = new Color(0, 0, 255);
482 }
483
484 g.setColor(color);
485
486 int thickness = scale / 20;
487
488 if (begin.y == end.y) {
489 for (int i = -thickness; i <= thickness; ++i) {
490 g.drawLine(begin.x, begin.y + i, end.x, end.y + i);
491 }
492 } else if (begin.x == end.x) {
493 for (int i = -thickness; i <= thickness; ++i) {
494 g.drawLine(begin.x + i, begin.y, end.x + i, end.y);
495 }
496 } else if (begin.y > end.y) {
497 for (int i = 1; i <= thickness; ++i) {
498 g.drawLine(begin.x, begin.y - i, end.x - i, end.y);
499 }
500
501 for (int i = 1; i <= thickness; ++i) {
502 g.drawLine(begin.x + i, begin.y, end.x, end.y + i);
503 }
504
505 g.drawLine(begin.x, begin.y, end.x, end.y);
506 } else if (begin.y < end.y) {
507 for (int i = 1; i <= thickness; ++i) {
508 g.drawLine(begin.x + i, begin.y, end.x, end.y - i);
509 }
510
511 for (int i = 1; i <= thickness; ++i) {
512 g.drawLine(begin.x, begin.y + i, end.x - i, end.y);
513 }
514
515 g.drawLine(begin.x, begin.y, end.x, end.y);
516 }
517 }
518 }
519
520
521