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

import javax.validation.constraints.NotNull;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.b2international.snowowl.core.domain.TransactionContext;
import com.b2international.snowowl.core.events.BaseRequest;
import com.b2international.snowowl.core.events.metrics.Metrics;
import com.b2international.snowowl.core.events.metrics.Timer;
import com.b2international.snowowl.core.exceptions.AlreadyExistsException;
import com.b2international.snowowl.core.exceptions.BadRequestException;
import com.b2international.snowowl.core.exceptions.ComponentNotFoundException;
import com.b2international.snowowl.snomed.core.domain.ConstantIdStrategy;
import com.b2international.snowowl.snomed.core.domain.IdGenerationStrategy;
import com.b2international.snowowl.snomed.core.domain.RegisteringIdStrategy;
import com.b2international.snowowl.snomed.core.domain.ReservingIdStrategy;

/**
 * @since 4.0
 */
public abstract class BaseSnomedComponentCreateRequest extends BaseRequest<TransactionContext, String> implements SnomedComponentCreateRequest {

	private static final Logger LOGGER = LoggerFactory.getLogger(BaseSnomedComponentCreateRequest.class);
	
	/** 
	 * The maximum number of identifier service reservation calls (after which a namespace is known to be completely full). 
	 */
	private static final int ID_GENERATION_ATTEMPTS = 9999_9999;
	
	@NotNull
	private IdGenerationStrategy idGenerationStrategy;
	
	private String moduleId;

	@Override
	public IdGenerationStrategy getIdGenerationStrategy() {
		return idGenerationStrategy;
	}

	@Override
	public String getModuleId() {
		return moduleId;
	}

	void setIdGenerationStrategy(final IdGenerationStrategy idGenerationStrategy) {
		this.idGenerationStrategy = idGenerationStrategy;
	}

	void setModuleId(final String moduleId) {
		this.moduleId = moduleId;
	}
	
	@Override
	protected final Class<String> getReturnType() {
		return String.class;
	}

	protected final void ensureUniqueId(String type, TransactionContext context) {
		final Timer idGenerationTimer = context.service(Metrics.class).timer("idGeneration");
		try {
			idGenerationTimer.start();
			if (getIdGenerationStrategy() instanceof RegisteringIdStrategy) {
				final String componentId = getIdGenerationStrategy().generate(context);
				
				try {
					checkComponentExists(context, componentId);
					throw new AlreadyExistsException(type, componentId);
				} catch (ComponentNotFoundException e) {
					setIdGenerationStrategy(new ConstantIdStrategy(componentId));
					return;
				}
				
				LOGGER.warn("SCTID generation returned component id already in use: %s.  Requesting another...", componentId);
			}
			
			if (getIdGenerationStrategy() instanceof ReservingIdStrategy) {
				String componentId = null;
				
				for (int i = 0; i < ID_GENERATION_ATTEMPTS; i++) {
					componentId = getIdGenerationStrategy().generate(context);
					
					try {
						checkComponentExists(context, componentId);
					} catch (ComponentNotFoundException e) {
						setIdGenerationStrategy(new RegisteringIdStrategy(componentId));
						return;
					}
				}
				
				throw new BadRequestException("Couldn't generate unique identifier for %s after %d attempts.", type, ID_GENERATION_ATTEMPTS); 
			}
		} finally {
			idGenerationTimer.stop();
		}
	}

	protected abstract void checkComponentExists(TransactionContext context, final String componentId) throws ComponentNotFoundException;
}

@@ -3212,123 +3212,8 @@
 %09%09%09%0A
-%09%09%09%09LOGGER.warn(%22SCTID generation returned component id already in use: %25s.  Requesting another...%22, componentId);%0A
 %09%09%09%7D
@@ -3640,24 +3640,146 @@
 urn;%0A%09%09%09%09%09%7D%0A
+%09%09%09%09%09%0A%09%09%09%09%09LOGGER.warn(%22SCTID generation returned component id already in use: %25s.  Requesting another...%22, componentId);%0A
 %09%09%09%09%7D%0A%09%09%09%09%0A%09

move log.info call to its original place