/* Copyright (C) 2010 - 2011 Fabian Neundorf, Philip Caroli,
* Maximilian Madlung, Usman Ghani Ahmed, Jeremias Mechler
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.ojim.client;
import java.io.Serializable;
import java.rmi.RemoteException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.ojim.client.triggers.OnAuction;
import org.ojim.client.triggers.OnBankruptcy;
import org.ojim.client.triggers.OnBuy;
import org.ojim.client.triggers.OnBuyEvent;
import org.ojim.client.triggers.OnCanEndTurn;
import org.ojim.client.triggers.OnCardPull;
import org.ojim.client.triggers.OnCashChange;
import org.ojim.client.triggers.OnConstruct;
import org.ojim.client.triggers.OnDestruct;
import org.ojim.client.triggers.OnDiceValues;
import org.ojim.client.triggers.OnFreeParkingChange;
import org.ojim.client.triggers.OnMessage;
import org.ojim.client.triggers.OnMortgageToogle;
import org.ojim.client.triggers.OnMove;
import org.ojim.client.triggers.OnNewPlayer;
import org.ojim.client.triggers.OnPlayerLeft;
import org.ojim.client.triggers.OnStartGame;
import org.ojim.client.triggers.OnTrade;
import org.ojim.client.triggers.OnTurn;
import org.ojim.iface.IClient;
import org.ojim.log.OJIMLogger;
import org.ojim.logic.state.Auction;
import org.ojim.logic.state.DiceSet;
import org.ojim.logic.state.GameState;
import org.ojim.logic.state.Player;
import org.ojim.logic.state.StaticDice;
import org.ojim.logic.state.fields.BuyableField;
import org.ojim.logic.state.fields.Field;
import org.ojim.logic.state.fields.FieldGroup;
import org.ojim.logic.state.fields.FreeParking;
import org.ojim.logic.state.fields.Jail;
import org.ojim.logic.state.fields.Street;
import org.ojim.rmi.client.ImplNetClient;
import org.ojim.rmi.client.StartNetClient;
import org.ojim.rmi.server.NetOjim;
import edu.kit.iti.pse.iface.IServer;
/**
* Basis Client für den GUIClient und AIClient.
*
* @author Fabian Neundorf
*/
public abstract class ClientBase extends SimpleClient implements IClient,Serializable {
private String name;
private ExecutorService executor;
private Logger logger;
private StaticDice[] dice;
public ClientBase() {
super();
this.executor = Executors.newFixedThreadPool(1);
this.logger = OJIMLogger.getLogger(this.getClass().toString());
}
/*
* MISC
*/
private void loadGameBoard() {
GameState state = this.getGameState();
state.getBank().setHotels(this.getNumberOfHotelsLeft());
state.getBank().setHouses(this.getNumberOfHousesLeft());
Map<Integer, FieldGroup> groups = new HashMap<Integer, FieldGroup>(17);
for (int position = 0; position < this.getGameState().getNumberOfFields(); position++) {
Field field = this.getFieldFromServer(position, groups, new HashMap<Integer, Player>());
if (field != null) {
state.setFieldAt(field, position);
}
}
}
public void setName(String name) {
this.name = name;
}
/*
* ACTION METHODS
*/
protected final boolean connect(String host, int port) {
try {
StartNetClient starter = new StartNetClient();
NetOjim netojim = starter.createClientRMIConnection(port, host, this);
ImplNetClient server = new ImplNetClient(this, netojim);
this.setParameters(server, this);
this.loadGameBoard();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
return true;
}
protected final void connect(IServer server, GameState state) {
this.setParameters(server, this, state);
this.loadGameBoard();
}
protected final void connect(IServer server) {
this.connect(server, new GameState());
}
@Override
protected void setParameters(IServer server, IClient client, GameState state) {
// New dynamic way?
this.dice = new StaticDice[2];
this.dice[0] = new StaticDice(6);
this.dice[1] = new StaticDice(6);
DiceSet set = new DiceSet(this.dice);
state.setDiceSet(set);
super.setParameters(server, client, state);
}
/*
* TRIGGER-METHODS
*/
@Override
public String getLanguage() {
return "eng";
}
@Override
public String getName() {
return this.name;
}
@Override
public final void informBankruptcy() {
this.logger.log(Level.INFO, "informBankruptcy()");
this.getGameState().getActivePlayer().setBankrupt();
// this.onBankruptcy();
this.executor.execute(new OnBankruptcy(this));
}
public abstract void onBankruptcy();
@Override
public final void informCardPull(String text, boolean communityCard) {
this.logger.log(Level.INFO, "informCardPull(" + text + ", " + communityCard + ")");
this.updatePlayersGetOutOfJailCards(this.getGameState().getActivePlayer());
//this.onCardPull(text, communityCard);
this.executor.execute(new OnCardPull(this, text, communityCard));
}
public abstract void onCardPull(String text, boolean communityCard);
@Override
public final void informCashChange(int playerId, int cashChange) {
this.logger.log(Level.INFO, "informCashChange(" + playerId + "," + cashChange + ")");
Player player = this.getGameState().getPlayerById(playerId);
if (player != null) {
player.transferMoney(cashChange);
// this.onCashChange(player, cashChange);
this.executor.execute(new OnCashChange(this, player, cashChange));
} else {
this.logger.warning("Get informCashChange with invalid player (" + playerId
+ ").");
}
}
public abstract void onCashChange(Player player, int cashChange);
@Override
public final void informConstruct(int street) {
this.logger.log(Level.INFO, "informConstruct(" + street + ")");
Field field = this.getLogic().getGameState().getFieldAt(street);
if (field instanceof Street) {
this.getLogic().upgrade((Street) field, +1);
//this.onConstruct((Street) field);
this.executor.execute(new OnConstruct(this, (Street) field));
} else {
this.logger.warning(
"Get informConstruct with invalid street.");
}
}
public abstract void onConstruct(Street street);
@Override
public final void informDestruct(int street) {
this.logger.log(Level.INFO, "informDestruct(" + street + ")");
Field field = this.getLogic().getGameState().getFieldAt(street);
if (field instanceof Street) {
this.getLogic().upgrade((Street) field, -1);
// this.onDestruct((Street) field);
this.executor.execute(new OnDestruct(this, (Street) field));
} else {
this.logger.warning("Get informDestruct with invalid street.");
}
}
public abstract void onDestruct(Street street);
@Override
public final void informDiceValues(int[] diceValues) {
this.logger.log(Level.INFO, "informDiceValues(" + Arrays.toString(diceValues) + ")");
// Set dice values in dice set
for (int i = 0; i < diceValues.length; i++) {
this.dice[i].setResult(diceValues[i]);
}
// this.onDiceValues(diceValues);
this.executor.execute(new OnDiceValues(this, diceValues));
}
public abstract void onDiceValues(int[] diceValues);
@Override
public final void informMessage(String text, int sender,
boolean privateMessage) {
this.logger.log(Level.INFO, "informMessage(" + text + "," + sender + "," + privateMessage + ")");
Player player = null;
if ((sender == -1)
|| (player = this.getGameState().getPlayerById(sender)) != null) {
//this.onMessage(text, player, privateMessage);
this.executor.execute(new OnMessage(this, text, player,
privateMessage));
} else {
this.logger.warning("Get informMessage with invalid player (" + sender + ").");
}
}
public abstract void onMessage(String text, Player sender,
boolean privateMessage);
@Override
public final void informMortgageToogle(int street) {
this.logger.log(Level.INFO, "informMortgageToogle(" + street + ")");
Field field = this.getLogic().getGameState().getFieldAt(street);
if (field instanceof BuyableField) {
this.getLogic().toggleMortgage((BuyableField) field);
//this.onMortgageToogle((BuyableField) field);
this.executor.execute(new OnMortgageToogle(this,
(BuyableField) field));
} else {
this.logger.warning("Get informMortgageToogle with invalid buyable field.");
}
}
public abstract void onMortgageToogle(BuyableField street);
@Override
public final void informStartGame(int[] ids) {
this.logger.log(Level.INFO, "informStartGame(" + Arrays.toString(ids) + ")");
GameState state = this.getGameState();
Player[] order = new Player[ids.length];
for (int i = 0; i < ids.length; i++) {
order[i] = state.getPlayerById(ids[i]);
}
state.setPlayerOrder(order);
//this.onStartGame(this.getGameState().getPlayers());
this.executor.execute(new OnStartGame(this, this.getGameState()
.getPlayers()));
}
public abstract void onStartGame(Player[] players);
@Override
public final void informTrade() {
this.logger.log(Level.INFO, "informTrade()");
//this.onTrade(acting, partner);
this.executor.execute(new OnTrade(this));
}
public abstract void onTrade();
@Override
public final void informTurn(int player) {
this.logger.log(Level.INFO, "informTurn(" + player + ")");
Player newPlayer = this.getGameState().getPlayerById(player);
if (newPlayer != null) {
this.getGameState().setActivePlayer(newPlayer);
//this.onTurn(newPlayer);
this.executor.execute(new OnTurn(this, newPlayer));
} else {
this.logger.warning("Get informTurn with invalid player.");
}
}
public abstract void onTurn(Player player);
@Override
public final void informMove(int playerId, int position) {
this.logger.log(Level.INFO, "informMove(" + playerId + ", " + position + ")");
Player player = this.getGameState().getPlayerById(playerId);
if (player != null) {
player.setPosition(position);
if (position < 0 && this.getGameState().getFieldAt(Math.abs(position)) instanceof Jail) {
player.sendToJail((Jail) this.getGameState().getFieldAt(Math.abs(position)));
} else {
player.sendToJail(null);
}
//this.onMove(player, position);
this.executor.execute(new OnMove(this, player));
} else {
this.logger.warning("Get informMove with invalid player, ID = " + playerId);
}
}
public abstract void onMove(Player player);
@Override
public final void informBuy(int playerId, int position) {
this.logger.log(Level.INFO, "informBuy(" + playerId + ", " + position + ")");
Player player = this.getGameState().getPlayerById(playerId);
if (player != null) {
Field field = this.getGameState().getFieldAt(position);
if (field instanceof BuyableField) {
((BuyableField) field).buy(player);
// this.onBuy(player, (BuyableField) field);
this.executor.execute(new OnBuy(this, player,
(BuyableField) field));
} else {
this.logger.warning("Get informBuy with invalid position.");
}
} else {
this.logger.warning("Get informBuy with invalid player.");
}
}
public abstract void onBuy(Player player, BuyableField field);
@Override
public void informBuyEvent(int player, int position) {
this.logger.log(Level.INFO, "informBuyEvent(" + player + ", " + position + ")");
Player p = this.getGameState().getPlayerById(player);
if (p != null) {
Field field = this.getGameState().getFieldAt(position);
if (field instanceof BuyableField) {
// this.onBuyEvent(player, (BuyableField) field);
this.executor.execute(new OnBuyEvent(this, p,
(BuyableField) field));
} else {
this.logger.warning("Get informBuy with invalid position.");
}
} else {
this.logger.warning("Get informBuy with invalid player.");
}
}
public abstract void onBuyEvent(Player player, BuyableField field);
@Override
public final void informAuction(int auctionState) {
this.logger.log(Level.INFO, "informAuction(" + auctionState + ")");
try {
Auction auction = this.getGameState().getAuction();
if (auction != null) {
auction = this.updateAuction(auction);
} else {
auction = this.getAuctionFromServer();
}
this.getGameState().setAuction(auction);
//this.onAuction(auctionState);
this.executor.execute(new OnAuction(this));
} catch (IllegalArgumentException e) {
this.logger.log(Level.WARNING, "Get informAuction with invalid auction.", e);
}
}
public abstract void onAuction();
public final void informNewPlayer(int playerId) {
this.logger.log(Level.INFO, "informNewPlayer(" + playerId + ")");
if (this.getGameState().getPlayerById(playerId) == null) {
Player player = this.getPlayerFromServer(playerId);
this.getGameState().setPlayer(player);
// Update all owned fields
for (int i = 0; i < this.getGameState().getNumberOfFields(); i++) {
Field field = this.getGameState().getFieldAt(i);
if (field instanceof BuyableField && ((BuyableField) field).getOwner() == null) {
this.updateFieldOwner((BuyableField) field, this.getGameState().getPlayersMap());
}
}
//this.onNewPlayer(player);
this.executor.execute(new OnNewPlayer(this, player));
} else {
this.logger.warning("Get informNewPlayer with already existing player.");
}
}
public abstract void onNewPlayer(Player player);
public final void informPlayerLeft(int playerId) {
this.logger.log(Level.INFO, "informPlayerLeft(" + playerId + ")");
Player old = this.getGameState().getPlayerById(playerId);
this.getGameState().removePlayer(old);
// Remove all owners for this field
for (int i = 0; i < this.getGameState().getNumberOfFields(); i++) {
Field field = this.getGameState().getFieldAt(i);
if (field instanceof BuyableField && ((BuyableField)field).getOwner() != null && ((BuyableField) field).getOwner().equals(old)) {
((BuyableField) field).buy(null);
}
}
//this.onPlayerLeft(old);
this.executor.execute(new OnPlayerLeft(this, old));
}
public abstract void onPlayerLeft(Player player);
@Override
public final void informFreeParkingChange(int freeParkingField, int newPot) {
this.logger.log(Level.INFO, "informFreeParkingChange(" + freeParkingField + ", " + newPot + ")");
Field f = this.getGameState().getFieldAt(freeParkingField);
if (f instanceof FreeParking) {
FreeParking freeParking = (FreeParking) f;
freeParking.transferMoney(newPot - freeParking.getMoneyInPot());
//onFreeParkingChange(old);
this.executor.execute(new OnFreeParkingChange(this, freeParking));
} else {
this.logger.warning("Get informFreeParkingChange with invalid position.");
}
}
public void informGameOver(int winnerID) { }
public abstract void onFreeParkingChange(FreeParking field);
@Override
public final void informCanEndTurn(int player) {
this.logger.log(Level.INFO, "informCanEndTurn(" + player + ")");
Player p = this.getGameState().getPlayerById(player);
if (p != null) {
//this.onCanEndTurn(p);
this.executor.execute(new OnCanEndTurn(this, p));
} else {
this.logger.warning("Get informCanEndTurn with invalid player.");
}
}
public abstract void onCanEndTurn(Player player);
@Override
public void setPlayerId(int newId) {
super.setPlayerId(newId);
}
}