package javastory.server.channel;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import javastory.channel.ChannelCharacter;
import javastory.channel.CharacterTransfer;
import javastory.io.GamePacket;
import javastory.world.core.CheaterData;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
public class PlayerStorage {
private final Lock activePlayerLock = new ReentrantLock();
private final Lock pendingPlayerLock = new ReentrantLock();
private final Lock sessionsLock = new ReentrantLock();
private final Map<String, ChannelCharacter> nameToChar = Maps.newHashMap();
private final Map<Integer, ChannelCharacter> idToChar = Maps.newHashMap();
private final Map<Integer, String> sessions = Maps.newHashMap();
private final Map<Integer, CharacterTransfer> pendingTransfers;
private final ScheduledThreadPoolExecutor cleanupScheduler;
private static class TransferTimeout implements Runnable {
private final int characterId;
private final PlayerStorage storage;
public TransferTimeout(PlayerStorage storage, int characterId) {
this.storage = storage;
this.characterId = characterId;
}
@Override
public void run() {
this.storage.deregisterTransfer(this.characterId);
}
}
public PlayerStorage() {
this.pendingTransfers = Maps.newLinkedHashMap();
cleanupScheduler = new ScheduledThreadPoolExecutor(10);
}
public final boolean registerSession(final int characterId, final String sessionIP) {
Preconditions.checkNotNull(sessionIP);
this.sessionsLock.lock();
try {
if (!this.sessions.get(characterId).equals(sessionIP)) {
return false;
}
this.sessions.put(characterId, sessionIP);
return true;
} finally {
this.sessionsLock.unlock();
}
}
public final void deregisterSession(final int characterId) {
this.sessionsLock.lock();
try {
this.sessions.remove(characterId);
} finally {
this.sessionsLock.unlock();
}
}
public final boolean checkSession(final int characterId, final String sessionIP) {
Preconditions.checkNotNull(sessionIP);
this.sessionsLock.lock();
try {
return this.sessions.get(characterId).equals(sessionIP);
} finally {
this.sessionsLock.unlock();
}
}
public final void registerTransfer(final CharacterTransfer chr, final int characterId) {
this.pendingPlayerLock.lock();
try {
this.pendingTransfers.put(characterId, chr);
cleanupScheduler.schedule(new TransferTimeout(this, characterId), 1, TimeUnit.MINUTES);
} finally {
this.pendingPlayerLock.unlock();
}
}
public final void deregisterPlayer(final ChannelCharacter chr) {
this.activePlayerLock.lock();
try {
this.nameToChar.remove(chr.getName().toLowerCase());
this.idToChar.remove(chr.getId());
} finally {
this.activePlayerLock.unlock();
}
}
public final void deregisterTransfer(final int characterId) {
this.pendingPlayerLock.lock();
try {
this.pendingTransfers.remove(characterId);
} finally {
this.pendingPlayerLock.unlock();
}
}
public final CharacterTransfer getPendingTransfer(final int characterId) {
final CharacterTransfer transfer = this.pendingTransfers.get(characterId);
if (transfer != null) {
this.deregisterTransfer(characterId);
}
return transfer;
}
public final void registerPlayer(final ChannelCharacter chr) {
this.activePlayerLock.lock();
try {
this.nameToChar.put(chr.getName().toLowerCase(), chr);
this.idToChar.put(chr.getId(), chr);
} finally {
this.activePlayerLock.unlock();
}
}
public final ChannelCharacter getCharacterByName(final String name) {
return this.nameToChar.get(name.toLowerCase());
}
public final ChannelCharacter getCharacterById(final int id) {
return this.idToChar.get(id);
}
public final int getConnectedClients() {
return this.idToChar.size();
}
public final List<CheaterData> getCheaters() {
final List<CheaterData> cheaters = Lists.newArrayList();
this.activePlayerLock.lock();
try {
final Iterator<ChannelCharacter> itr = this.nameToChar.values().iterator();
ChannelCharacter chr;
while (itr.hasNext()) {
chr = itr.next();
final int points = chr.getCheatTracker().getPoints();
if (points <= 0) {
continue;
}
final String summary = chr.getCheatTracker().getSummary();
final String readableName = chr.getName().toUpperCase();
final String description = String.format("%s (%d) %s", readableName, points, summary);
cheaters.add(new CheaterData(points, description));
}
} finally {
this.activePlayerLock.unlock();
}
return cheaters;
}
public final void disconnectAll() {
this.activePlayerLock.lock();
try {
final Iterator<ChannelCharacter> itr = this.nameToChar.values().iterator();
ChannelCharacter chr;
while (itr.hasNext()) {
chr = itr.next();
if (!chr.isGM()) {
chr.getClient().disconnect();
chr.getClient().disconnect();
itr.remove();
}
}
} finally {
this.activePlayerLock.unlock();
}
}
public final String getOnlinePlayers(final boolean byGM) {
final StringBuilder sb = new StringBuilder();
if (byGM) {
this.activePlayerLock.lock();
try {
final Iterator<ChannelCharacter> itr = this.nameToChar.values().iterator();
final ChannelCharacter character = itr.next();
while (itr.hasNext()) {
sb.append(character.getWorldName().toUpperCase());
sb.append(", ");
}
} finally {
this.activePlayerLock.unlock();
}
} else {
this.activePlayerLock.lock();
try {
final Iterator<ChannelCharacter> itr = this.nameToChar.values().iterator();
ChannelCharacter chr;
while (itr.hasNext()) {
chr = itr.next();
if (!chr.isGM()) {
sb.append(chr.getWorldName().toUpperCase());
sb.append(", ");
}
}
} finally {
this.activePlayerLock.unlock();
}
}
return sb.toString();
}
public final void broadcastPacket(final GamePacket data) {
this.activePlayerLock.lock();
try {
final Iterator<ChannelCharacter> itr = this.nameToChar.values().iterator();
while (itr.hasNext()) {
itr.next().getClient().write(data);
}
} finally {
this.activePlayerLock.unlock();
}
}
public final void broadcastSmegaPacket(final GamePacket data) {
this.activePlayerLock.lock();
try {
final Iterator<ChannelCharacter> itr = this.nameToChar.values().iterator();
ChannelCharacter chr;
while (itr.hasNext()) {
chr = itr.next();
if (chr.getClient().isLoggedIn() && chr.getSmega()) {
chr.getClient().write(data);
}
}
} finally {
this.activePlayerLock.unlock();
}
}
public final void broadcastGMPacket(final GamePacket data) {
this.activePlayerLock.lock();
try {
final Iterator<ChannelCharacter> itr = this.nameToChar.values().iterator();
ChannelCharacter chr;
while (itr.hasNext()) {
chr = itr.next();
if (chr.getClient().isLoggedIn() && chr.isGM() && chr.isCallGM()) {
chr.getClient().write(data);
}
}
} finally {
this.activePlayerLock.unlock();
}
}
public Collection<ChannelCharacter> getAllCharacters() {
return this.nameToChar.values();
}
}