package com.faforever.client.remote;
import com.faforever.client.api.FafApiAccessor;
import com.faforever.client.api.Ranked1v1Stats;
import com.faforever.client.api.RatingType;
import com.faforever.client.chat.PlayerInfoBean;
import com.faforever.client.chat.avatar.AvatarBean;
import com.faforever.client.chat.avatar.event.AvatarChangedEvent;
import com.faforever.client.config.CacheNames;
import com.faforever.client.connectivity.ConnectivityService;
import com.faforever.client.domain.RatingHistoryDataPoint;
import com.faforever.client.game.Faction;
import com.faforever.client.game.NewGameInfo;
import com.faforever.client.leaderboard.Ranked1v1EntryBean;
import com.faforever.client.map.MapBean;
import com.faforever.client.mod.ModInfoBean;
import com.faforever.client.net.ConnectionState;
import com.faforever.client.relay.GpgClientMessage;
import com.faforever.client.remote.domain.GameEndedMessage;
import com.faforever.client.remote.domain.GameLaunchMessage;
import com.faforever.client.remote.domain.LoginMessage;
import com.faforever.client.remote.domain.ServerMessage;
import com.google.common.eventbus.EventBus;
import javafx.beans.property.ReadOnlyObjectProperty;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import static java.lang.Long.parseLong;
import static java.time.LocalDateTime.ofEpochSecond;
import static java.time.ZoneOffset.UTC;
public class FafServiceImpl implements FafService {
@Resource
FafServerAccessor fafServerAccessor;
@Resource
FafApiAccessor fafApiAccessor;
@Resource
ConnectivityService connectivityService;
@Resource
ThreadPoolExecutor threadPoolExecutor;
@Resource
EventBus eventBus;
@Override
public <T extends ServerMessage> void addOnMessageListener(Class<T> type, Consumer<T> listener) {
fafServerAccessor.addOnMessageListener(type, listener);
}
@Override
@SuppressWarnings("unchecked")
public <T extends ServerMessage> void removeOnMessageListener(Class<T> type, Consumer<T> listener) {
fafServerAccessor.removeOnMessageListener(type, listener);
}
@Override
public CompletionStage<GameLaunchMessage> requestHostGame(NewGameInfo newGameInfo) {
return fafServerAccessor.requestHostGame(newGameInfo,
connectivityService.getRelayAddress(),
connectivityService.getExternalSocketAddress().getPort()
);
}
@Override
public ReadOnlyObjectProperty<ConnectionState> connectionStateProperty() {
return fafServerAccessor.connectionStateProperty();
}
@Override
public CompletionStage<GameLaunchMessage> requestJoinGame(int gameId, String password) {
return fafServerAccessor.requestJoinGame(gameId, password,
connectivityService.getRelayAddress(),
connectivityService.getExternalSocketAddress().getPort());
}
@Override
public CompletionStage<GameLaunchMessage> startSearchRanked1v1(Faction faction, int port) {
return fafServerAccessor.startSearchRanked1v1(faction, port, connectivityService.getRelayAddress());
}
@Override
public void stopSearchingRanked() {
fafServerAccessor.stopSearchingRanked();
}
@Override
public void initConnectivityTest(int port) {
fafServerAccessor.initConnectivityTest(port);
}
@Override
public void sendGpgMessage(GpgClientMessage message) {
fafServerAccessor.sendGpgMessage(message);
}
@Override
public CompletionStage<LoginMessage> connectAndLogIn(String username, String password) {
return fafServerAccessor.connectAndLogIn(username, password);
}
@Override
public void disconnect() {
fafServerAccessor.disconnect();
}
@Override
public void addFriend(PlayerInfoBean player) {
fafServerAccessor.addFriend(player.getId());
}
@Override
public void addFoe(PlayerInfoBean player) {
fafServerAccessor.addFoe(player.getId());
}
@Override
public void removeFriend(PlayerInfoBean player) {
fafServerAccessor.removeFriend(player.getId());
}
@Override
public void removeFoe(PlayerInfoBean player) {
fafServerAccessor.removeFoe(player.getId());
}
@Override
public Long getSessionId() {
return fafServerAccessor.getSessionId();
}
@Override
public CompletionStage<List<Ranked1v1EntryBean>> getRanked1v1Entries() {
return CompletableFuture.supplyAsync(() -> fafApiAccessor.getRanked1v1Entries(), threadPoolExecutor);
}
@Override
public CompletionStage<Ranked1v1Stats> getRanked1v1Stats() {
return CompletableFuture.supplyAsync(() -> fafApiAccessor.getRanked1v1Stats(), threadPoolExecutor);
}
@Override
public CompletionStage<Ranked1v1EntryBean> getRanked1v1EntryForPlayer(int playerId) {
return CompletableFuture.supplyAsync(() -> fafApiAccessor.getRanked1v1EntryForPlayer(playerId), threadPoolExecutor);
}
@Override
public void notifyGameEnded() {
fafServerAccessor.sendGpgMessage(new GameEndedMessage());
}
@Override
@Cacheable(CacheNames.MAPS)
public List<MapBean> getMaps() {
return fafApiAccessor.getMaps();
}
@Override
public MapBean findMapByName(String mapName) {
return fafApiAccessor.findMapByName(mapName);
}
@Override
@Cacheable(CacheNames.MODS)
public List<ModInfoBean> getMods() {
return fafApiAccessor.getMods();
}
@Override
public void reconnect() {
fafServerAccessor.reconnect();
}
@Override
public CompletionStage<List<MapBean>> getMostDownloadedMaps(int count) {
return CompletableFuture.supplyAsync(() -> fafApiAccessor.getMostDownloadedMaps(count), threadPoolExecutor);
}
@Override
public CompletionStage<List<MapBean>> getMostPlayedMaps(int count) {
return CompletableFuture.supplyAsync(() -> fafApiAccessor.getMostPlayedMaps(count), threadPoolExecutor);
}
@Override
public CompletionStage<List<MapBean>> getMostLikedMaps(int count) {
return CompletableFuture.supplyAsync(() -> fafApiAccessor.getBestRatedMaps(count), threadPoolExecutor);
}
@Override
public CompletionStage<List<MapBean>> getNewestMaps(int count) {
return CompletableFuture.supplyAsync(() -> fafApiAccessor.getNewestMaps(count), threadPoolExecutor);
}
@Override
public CompletionStage<List<AvatarBean>> getAvailableAvatars() {
return CompletableFuture.supplyAsync(() -> fafServerAccessor.getAvailableAvatars())
.thenApply(avatars -> avatars.stream()
.map(AvatarBean::fromAvatar)
.collect(Collectors.toList()));
}
@Override
public void selectAvatar(AvatarBean avatar) {
fafServerAccessor.selectAvatar(avatar == null ? null : avatar.getUrl());
eventBus.post(new AvatarChangedEvent(avatar));
}
@Override
@CacheEvict(CacheNames.MODS)
public void evictModsCache() {
// Nothing to see, please move along
}
@Cacheable(CacheNames.RATING_HISTORY)
@Override
public CompletableFuture<List<RatingHistoryDataPoint>> getRatingHistory(RatingType ratingType, int playerId) {
return CompletableFuture.supplyAsync(() -> fafApiAccessor.getRatingHistory(ratingType, playerId)
.getData().entrySet()
.stream()
.sorted((o1, o2) -> Long.compare(parseLong(o1.getKey()), parseLong(o2.getKey())))
.map(entry -> new RatingHistoryDataPoint(ofEpochSecond(parseLong(entry.getKey()), 0, UTC), entry.getValue().get(0), entry.getValue().get(1)))
.collect(Collectors.toList())
);
}
}