package pong.client.model;
import javax.swing.JFrame;
import pong.client.ClientSettings;
import pong.common.GlobalSettings;
import pong.common.PlayerMovementInformation;
import pong.common.Position;
/**
* This class manages everything the client needs to play a match.
*
* @author Lorenzo Gatto
*
*/
public class ClientModel implements EventsHandler, ClientModelInterface {
private final KeyboardListener listener;
private final Integer[] roundWon;
private final JFrame window;
private ClientProtocolThread connection;
private Position[] position;
private Integer playerIndex;
private State state;
private int roundsNumber;
/**
* Initializer.
*
* @param window
* the frame where to listen for keyboard events
*/
public ClientModel(final JFrame window) {
this.window = window;
this.listener = new KeyboardListener();
this.window.setFocusable(true);
this.roundWon = new Integer[2];
this.position = new Position[3];
for (int i = 0; i < 3; i++) {
this.position[i] = new Position();
}
this.state = State.GETTING_SERVER_INFORMATION;
}
@Override
public synchronized void matchBeginsEvent(final int roundsNumber) {
this.state = State.MATCH_BEGINS;
this.roundWon[0] = 0;
this.roundWon[1] = 0;
this.roundsNumber = roundsNumber;
}
@Override
public synchronized void roundBeginsEvent() {
this.state = State.PLAYING_ROUND;
}
@Override
public synchronized void serverDisconnectedEvent() {
this.window.removeKeyListener(listener);
this.state = State.SERVER_DISCONNECTED;
this.connection = null;
}
@Override
public synchronized void otherDisconnectedWhilePlayingEvent() {
this.state = State.OTHER_PLAYER_DISCONNECTED;
try {
Thread.sleep(ClientSettings.OTHER_DISCONNECTS_PAUSE_MS);
} catch (InterruptedException e) {
// DO NOTHING
}
state = State.WAITING_OTHER_PLAYER;
}
@Override
public synchronized void connectionSuccessfullEvent() {
this.state = State.WAITING_OTHER_PLAYER;
}
@Override
public synchronized void connectionFailedEvent() {
this.window.removeKeyListener(listener);
this.state = State.CONNECTION_FAILED;
this.connection = null;
}
@Override
public synchronized void playerIndexReceivedEvent(final Integer playerIndex) {
assert playerIndex == 0 || playerIndex == 1;
this.playerIndex = playerIndex;
}
@Override
public synchronized PlayerMovementInformation movementInformationRequestedEvent() {
final PlayerMovementInformation movement = new PlayerMovementInformation();
movement.setGoingUp(listener.pressingUp());
movement.setGoingDown(listener.pressingDown());
return movement;
}
@Override
public synchronized void objectPositionsReceivedEvent(final Position[] newPositions) {
this.position = newPositions;
}
@Override
public synchronized void roundEndEvent(final Boolean won) {
if (won) {
this.state = State.ROUND_WON;
this.roundWon[playerIndex]++;
} else {
this.state = State.ROUND_LOST;
this.roundWon[1 - playerIndex]++;
}
checkMatchEnd();
}
@Override
public synchronized void connect(final String host, final int port) {
this.window.addKeyListener(listener);
this.connection = new ClientProtocolThread(this, host, port);
this.state = State.CONNECTION;
this.connection.start();
}
@Override
public synchronized void disconnect() {
this.window.removeKeyListener(listener);
if (this.connection != null) {
this.connection.disconnect();
this.connection = null;
}
this.state = State.GETTING_SERVER_INFORMATION;
}
@Override
public synchronized Position[] getPositions() {
final Position[] positionsClone = this.position.clone();
return positionsClone;
}
@Override
public synchronized int getPlayerIndex() {
return this.playerIndex;
}
@Override
public synchronized State getState() {
return this.state;
}
@Override
public synchronized Integer[] getRoundsWon() {
final Integer[] roundWonClone = this.roundWon.clone();
return roundWonClone;
}
@Override
public synchronized int getRoundsNumber() {
return this.roundsNumber;
}
/**
* Checks for match end based on round played and updates the state
*/
private void checkMatchEnd() {
if (this.roundWon[0] + this.roundWon[1] == this.roundsNumber) {
try {
Thread.sleep(GlobalSettings.MATCH_END_PAUSE / 2);
} catch (InterruptedException e) {
// DO NOTHING
}
if (this.roundWon[this.playerIndex] > this.roundWon[1 - this.playerIndex]) {
this.state = State.MATCH_WON;
} else if (this.roundWon[this.playerIndex] == this.roundWon[1 - this.playerIndex]) {
this.state = State.MATCH_DRAWN;
} else {
this.state = State.MATCH_LOST;
}
}
}
}