package org.openbakery.racecontrol;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeSet;
import org.openbakery.jinsim.Tiny;
import org.openbakery.jinsim.request.TinyRequest;
import org.openbakery.jinsim.response.*;
import org.openbakery.racecontrol.control.AbstractControl;
import org.openbakery.racecontrol.control.LapControl;
import org.openbakery.racecontrol.control.MainRaceControl;
import org.openbakery.racecontrol.control.MessageControl;
import org.openbakery.racecontrol.control.PitControl;
import org.openbakery.racecontrol.control.PlayerControl;
import org.openbakery.racecontrol.data.Driver;
import org.openbakery.racecontrol.data.Flag;
import org.openbakery.racecontrol.data.Lap;
import org.openbakery.racecontrol.event.CameraEvent;
import org.openbakery.racecontrol.event.CameraEventListener;
import org.openbakery.racecontrol.event.LapEvent;
import org.openbakery.racecontrol.event.LapEventListener;
import org.openbakery.racecontrol.event.RaceEvent;
import org.openbakery.racecontrol.event.RaceEventListener;
import org.openbakery.racecontrol.event.RaceEvent.Type;
import org.openbakery.racecontrol.gui.ButtonMessageHelper;
import org.openbakery.racecontrol.persistence.Persistence;
import org.openbakery.racecontrol.plugin.Plugin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class RaceControl implements InSimListener, Runnable {
private static Logger log = LoggerFactory.getLogger(RaceControl.class);
private JInSimClient client;
private Persistence persistence;
private Race race;
private ArrayList<LapEventListener> lapEventListener = new ArrayList<LapEventListener>();
private ArrayList<RaceEventListener> raceEventListener = new ArrayList<RaceEventListener>();
private ArrayList<CameraEventListener> cameraEventListener = new ArrayList<CameraEventListener>();
private List<Plugin> plugins;
private ArrayList<AbstractControl> controlList;
public RaceControl() {
race = new Race();
plugins = new ArrayList<Plugin>();
}
public void start() throws IOException {
controlList = new ArrayList<AbstractControl>();
controlList.add(new MainRaceControl(this, persistence));
controlList.add(new LapControl(this, persistence));
controlList.add(new MessageControl(this, persistence));
controlList.add(new PitControl(this, persistence));
controlList.add(new PlayerControl(this, persistence));
client.connect();
client.addListener(this);
log.info("Started...");
client.send(new TinyRequest(Tiny.RESTART));
client.send(new TinyRequest(Tiny.ALL_CONNECTIONS));
client.send(new TinyRequest(Tiny.ALL_PLAYERS));
}
public void stop() throws IOException {
log.info("Stopped");
for (AbstractControl control : controlList) {
control.destroy();
}
controlList.clear();
client.removeListener(this);
client.close();
}
public boolean isConnected() {
return client.isConnected();
}
public void packetReceived(InSimResponse response) {
log.debug("packageReceived: {}", response);
if (response instanceof PlayerResponse) {
PlayerResponse playerResponse = (PlayerResponse)response;
playerResponse.getPlayerId();
Driver driver = race.getDriverByPlayerId(playerResponse.getPlayerId());
if (driver == null) {
log.debug("Driver unknown: {}", playerResponse);
} else {
log.debug("Driver {}: {}", driver.getName(), playerResponse);
}
}
for (AbstractControl control : controlList) {
control.packetReceived(response);
}
try {
if (response instanceof FlagResponse) {
processFlagResponse((FlagResponse) response);
} else if (response instanceof PenaltyResponse) {
processPenaltyResponse((PenaltyResponse) response);
} else if (response instanceof MultiplayerBeginResponse) {
processMultiplayerBeginResponse((MultiplayerBeginResponse) response);
} else if (response instanceof HiddenMessageResponse) {
HiddenMessageResponse hiddenMessageResponse = (HiddenMessageResponse) response;
int connectionId = hiddenMessageResponse.getConnectionId();
Driver driver = race.getDriver(connectionId);
if (connectionId == 0 || driver.isAdmin()) {
processCommand(hiddenMessageResponse);
}
} else if (response instanceof StateResponse) {
StateResponse cameraResponse = (StateResponse) response;
Driver driver = race.getDriverByPlayerId(cameraResponse.getPlayer());
if (driver != null) {
notifyCameryEventListener(new CameraEvent(driver, CameraEvent.CameraType.getByInSimType(cameraResponse.getCamera())));
}
} else if (response instanceof ConnectionCloseResponse) {
stop();
log.info("Disconnected from host");
//Thread.sleep(10000);
//start();
}
// else {
// log.debug("reponse: " + response);
// }
} catch (Exception ex) {
log.error("Unknown error", ex);
System.exit(1);
}
}
private void processMultiplayerBeginResponse(MultiplayerBeginResponse response) {
try {
client.send(new TinyRequest(Tiny.ALL_CONNECTIONS));
client.send(new TinyRequest(Tiny.ALL_PLAYERS));
client.send(new TinyRequest(Tiny.SEND_STATE_INFO));
} catch (IOException e) {
log.error("Cannot end all players request", e);
}
}
private void processPenaltyResponse(PenaltyResponse response) {
Driver driver;
try {
driver = race.getRaceDriver(response);
if (!race.hasFinished(driver)) {
Lap lap = driver.getCurrentLap();
lap.setOldPenalty(response.getOldPenalty());
lap.setNewPenalty(response.getNewPenalty());
}
} catch (DriverNotFoundException e) {
log.warn(e.getMessage());
}
}
private void processFlagResponse(FlagResponse response) {
if (race.hasRaceEntry()) {
Driver driver;
try {
driver = race.getRaceDriver(response);
if (!race.hasFinished(driver)) {
Lap lap = driver.getCurrentLap();
Flag flag = lap.getCurrentFlag();
if (flag != null) {
if (response.getOn() && response.getFlag() == flag.getType()) {
flag.setEndTime(System.currentTimeMillis());
}
}
if (response.getOn()) {
flag = new Flag();
flag.setType(response.getFlag());
flag.setStartTime(System.currentTimeMillis());
lap.addFlag(flag);
}
}
} catch (DriverNotFoundException e) {
log.warn(e.getMessage());
}
}
}
public void exit() {
try {
client.close();
} catch (IOException e) {
log.error("Cannot close client connection", e);
}
}
/*
* private void calculateQualifyingResults() { ArrayList<Result> allResults = new ArrayList<Result>();
*
* for (Driver driver : race.getRaceDrivers()) { long bestLapTime = Long.MAX_VALUE; for (Lap lap : driver.getAllLaps()) { if (lap.isFinished() && bestLapTime > lap.getTime()) { bestLapTime =
* lap.getTime(); } } Result result = driver.getResult(); if (result == null) { result = new Result(); driver.setResult(result); } driver.getResult().setBestLapTime(bestLapTime);
* allResults.add(result); }
*
* Collections.sort(allResults, new ResultComparator()); for (int i=0; i<allResults.size(); i++) { allResults.get(i).setPosition(i+1); log.debug(allResults.get(i)); } }
*/
/*
* @SuppressWarnings("unchecked") private void removeOldDriver(byte connectionId) { if (log.isDebugEnabled()) { log.debug("remove driver with connection id: " + connectionId); } Driver oldDriver =
* null; for (Driver driver : race.getDrivers()) { if (driver.getConnectionId() == connectionId) { oldDriver = driver; break; } } if (oldDriver != null) { if (log.isDebugEnabled()) {
* log.debug("removing driver: " + oldDriver); } race.removeDriver(oldDriver); } }
*/
public void run() {
try {
while (true) {
Thread.sleep(10);
}
} catch (Exception ex) {
log.error("Unexpected Exception", ex);
}
}
private void processCommand(HiddenMessageResponse response) {
String line = response.getMessage();
log.debug("process command: " + line);
if (line == null) {
return;
}
if ("help".equalsIgnoreCase(line)) {
log.info("Commands:");
log.info("plugins - lists available plugins");
} else if (line.startsWith("plugins")) {
StringBuilder message = new StringBuilder("Available plugins: ");
for (Plugin plugin : plugins) {
message.append(plugin.getName());
message.append(", ");
}
message.delete(message.length() - 2, message.length());
ButtonMessageHelper.getInstance().sendButtonMessage(message.toString());
}
}
public void setLapEventListener(List<LapEventListener> listener) {
this.lapEventListener.addAll(listener);
}
public void addLapEventListener(LapEventListener listener) {
lapEventListener.add(listener);
}
public void removeLapEventListener(LapEventListener listener) {
lapEventListener.remove(listener);
}
public void notifyLapEventListener(LapEvent event) {
for (LapEventListener listener : lapEventListener) {
try {
if (event.getSplit() > 0) {
listener.lapSplit(event);
} else {
listener.lapFinished(event);
}
} catch (Exception ex) {
log.error("Error notifying a lap event listener", ex);
}
}
}
private void notifyCameryEventListener(CameraEvent event) {
for (CameraEventListener listener : cameraEventListener) {
try {
listener.cameraChangedEvent(event);
} catch (Exception ex) {
log.error("Error notifying a camera event listener", ex);
}
}
}
public void setRaceEventListener(List<RaceEventListener> listener) {
this.raceEventListener.addAll(listener);
}
public void addRaceEventListener(RaceEventListener listener) {
raceEventListener.add(listener);
}
public void removeRaceEventListener(RaceEventListener listener) {
raceEventListener.remove(listener);
}
public void notifyRaceEventListener(RaceEvent event) {
for (RaceEventListener listener : raceEventListener) {
try {
if (event.getType() == Type.STARTED) {
listener.raceStartEvent(event);
} else if (event.getType() == Type.NEW_DRIVER) {
listener.raceNewDriverEvent(event);
} else {
listener.raceEndEvent(event);
}
} catch (Exception ex) {
log.error("error notifying a race event listener", ex);
}
}
}
public void setPersistence(Persistence persistence) {
this.persistence = persistence;
}
public void setClient(JInSimClient client) {
this.client = client;
}
public Race getRace() {
return race;
}
public void setPlugins(List<Plugin> plugins) {
for (Plugin p : plugins) {
this.plugins.add(p);
client.addListener(p);
}
}
public List<Plugin> getPlugins() {
return plugins;
}
}