package ch.sahits.game.openpatrician.server;
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import org.apache.log4j.Logger;
import ch.sahits.game.event.Event;
import ch.sahits.game.event.IEventListener;
import ch.sahits.game.openpatrician.client.GameRunnable;
import ch.sahits.game.openpatrician.controller.CityEngine;
import ch.sahits.game.openpatrician.model.Date;
import ch.sahits.game.openpatrician.model.GameFactory;
import ch.sahits.game.openpatrician.model.IGame;
import ch.sahits.game.openpatrician.model.IPlayer;
import ch.sahits.game.openpatrician.model.city.ICity;
/**
* Server of the Openpatrician Game
* @author Andi Hotz, (c) Sahits GmbH, 2011
* Created on Sep 17, 2011
*
*/
public class OpenPatricianServer implements IEventListener{
private static final Logger logger = Logger.getLogger(OpenPatricianServer.class);
private static boolean running = true;
private final int NUMBER_OF_PLAYERS;
private IPlayer[] players;
private List<Thread> threads = new LinkedList<Thread>();
private final IGame game;
/**
* engine that handles the city events based on clock ticks
*/
private final CityEngine cityEngine;
/** Timer that let the game time progress */
private final Timer clockTimer; // this might be tricky in multiplayer scenario (perhaps synchronize with clients at day change )
/**
* Based on the event server setup there are different implementation of the
* event listeners
*/
private IEventListener eventListenerDelegate;
/**
* Create the server instance for a game
* @param game model of it
* @param nbHumanPlayers number of human players
*/
public OpenPatricianServer(IGame game ,int nbHumanPlayers){
this.game=game;
NUMBER_OF_PLAYERS=game.getMap().getNumberCities();
players = new IPlayer[NUMBER_OF_PLAYERS+nbHumanPlayers];
clockTimer = new Timer("Game-Clcok");
clockTimer.scheduleAtFixedRate(new ClockTick(game.getTime()), 0, 100); // schedule every 1/10 s
cityEngine = new CityEngine();
}
/**
* Convenience constructor to set the server up with one human player
* @param game
*/
public OpenPatricianServer(IGame game){
this(game, 1);
}
/**
* Create a standalone game
* @param run {@link GameRunnable} identifing the human player UI
*/
public void startStandaloneGame(GameRunnable run) {
// create the player instances
players[0] = run.getClient().getPlayer();
createAndInitAIPlayers(1,players[0].getCash());
// create event listeners
eventListenerDelegate = new SinglePlayerEventListener();
Event.add(this);
threads.add(Thread.currentThread());
threads.add(new Thread(createAIPlayerRunner()));
// initilaize the client map and other players
run.getClient().initGame(game);
for (int i= 1;i<players.length;i++){
run.getClient().addCompetitor(players[i]);
}
// run this in the same thread as the user
List<ICity> cities = game.getMap().getCities();
for (ICity city : cities) {
cityEngine.addCity(city);
}
cityEngine.start(game);
logger.debug("Standalone Server created");
}
/**
* Create the remaining players as artificial players
* @param nbOfPlayersInitialized
*/
private void createAndInitAIPlayers(int nbOfPlayersInitialized, long initialcash) {
List<ICity> cities = game.getMap().getCities();
int cityIndex=0;
for (int i = nbOfPlayersInitialized; i < players.length; i++) {
players[i] = GameFactory.createAIPlayer(cities.get(cityIndex++),initialcash);
}
}
/**
* Add a player to the multiplayer game. If all
* players are added the the game is started
*/
public void addMultiplayer(){
// TODO implement
}
// /**
// * Start the multiplayer game.
// */
// private void startMultiplayerGame(){
// // TODO implement
// // Set up event listener
// }
private Runnable createAIPlayerRunner(){ // TODO use GameRunnable
return new Runnable() {
@Override
public void run() {
while (running){
try {
Thread.sleep(1000); // TODO implement AI
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
}
/**
* @param running the running to set
*/
public static void setRunning(boolean running) {
OpenPatricianServer.running = running;
}
/**
* Delegate to the event listener implementation
*/
@Override
public void gameUpdate(Event e, Object eventNotice) {
eventListenerDelegate.gameUpdate(e, eventNotice);
}
/**
* Timer task updating the date by one tick
* @author Andi Hotz, (c) Sahits GmbH, 2011
* Created on Nov 27, 2011
*
*/
private static class ClockTick extends TimerTask{
private Date clock;
public ClockTick(Date clock){
this.clock = clock;
}
@Override
public void run() {
clock.tick();
}
}
}