/*
 * Copyright 2011-2015 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.update;

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

import java.util.Collection;
import java.util.Set;

import org.apache.lucene.document.Document;

import com.b2international.snowowl.datastore.index.DocumentUpdaterBase;
import com.b2international.snowowl.datastore.index.mapping.IndexField;
import com.b2international.snowowl.snomed.datastore.index.mapping.SnomedDocumentBuilder;
import com.b2international.snowowl.snomed.datastore.index.mapping.SnomedMappings;
import com.b2international.snowowl.snomed.datastore.index.refset.RefSetMemberChange;
import com.b2international.snowowl.snomed.snomedrefset.SnomedRefSetType;

/**
 * @since 4.3
 */
public class ReferenceSetMembershipUpdater extends DocumentUpdaterBase<SnomedDocumentBuilder> {

	private Collection<RefSetMemberChange> memberChanges;

	public ReferenceSetMembershipUpdater(String componentId, Collection<RefSetMemberChange> memberChanges) {
		super(componentId);
		this.memberChanges = memberChanges;
	}

	@Override
	public void doUpdate(SnomedDocumentBuilder doc) {
		Document document = doc.build();
		final IndexField<Long> referringRefSetId = SnomedMappings.conceptReferringRefSetId();
		final IndexField<Long> referringMappingRefSetId = SnomedMappings.conceptReferringMappingRefSetId();
		
		// get reference set membership fields
		final Set<Long> referencingRefSetIds = newHashSet(referringRefSetId.getValues(document));
		// get reference set mapping membership fields
		final Set<Long> mappingReferencingRefSetIds = newHashSet(referringMappingRefSetId.getValues(document));
		
		// remove all fields
		doc.removeAll(referringRefSetId);
		
		// mapping fields as well
		doc.removeAll(referringMappingRefSetId);
		
		// merge reference set membership with the changes extracted from the transaction, if any.
		// FIXME: Maybe run the iteration twice to add everything, then remove everything?
		for (final RefSetMemberChange change : memberChanges) {
			switch (change.getChangeKind()) {
				case ADDED:
					if (SnomedRefSetType.SIMPLE.equals(change.getType()) || SnomedRefSetType.ATTRIBUTE_VALUE.equals(change.getType())) {
						referencingRefSetIds.add(change.getRefSetId());
					} else if (SnomedRefSetType.SIMPLE_MAP.equals(change.getType())) {
						mappingReferencingRefSetIds.add(change.getRefSetId());
					}
					break;
				case REMOVED:
					if (SnomedRefSetType.SIMPLE.equals(change.getType()) || SnomedRefSetType.ATTRIBUTE_VALUE.equals(change.getType())) {
						referencingRefSetIds.remove(change.getRefSetId());
					} else if (SnomedRefSetType.SIMPLE_MAP.equals(change.getType())) {
						mappingReferencingRefSetIds.remove(change.getRefSetId());
					}
					break;
				default:
					throw new IllegalArgumentException("Unknown reference set member change kind: " + change.getChangeKind());
			}
		}
		
		// re-add reference set membership fields
		for (final long refSetId : referencingRefSetIds) {
			doc.conceptReferringRefSetId(refSetId);
		}
		// re-add mapping reference set membership fields
		for (final long refSetId : mappingReferencingRefSetIds) {
			doc.conceptReferringMappingRefSetId(refSetId);
		}
	}
}

@@ -700,108 +700,28 @@
 ort 
-static com.google.common.collect.Sets.newHashSet;%0A%0Aimport java.util.Collection;%0Aimport java.util.Set
+java.util.Collection
 ;%0A%0Ai
@@ -1235,16 +1235,106 @@
 SetType;
+%0Aimport com.google.common.collect.HashMultiset;%0Aimport com.google.common.collect.Multiset;
 %0A%0A/**%0A *
@@ -2003,33 +2003,38 @@
  fields%0A%09%09final 
-S
+Multis
 et%3CLong%3E referen
@@ -2045,34 +2045,43 @@
 RefSetIds = 
-new
 Hash
-Set
+Multiset.create
 (referringRe
@@ -2166,17 +2166,22 @@
 %09%09final 
-S
+Multis
 et%3CLong%3E
@@ -2215,18 +2215,27 @@
 s = 
-new
 Hash
-Set
+Multiset.create
 (ref
@@ -2514,93 +2514,8 @@
 ny.%0A
-%09%09// FIXME: Maybe run the iteration twice to add everything, then remove everything?%0A
 %09%09fo
@@ -2963,24 +2963,312 @@
 se REMOVED:%0A
+%09%09%09%09%09break;%0A%09%09%09%09default:%0A%09%09%09%09%09throw new IllegalArgumentException(%22Unknown reference set member change kind: %22 + change.getChangeKind());%0A%09%09%09%7D%0A%09%09%7D%0A%0A%09%09for (final RefSetMemberChange change : memberChanges) %7B%0A%09%09%09switch (change.getChangeKind()) %7B%0A%09%09%09%09case ADDED:%0A%09%09%09%09%09break;%0A%09%09%09%09case REMOVED:%0A
 %09%09%09%09%09if (Sno
@@ -3870,16 +3870,19 @@
 d);%0A%09%09%7D%0A
+%09%09%0A
 %09%09// re-

Allow multiple memberships for the same reference set...