package org.ggp.base.util.statemachine.cache;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.ggp.base.util.gdl.grammar.Gdl;
import org.ggp.base.util.statemachine.MachineState;
import org.ggp.base.util.statemachine.Move;
import org.ggp.base.util.statemachine.Role;
import org.ggp.base.util.statemachine.StateMachine;
import org.ggp.base.util.statemachine.exceptions.GoalDefinitionException;
import org.ggp.base.util.statemachine.exceptions.MoveDefinitionException;
import org.ggp.base.util.statemachine.exceptions.TransitionDefinitionException;
import com.google.common.collect.ImmutableList;
public final class CachedStateMachine extends StateMachine
{
private final StateMachine backingStateMachine;
private final TtlCache<MachineState, Entry> ttlCache;
private final class Entry
{
public Map<Role, Integer> goals;
public Map<Role, List<Move>> moves;
public Map<List<Move>, MachineState> nexts;
public Boolean terminal;
public Entry()
{
goals = new HashMap<Role, Integer>();
moves = new HashMap<Role, List<Move>>();
nexts = new HashMap<List<Move>, MachineState>();
terminal = null;
}
}
public CachedStateMachine(StateMachine backingStateMachine)
{
this.backingStateMachine = backingStateMachine;
ttlCache = new TtlCache<MachineState, Entry>(1);
}
private Entry getEntry(MachineState state)
{
if (!ttlCache.containsKey(state))
{
ttlCache.put(state, new Entry());
}
return ttlCache.get(state);
}
@Override
public int getGoal(MachineState state, Role role) throws GoalDefinitionException
{
Entry entry = getEntry(state);
synchronized (entry)
{
if (!entry.goals.containsKey(role))
{
entry.goals.put(role, backingStateMachine.getGoal(state, role));
}
return entry.goals.get(role);
}
}
@Override
public List<Move> getLegalMoves(MachineState state, Role role) throws MoveDefinitionException
{
Entry entry = getEntry(state);
synchronized (entry)
{
if (!entry.moves.containsKey(role))
{
entry.moves.put(role, ImmutableList.copyOf(backingStateMachine.getLegalMoves(state, role)));
}
return entry.moves.get(role);
}
}
@Override
public MachineState getNextState(MachineState state, List<Move> moves) throws TransitionDefinitionException
{
Entry entry = getEntry(state);
synchronized (entry)
{
if (!entry.nexts.containsKey(moves))
{
entry.nexts.put(moves, backingStateMachine.getNextState(state, moves));
}
return entry.nexts.get(moves);
}
}
@Override
public boolean isTerminal(MachineState state)
{
Entry entry = getEntry(state);
synchronized (entry)
{
if (entry.terminal == null)
{
entry.terminal = backingStateMachine.isTerminal(state);
}
return entry.terminal;
}
}
@Override
public void doPerMoveWork()
{
prune();
}
public void prune()
{
ttlCache.prune();
}
@Override
public void initialize(List<Gdl> description) {
backingStateMachine.initialize(description);
}
@Override
public List<Role> getRoles() {
// TODO(schreib): Should this be cached as well?
return backingStateMachine.getRoles();
}
@Override
public MachineState getInitialState() {
// TODO(schreib): Should this be cached as well?
return backingStateMachine.getInitialState();
}
}