package org.openbakery.racecontrol.control;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import org.openbakery.jinsim.Tiny;
import org.openbakery.jinsim.response.InSimResponse;
import org.openbakery.jinsim.response.RaceStartResponse;
import org.openbakery.jinsim.response.ReorderResponse;
import org.openbakery.jinsim.response.ResultResponse;
import org.openbakery.jinsim.response.TinyResponse;
import org.openbakery.racecontrol.DriverNotFoundException;
import org.openbakery.racecontrol.Race;
import org.openbakery.racecontrol.RaceControl;
import org.openbakery.racecontrol.ResultComparator;
import org.openbakery.racecontrol.data.Driver;
import org.openbakery.racecontrol.data.Lap;
import org.openbakery.racecontrol.data.RaceEntry;
import org.openbakery.racecontrol.data.Result;
import org.openbakery.racecontrol.data.Weather;
import org.openbakery.racecontrol.data.Wind;
import org.openbakery.racecontrol.event.RaceEvent;
import org.openbakery.racecontrol.event.RaceEvent.Type;
import org.openbakery.racecontrol.persistence.Persistence;
import org.openbakery.racecontrol.persistence.PersistenceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MainRaceControl extends AbstractControl {
private static Logger log = LoggerFactory.getLogger(MainRaceControl.class);
public MainRaceControl(RaceControl raceControl, Persistence persistence) {
super(raceControl, persistence);
}
public void packetReceived(InSimResponse response) {
try {
if (response instanceof TinyResponse) {
TinyResponse tinyResponse = (TinyResponse) response;
Tiny type = tinyResponse.getType();
if (type == Tiny.MULTIPLAYER_END || type == Tiny.RACE_END) {
endRace();
}
} else if (response instanceof ReorderResponse) {
processReorderResponse((ReorderResponse) response);
} else if (response instanceof RaceStartResponse) {
processRaceStartResponse((RaceStartResponse) response);
} else if (response instanceof ResultResponse) {
processResultResponse((ResultResponse) response);
}
} catch (Exception ex) {
log.error(ex.getMessage(), ex);
}
}
private void endRace() throws PersistenceException {
Race race = raceControl.getRace();
// if (race.hasRaceEntry() && race.getRaceEntry().getResults().size() > 0) {
calculate();
raceControl.getRace().reset();
raceControl.notifyRaceEventListener(new RaceEvent(Type.END, raceControl.getRace(), null));
persistence.flush();
log.info("Race has ended");
// }
}
private void processRaceStartResponse(RaceStartResponse response) throws IOException {
log.debug("start race: " + response);
RaceEntry raceEntry = raceControl.getRace().getRaceEntry();
raceEntry.setLaps(response.getRaceLaps());
raceEntry.setHours(response.getRaceHours());
raceEntry.setQualifyingMinutes(response.getQualifingMinutes());
raceEntry.setRacers(response.getNumberOfPlayers());
raceEntry.setTrack(response.getTrack().getShortname());
raceEntry.setWeather(getWeather(response.getWeather()));
raceEntry.setWind(getWind(response.getWind()));
log.info("Race start...");
try {
RaceEntry newRaceEntry = persistence.store(raceEntry);
//raceControl.getRace().setRaceEntry(newRaceEntry);
raceEntry.setId(newRaceEntry.getId());
} catch (PersistenceException e) {
log.error(e.getMessage(), e);
}
raceControl.notifyRaceEventListener(new RaceEvent(Type.STARTED, raceControl.getRace(), null));
log.debug("{}", raceEntry);
log.debug("with drivers {}", raceEntry.getDrivers());
}
private Wind getWind(org.openbakery.jinsim.Wind wind) {
int windValue = org.openbakery.jinsim.Wind.getValue(wind);
return Wind.getWind(windValue);
}
private Weather getWeather(org.openbakery.jinsim.Weather weather) {
int weatherValue = org.openbakery.jinsim.Weather.getValue(weather);
return Weather.getWeather(weatherValue);
}
private void processReorderResponse(ReorderResponse response) throws CloneNotSupportedException, PersistenceException {
// endRace();
Race race = raceControl.getRace();
log.debug("processReorderResponse: current race drivers {}", raceControl.getRace().getRaceDrivers());
int i = 1;
for (int playerId : response.getPlayerPositions()) {
if (playerId != 0) {
Driver driver = race.getDriverByPlayerId(playerId);
if (driver != null) {
driver = driver.clone();
driver.setStartingPosition(i++);
Driver newDriver = persistence.store(driver);
driver.setId(newDriver.getId());
race.addRaceDriver(driver);
}
}
}
log.debug("race drivers: " + race.getRaceDrivers());
}
private void processResultResponse(ResultResponse response) {
Race race = raceControl.getRace();
try {
Driver driver = race.getRaceDriver(response);
if (driver == null) {
log.error("Driver not found with id: " + response.getPlayerId());
}
Result result = new Result();
result.setBestLapTime(response.getBestLapTime().getTime());
result.setConfirmationFlags(response.getConfirmationFlags());
result.setLapsCompleted(response.getLapsDone());
result.setPitStops(response.getNumberPitStops());
result.setRaceTime(response.getTotalTime().getTime());
result.setPosition(response.getResultPosition() + 1);
race.getRaceEntry().addResult(result, driver);
// driver.setResult(result);
try {
Result newResult = persistence.store(result);
result.setId(newResult.getId());
} catch (PersistenceException e) {
log.error("unable to store result: " + result);
}
try {
if (driver.getPlayerId() > 0) {
persistence.store(driver);
}
} catch (PersistenceException e) {
log.error("unable to store driver: " + driver);
}
log.info("Result: " + result.toString(driver.getName()));
} catch (DriverNotFoundException e) {
log.error("Driver not found", e);
}
}
public void calculate() throws PersistenceException {
Race race = raceControl.getRace();
if (race.hasRaceEntry()) {
if (!race.getRaceEntry().isQualifying() && !race.getRaceEntry().isPractice()) {
calculatePositionInLaps();
addUnfinishedRacers();
}
}
}
private void addUnfinishedRacers() throws PersistenceException {
ArrayList<Result> allResults = new ArrayList<Result>();
Race race = raceControl.getRace();
for (Driver driver : race.getRaceDrivers()) {
Result result = driver.getResult();
int longestAttempt = driver.getLongestAttempt();
if (result == null || result.getLapsCompleted() < driver.getCompletedLaps(longestAttempt).size()) {
if (log.isDebugEnabled()) {
log.debug("add unfinished racer: " + driver);
}
long bestLapTime = Long.MAX_VALUE;
int completedLaps = 0;
int pitStops = 0;
long overallTime = 0;
for (Lap lap : driver.getCompletedLaps(longestAttempt)) {
if (lap.getTime() < bestLapTime) {
bestLapTime = lap.getTime();
}
completedLaps++;
overallTime = lap.getTotalTime();
}
if (overallTime != 0) {
if (result == null) {
result = new Result();
result.setConfirmationFlags(128);
}
result.setBestLapTime(bestLapTime);
result.setLapsCompleted(completedLaps);
result.setPitStops(pitStops);
result.setRaceTime(overallTime);
result.setPosition(0);
driver.setResult(result);
Result newResult = persistence.store(result);
result.setId(newResult.getId());
persistence.store(driver);
}
}
if (driver.getResult() != null) {
allResults.add(driver.getResult());
} else {
log.info("No Result for driver: " + driver);
}
}
if (allResults.size() > 0) {
Collections.sort(allResults, new ResultComparator());
for (int i = 0; i < allResults.size(); i++) {
Result result = allResults.get(i);
result.setPosition(i + 1);
persistence.store(result);
}
}
}
private void calculatePositionInLaps() {
ArrayList<Lap> previousLaps = null;
ArrayList<Lap> currentLaps = null;
ArrayList<Lap> positionList = new ArrayList<Lap>();
Race race = raceControl.getRace();
log.debug("race {}", race);
for (int i = 0; i < race.getRaceEntry().getLaps(); i++) {
currentLaps = new ArrayList<Lap>();
previousLaps = new ArrayList<Lap>();
positionList.clear();
for (Driver driver : race.getRaceDrivers()) {
// log.debug(driver);
Lap lap = driver.getCompletedLap(i);
log.debug("lap {}: {}", i, lap);
if (lap != null) {
currentLaps.add(lap);
if (i > 0) {
previousLaps.add(driver.getCompletedLap(i - 1));
}
}
}
if (previousLaps.size() == 0) {
for (int j = 0; j < currentLaps.size(); j++) {
Lap currentLap = currentLaps.get(j);
positionList.add(currentLap);
}
} else {
for (int j = 0; j < currentLaps.size(); j++) {
Lap currentLap = currentLaps.get(j);
if (currentLap.isFinished()) {
positionList.add(currentLap);
}
}
}
Collections.sort(positionList);
for (int j = 1; j <= positionList.size(); j++) {
Lap lap = positionList.get(j - 1);
lap.setPosition(j);
try {
persistence.store(lap);
} catch (PersistenceException e) {
log.error(e.getMessage(), e);
}
}
}
}
@Override
public void destroy() {
try {
endRace();
} catch (PersistenceException e) {
log.error(e.getMessage(), e);
}
}
}