class MobilityModule extends Module implements IMobilityModule, IMobilityModuleController {

    @Override
    public double costForLevelingToLevel(final LevelType levelType)
            throws NotAuthenticatedException, NotObservableException {
        assertObservable();
        Tile location = getGameObject().getLocation().get();

        // Level up until we reach the target level.
        double cost = 0;
        LevelType currentLevel = location.getLevel().getType();
        if (levelType == currentLevel)
            return 0;
        while (true) {
            Optional<LevelType> newLevel = currentLevel.up();
            if (!newLevel.isPresent())
                break;

            Double currentLevelCost = levelingCost.get( EnumUtils.min( currentLevel, newLevel.get() ) );
            if (currentLevelCost == null)
                // Cannot level to this level.
                return Double.MAX_VALUE;

            currentLevel = newLevel.get();
            cost += currentLevelCost;

            if (currentLevel == levelType)
                return cost;
        }

        // Level down until we reach the target level.
        cost = 0;
        currentLevel = location.getLevel().getType();
        while (true) {
            Optional<LevelType> newLevel = currentLevel.down();
            if (!newLevel.isPresent())
                break;

            Double currentLevelCost = levelingCost.get( EnumUtils.min( currentLevel, newLevel.get() ) );
            if (currentLevelCost == null)
                // Cannot level to this level.
                return Double.MAX_VALUE;

            currentLevel = newLevel.get();
            cost += currentLevelCost;

            if (currentLevel == levelType)
                return cost;
        }

        // Unreachable code.
        throw new IllegalArgumentException( "Unsupported level type: " + levelType );
    }

    protected  MobilityModule(final ImmutableResourceCost resourceCost, final int movementSpeed, final Map<LevelType, Double> movementCost,
                             final Map<LevelType, Double> levelingCost);

}