// Here we are not checking the bound, because we are assuming all data
// outside of bound has already been filtered out and doesn't exist in the
// PbfMemoryStore
private Optional<List<Relation>> processDefaultRelation(final Relation relation,
            final List<Long> parents)
    {
        final List<Relation> createdRelations = new ArrayList<>();
        final List<RelationMember> members = new ArrayList<>();
        boolean isModified = false;
        for (final RelationMember member : relation.getMembers())
        {
            switch (member.getMemberType())
            {
                case Way:
                    final List<Way> slicedWays = this.changeSet
                            .getCreatedWays(member.getMemberId());
                    if (slicedWays != null && !slicedWays.isEmpty())
                    {
                        isModified = true;
                        slicedWays.forEach(way -> members
                                .add(this.store.createRelationMember(member, way.getId())));
                    }
                    else
                    {
                        // Either the way is not sliced or way is outside of the supplied bound
                        members.add(member);
                    }
                    break;
                case Relation:
                    parents.add(relation.getId());
                    final Relation subRelation = this.store.getRelation(member.getMemberId());
                    // Check if we have the sub-relation in the store
                    if (subRelation == null)
                    {
                        // Put the member back into the relation. Missing members will be handled
                        // on a case by case basis
                        members.add(member);
                        break;
                    }
                    final Optional<List<Relation>> slicedMembers;
                    if (!parents.contains(subRelation.getId()))
                    {
                        slicedMembers = sliceRelation(subRelation, parents);
                    }
                    else
                    {
                        logger.error("Relation {} has a loop! Parent tree: {}", subRelation.getId(),
                                parents);
                        slicedMembers = Optional.empty();
                    }
                    if (slicedMembers.isPresent())
                    {
                        isModified = true;
                        slicedMembers.get().forEach(slicedRelation ->
                        {
                            members.add(this.store.createRelationMember(member,
                                    slicedRelation.getId()));
                        });
                    }
                    else
                    {
                        members.add(member);
                    }
                    break;
                default:
                    // Here we are not checking the bound, because we are assuming all data
                    // outside of bound has already been filtered out and doesn't exist in the
                    // PbfMemoryStore
                    members.add(member);
                    break;
            }
        }
        if (isModified)
        {
            // Modified by way slicing or relation slicing
            this.changeSet.addModifiedRelation(relation);
        }
        // Group entities by country
        final Map<String, List<RelationMember>> countryEntityMap = members.stream()
                .collect(Collectors.groupingBy(member ->
                {
                    final Entity entity = this.store.getEntity(member);
                    if (Objects.isNull(entity))
                    {
                        return ISOCountryTag.COUNTRY_MISSING;
                    }
                    else
                    {
                        final Optional<Tag> countryCodeTag = entity.getTags().stream()
                                .filter(tag -> tag.getKey().equals(ISOCountryTag.KEY)).findFirst();
                        if (countryCodeTag.isPresent())
                        {
                            return countryCodeTag.get().getValue();
                        }
                        else
                        {
                            return ISOCountryTag.COUNTRY_MISSING;
                        }
                    }
                }));
        final List<RelationMember> memberWithoutCountry;
        if (countryEntityMap.containsKey(ISOCountryTag.COUNTRY_MISSING))
        {
            memberWithoutCountry = countryEntityMap.remove(ISOCountryTag.COUNTRY_MISSING);
        }
        else
        {
            memberWithoutCountry = Collections.emptyList();
        }
        final int countryCount = countryEntityMap.size();
        if (countryCount == 0)
        {
            relation.getTags().add(new Tag(ISOCountryTag.KEY, ISOCountryTag.COUNTRY_MISSING));
            return Optional.empty();
        }
        else if (countryCount == 1)
        {
            // One country code found, assign it
            relation.getTags()
                    .add(new Tag(ISOCountryTag.KEY, countryEntityMap.keySet().iterator().next()));
            return Optional.empty();
        }
        else
        {
            // Muliple country codes found, implies relation crosses countries. As a 2 dimensional
            // feature, relation sliced should not have more than one piece for each country. For
            // now, for features without a country code (nodes and feature not covered by any
            // boundary), we put a copy for every sliced piece to ensure integrity.
            RuntimeCounter.relationSliced();
            this.changeSet.addDeletedRelation(relation);
            final CountrySlicingIdentifierFactory relationIdFactory = new CountrySlicingIdentifierFactory(
                    relation.getId());
            countryEntityMap.entrySet().forEach(entry ->
            {
                final List<RelationMember> candidateMembers = new ArrayList<>();
                candidateMembers.addAll(entry.getValue());
                candidateMembers.addAll(memberWithoutCountry);
                if (!candidateMembers.isEmpty())
                {
                    final Relation relationToAdd = this.store.createRelation(relation,
                            relationIdFactory.nextIdentifier(), candidateMembers);
                    // TODO Consider sharing CountryCode Tag objects
                    relationToAdd.getTags().add(new Tag(ISOCountryTag.KEY, entry.getKey()));
                    createdRelations.add(relationToAdd);
                    this.changeSet.addCreatedRelation(relationToAdd);
                }
            });
        }
        return Optional.of(createdRelations);
    }
break;
default:
// Here we are not checking the bound, because we are assuming all data
// outside of bound has already been filtered out and doesn't exist in the
// PbfMemoryStore
members.add(member);
break;
members.add(this.store.createRelationMember(member,
slicedRelation.getId()));
});
}
else
{
members.add(member);
}
break;
default:
// Here we are not checking the bound, because we are assuming all data
// outside of bound has already been filtered out and doesn't exist in the
// PbfMemoryStore
members.add(member);
break;
}
}
if (isModified)
{
// Modified by way slicing or relation slicing
this.changeSet.addModifiedRelation(relation);
}
// Group entities by country
{
logger.error("Relation {} has a loop! Parent tree: {}", subRelation.getId(),
parents);
slicedMembers = Optional.empty();
}
if (slicedMembers.isPresent())
{
isModified = true;
slicedMembers.get().forEach(slicedRelation ->
{
members.add(this.store.createRelationMember(member,
slicedRelation.getId()));
});
}
else
{
members.add(member);
}
break;
default:
// Here we are not checking the bound, because we are assuming all data
// outside of bound has already been filtered out and doesn't exist in the
// PbfMemoryStore
members.add(member);
break;
}
}
if (isModified)
{
// Modified by way slicing or relation slicing
this.changeSet.addModifiedRelation(relation);
}
// Group entities by country
final Map<String, List<RelationMember>> countryEntityMap = members.stream()
.collect(Collectors.groupingBy(member ->
{
final Entity entity = this.store.getEntity(member);
if (Objects.isNull(entity))
{
return ISOCountryTag.COUNTRY_MISSING;
}
else
{