/*
 * Copyright 2011-2017 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.request;

import java.util.Set;

import javax.validation.constraints.NotNull;

import org.hibernate.validator.constraints.NotEmpty;

import com.b2international.snowowl.core.CoreTerminologyBroker;
import com.b2international.snowowl.core.domain.TransactionContext;
import com.b2international.snowowl.core.events.Request;
import com.b2international.snowowl.core.exceptions.BadRequestException;
import com.b2international.snowowl.snomed.SnomedConstants.Concepts;
import com.b2international.snowowl.snomed.core.store.SnomedComponents;
import com.b2international.snowowl.snomed.datastore.SnomedEditingContext;
import com.b2international.snowowl.snomed.datastore.SnomedRefSetEditingContext;
import com.b2international.snowowl.snomed.datastore.SnomedRefSetUtil;
import com.b2international.snowowl.snomed.snomedrefset.SnomedConcreteDataTypeRefSet;
import com.b2international.snowowl.snomed.snomedrefset.SnomedMappingRefSet;
import com.b2international.snowowl.snomed.snomedrefset.SnomedRefSet;
import com.b2international.snowowl.snomed.snomedrefset.SnomedRefSetType;
import com.b2international.snowowl.snomed.snomedrefset.SnomedRegularRefSet;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;

/**
 * @since 4.5
 */
final class SnomedRefSetCreateRequest implements Request<TransactionContext, String> {

	public static final Set<String> STRUCTURAL_ATTRIBUTE_VALUE_SETS = ImmutableSet.of(
			Concepts.REFSET_CONCEPT_INACTIVITY_INDICATOR,
			Concepts.REFSET_DESCRIPTION_INACTIVITY_INDICATOR,
			Concepts.REFSET_RELATIONSHIP_REFINABILITY);	
	
	@NotNull
	private final SnomedRefSetType type;
	
	@NotEmpty
	private final String referencedComponentType;
	
	private String mapTargetComponentType = CoreTerminologyBroker.UNSPECIFIED;
	
	private String identifierId;
	
	SnomedRefSetCreateRequest(SnomedRefSetType type, String referencedComponentType) {
		this.type = type;
		this.referencedComponentType = referencedComponentType;
	}

	SnomedRefSetType getRefSetType() {
		return type;
	}

	void setIdentifierId(String identifierId) {
		this.identifierId = identifierId;
	}
	
	void setMapTargetComponentType(String mapTargetComponentType) {
		this.mapTargetComponentType = mapTargetComponentType;
	}

	@Override
	public String execute(TransactionContext context) {
		RefSetSupport.checkType(type, referencedComponentType);
		
		if (Strings.isNullOrEmpty(identifierId)) {
			throw new BadRequestException("Reference set identifier ID may not be null or empty.");
		}
		
		// FIXME due to different resource lists we need access to the specific editing context (which will be removed later)
		final SnomedRefSetEditingContext refSetContext = context.service(SnomedEditingContext.class).getRefSetEditingContext();
		final SnomedRefSet refSet;
		
		switch (type) {
			case SIMPLE:
			case QUERY:
			case DESCRIPTION_TYPE:
			case MODULE_DEPENDENCY:
				refSet = createRegularRefSet(context);
				break;
			case CONCRETE_DATA_TYPE:
				refSet = createConcreteDomainRefSet(context);
				break;
			case COMPLEX_MAP:
			case EXTENDED_MAP:
			case SIMPLE_MAP:
				refSet = createMappingRefSet(context);
				break;
			case ASSOCIATION:
			case LANGUAGE:
				refSet = createStructuralRefSet(context);
				break;
			case ATTRIBUTE_VALUE:
				if (STRUCTURAL_ATTRIBUTE_VALUE_SETS.contains(identifierId)) {
					refSet = createStructuralRefSet(context);
				} else {
					refSet = createRegularRefSet(context);
				}
				break;
			default:
				throw new IllegalArgumentException("Unsupported reference set type " + type + " for reference set identifier " + identifierId);
		}
		
		refSetContext.add(refSet);
		return identifierId;
	}

	private SnomedRegularRefSet createRegularRefSet(TransactionContext context) {
		return SnomedComponents.newRegularReferenceSet()
			.withType(type)
			.withReferencedComponentType(referencedComponentType)
			.withIdentifierConceptId(identifierId)
			.build(context);
	}

	private SnomedConcreteDataTypeRefSet createConcreteDomainRefSet(TransactionContext context) {
		return SnomedComponents.newConcreteDomainReferenceSet()
			.withDataType(SnomedRefSetUtil.getDataType(identifierId))
			.withIdentifierConceptId(identifierId)
			.build(context);
	}

	private SnomedMappingRefSet createMappingRefSet(TransactionContext context) {
		return SnomedComponents.newMappingReferenceSet()
			.withType(type)
			.withIdentifierConceptId(identifierId)
			.withReferencedComponentType(referencedComponentType)
			.withMapTargetComponentType(mapTargetComponentType)
			.build(context);
	}

	private SnomedRefSet createStructuralRefSet(TransactionContext context) {
		return SnomedComponents.newStructuralReferenceSet()
				.withType(type)
				.withReferencedComponentType(referencedComponentType)
				.withIdentifierConceptId(identifierId)
				.build(context);
	}

}

@@ -21,9 +21,9 @@
 -201
-7
+8
  B2i
@@ -3471,23 +3471,57 @@
 PLE:
-%0A%09%09%09case QUERY:
+ //$FALL-THROUGH$%0A%09%09%09case QUERY: //$FALL-THROUGH$
 %0A%09%09%09
@@ -3538,24 +3538,41 @@
 IPTION_TYPE:
+ //$FALL-THROUGH$
 %0A%09%09%09case MOD
@@ -3746,24 +3746,41 @@
 COMPLEX_MAP:
+ //$FALL-THROUGH$
 %0A%09%09%09case EXT
@@ -3785,24 +3785,41 @@
 XTENDED_MAP:
+ //$FALL-THROUGH$
 %0A%09%09%09case SIM
@@ -3826,16 +3826,70 @@
 PLE_MAP:
+ //$FALL-THROUGH$%0A%09%09%09case SIMPLE_MAP_WITH_DESCRIPTION:
 %0A%09%09%09%09ref
@@ -5603,11 +5603,10 @@
 xt);%0A%09%7D%0A
-%0A
 %7D%0A

Add SnomedRefSetType literal to SnomedRefSetCreateRequest