/*
 * Copyright 2011-2020 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.converter;

import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import com.b2international.commons.http.ExtendedLocale;
import com.b2international.commons.options.Options;
import com.b2international.commons.options.OptionsBuilder;
import com.b2international.snowowl.core.domain.BranchContext;
import com.b2international.snowowl.snomed.common.SnomedRf2Headers;
import com.b2international.snowowl.snomed.core.domain.SnomedCoreComponent;
import com.b2international.snowowl.snomed.core.domain.refset.SnomedRefSetType;
import com.b2international.snowowl.snomed.core.domain.refset.SnomedReferenceSetMember;
import com.b2international.snowowl.snomed.core.domain.refset.SnomedReferenceSetMembers;
import com.b2international.snowowl.snomed.datastore.request.SnomedRefSetMemberSearchRequestBuilder;
import com.b2international.snowowl.snomed.datastore.request.SnomedRequests;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;

/**
 * @since 4.6
 */
class MembersExpander {
	
	private final BranchContext context;
	private final Options expand;
	private final List<ExtendedLocale> locales;

	public MembersExpander(BranchContext context, Options expand, List<ExtendedLocale> locales) {
		this.context = context;
		this.expand = expand;
		this.locales = locales;
	}
	
	void expand(List<? extends SnomedCoreComponent> results, Set<String> componentIds) {
		if (expand.containsKey("members")) {
			final Options membersOptions = expand.get("members", Options.class);
			
			// TODO better support for limit, offset, filtering, selection
			final SnomedRefSetMemberSearchRequestBuilder requestBuilder = SnomedRequests.prepareSearchMember()
				.all()
				.filterByReferencedComponent(componentIds);
			
			addActiveFilter(requestBuilder, membersOptions);
			addRefSetTypesFilter(requestBuilder, membersOptions);
			
			final OptionsBuilder propertyOptionsBuilder = OptionsBuilder.newBuilder();
			addCharacteristicTypeFilter(propertyOptionsBuilder, membersOptions);
			
			final Options propertyOptions = propertyOptionsBuilder.build();
			if (!propertyOptions.isEmpty()) {
				requestBuilder.filterByProps(propertyOptions);
			}
			
			final SnomedReferenceSetMembers matchingMembers = requestBuilder
				.setLocales(locales)
				.setExpand(membersOptions.get("expand", Options.class))
				.build()
				.execute(context);
			
			final Multimap<String, SnomedReferenceSetMember> membersByReferencedComponentId = Multimaps.index(matchingMembers, 
					input -> input.getReferencedComponent().getId());
			
			for (SnomedCoreComponent component : results) {
				final Collection<SnomedReferenceSetMember> members = membersByReferencedComponentId.get(component.getId());
				((SnomedCoreComponent) component).setMembers(new SnomedReferenceSetMembers(ImmutableList.copyOf(members), null, members.size(), members.size()));
			}
		}
	}

	private void addActiveFilter(SnomedRefSetMemberSearchRequestBuilder requestBuilder, Options membersOptions) {
		if (membersOptions.containsKey("active")) {
			requestBuilder.filterByActive(membersOptions.getBoolean("active"));
		}
	}

	private void addRefSetTypesFilter(SnomedRefSetMemberSearchRequestBuilder requestBuilder, Options membersOptions) {
		if (membersOptions.containsKey("refSetType")) {
			final Collection<String> refSetTypesAsString = membersOptions.getCollection("refSetType", String.class);
			final Iterable<SnomedRefSetType> refSetTypes = refSetTypesAsString.stream()
					.map(SnomedRefSetType::valueOf)
					.collect(Collectors.toSet());

			requestBuilder.filterByRefSetType(refSetTypes);
		}
	}

	private void addCharacteristicTypeFilter(OptionsBuilder propertyOptionsBuilder, Options membersOptions) {
		if (membersOptions.containsKey(SnomedRf2Headers.FIELD_CHARACTERISTIC_TYPE_ID)) {
			propertyOptionsBuilder.put(SnomedRf2Headers.FIELD_CHARACTERISTIC_TYPE_ID, 
					membersOptions.getCollection(SnomedRf2Headers.FIELD_CHARACTERISTIC_TYPE_ID, String.class));
		}
	}
}

@@ -17,17 +17,17 @@
 2011-202
-0
+2
  B2i Hea
@@ -2606,32 +2606,86 @@
 embersOptions);%0A
+%09%09%09addRefsetIdFilter(requestBuilder, membersOptions);%0A
 %09%09%09%0A%09%09%09final Opt
@@ -4780,10 +4780,316 @@
 %0A%09%09%7D%0A%09%7D%0A
+%09%0A%09private void addRefsetIdFilter(SnomedRefSetMemberSearchRequestBuilder requestBuilder, Options membersOptions) %7B%0A%09%09if (membersOptions.containsKey(SnomedRf2Headers.FIELD_REFSET_ID)) %7B%0A%09%09%09requestBuilder.filterByRefSet(membersOptions.getCollection(SnomedRf2Headers.FIELD_REFSET_ID, String.class));%0A%09%09%7D%0A%09%7D%0A%09%0A
 %7D%0A

support filtering of members during expand via refsetId...