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);
    }
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
                    {
                       
                        members.add(member);
                    }
                    break;
                case Relation:
                    parents.add(relation.getId());
                    final Relation subRelation = this.store.getRelation(member.getMemberId());
                   
                    if (subRelation == null)
                    {
                       
                       
                        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:
                   
                   
                   
                    members.add(member);
                    break;
            }
        }
        if (isModified)
        {
           
            this.changeSet.addModifiedRelation(relation);
        }
       
        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)
        {
           
            relation.getTags()
                    .add(new Tag(ISOCountryTag.KEY, countryEntityMap.keySet().iterator().next()));
            return Optional.empty();
        }
        else
        {
           
           
           
           
            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);
                   
                    relationToAdd.getTags().add(new Tag(ISOCountryTag.KEY, entry.getKey()));
                    createdRelations.add(relationToAdd);
                    this.changeSet.addCreatedRelation(relationToAdd);
                }
            });
        }
        return Optional.of(createdRelations);
    }
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 { members.add(member); } break; case relation: parents.add(relation.getid()); final relation subrelation = this.store.getrelation(member.getmemberid()); if (subrelation == null) { 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: members.add(member); break; } } if (ismodified) { this.changeset.addmodifiedrelation(relation); } 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) { relation.gettags() .add(new tag(isocountrytag.key, countryentitymap.keyset().iterator().next())); return optional.empty(); } else { 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); relationtoadd.gettags().add(new tag(isocountrytag.key, entry.getkey())); createdrelations.add(relationtoadd); this.changeset.addcreatedrelation(relationtoadd); } }); } return optional.of(createdrelations); }