/*
 * Copyright 2018 B2i Healthcare Pte Ltd, http://b2i.sg
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.b2international.snowowl.snomed.datastore.index.change;

import static com.google.common.collect.Sets.newHashSet;

import java.io.IOException;
import java.util.Set;

import com.b2international.index.Hits;
import com.b2international.index.query.Expressions;
import com.b2international.index.query.Expressions.ExpressionBuilder;
import com.b2international.index.query.Query;
import com.b2international.index.revision.RevisionSearcher;
import com.b2international.index.revision.StagingArea;
import com.b2international.snowowl.datastore.index.ChangeSetProcessorBase;
import com.b2international.snowowl.snomed.common.SnomedRf2Headers;
import com.b2international.snowowl.snomed.datastore.index.entry.SnomedComponentDocument;
import com.b2international.snowowl.snomed.datastore.index.entry.SnomedConceptDocument;
import com.b2international.snowowl.snomed.datastore.index.entry.SnomedDescriptionIndexEntry;
import com.b2international.snowowl.snomed.datastore.index.entry.SnomedRefSetMemberIndexEntry;
import com.b2international.snowowl.snomed.datastore.index.entry.SnomedRelationshipIndexEntry;

/**
 * Processes deleted container components and makes sure that components contained by the container will be deleted/inactivated etc. as well. 
 * 
 * @since 7.0
 */
public final class DetachedContainerChangeProcessor extends ChangeSetProcessorBase {

	public DetachedContainerChangeProcessor() {
		super("referring members");
	}

	@Override
	public void process(StagingArea staging, RevisionSearcher searcher) throws IOException {
		final Set<String> deletedCoreComponentIds = newHashSet();
		final Set<String> deletedConceptIds = newHashSet();
		
		staging.getRemovedObjects().values()
			.forEach(detachedObject -> {
				if (detachedObject instanceof SnomedComponentDocument) {
					String id = ((SnomedComponentDocument) detachedObject).getId();
					deletedCoreComponentIds.add(id);
					if (detachedObject instanceof SnomedConceptDocument) {
						deletedConceptIds.add(id);
					}
				}
			});
		
		if (deletedCoreComponentIds.isEmpty() && deletedConceptIds.isEmpty()) {
			return;
		}
		
		// deleting concepts should delete all of its descriptions, relationships, and inbound relationships
		for (Hits<SnomedDescriptionIndexEntry> hits : searcher.scroll(Query
				.select(SnomedDescriptionIndexEntry.class)
				.where(SnomedDescriptionIndexEntry.Expressions.concepts(deletedConceptIds))
				.limit(PAGE_SIZE)
				.build()))  {
			for (SnomedDescriptionIndexEntry description : hits) {
				deletedCoreComponentIds.add(description.getId());
				stageRemove(description);
			}
		}
		
		for (Hits<SnomedRelationshipIndexEntry> hits : searcher.scroll(Query
				.select(SnomedRelationshipIndexEntry.class)
				.where(Expressions.builder()
						.should(SnomedRelationshipIndexEntry.Expressions.sourceIds(deletedConceptIds))
						.should(SnomedRelationshipIndexEntry.Expressions.destinationIds(deletedConceptIds))
						.build())
				.limit(PAGE_SIZE)
				.build()))  {
			for (SnomedRelationshipIndexEntry relationship : hits) {
				deletedCoreComponentIds.add(relationship.getId());
				stageRemove(relationship);
			}
		}
		
		// deleting core components should delete all referring members as well
		ExpressionBuilder referringMembersQuery = Expressions.builder()
				.should(SnomedRefSetMemberIndexEntry.Expressions.referencedComponentIds(deletedCoreComponentIds))
				.should(SnomedRefSetMemberIndexEntry.Expressions.referenceSetId(deletedCoreComponentIds));
		
		SnomedRf2Headers.MEMBER_FIELDS_WITH_COMPONENT_ID.forEach(memberField -> {
			referringMembersQuery.should(Expressions.matchAny(memberField, deletedCoreComponentIds));
		});
		
		for (Hits<SnomedRefSetMemberIndexEntry> hits : searcher.scroll(Query
				.select(SnomedRefSetMemberIndexEntry.class)
				.where(referringMembersQuery.build())
				.limit(PAGE_SIZE)
				.build()))  {
			for (SnomedRefSetMemberIndexEntry member : hits) {
				stageRemove(member);
			}
		}
	}

}

@@ -13,16 +13,21 @@
 ght 2018
+-2019
  B2i Hea
@@ -4069,34 +4069,28 @@
 Id(deletedCo
-reComponen
+ncep
 tIds));%0A%09%09%0A%09

Use deletedConceptIds when searching for members to delete...