package ca.uhn.fhir.jpa.search.elastic;

import ca.uhn.fhir.jpa.api.config.DaoConfig;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.search.backend.elasticsearch.index.layout.IndexLayoutStrategy;
import org.hibernate.search.backend.elasticsearch.logging.impl.Log;
import org.hibernate.search.util.common.logging.impl.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.invoke.MethodHandles;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * This class instructs hibernate search on how to create index names for indexed entities.
 * In our case, we use this class to add an optional prefix to all indices which are created, which can be controlled via
 * {@link DaoConfig#setElasticSearchIndexPrefix(String)}.
 */
@Service
public class IndexNamePrefixLayoutStrategy implements IndexLayoutStrategy {

	@Autowired
	private DaoConfig myDaoConfig;

	static final Log log = (Log) LoggerFactory.make(Log.class, MethodHandles.lookup());
	public static final String NAME = "prefix";
	public static final Pattern UNIQUE_KEY_EXTRACTION_PATTERN = Pattern.compile("(.*)-\\d{6}");

	public String createInitialElasticsearchIndexName(String hibernateSearchIndexName) {
		return addPrefixIfNecessary(hibernateSearchIndexName + "-000001");
	}

	public String createWriteAlias(String hibernateSearchIndexName) {
		return addPrefixIfNecessary(hibernateSearchIndexName +"-write");
	}

	public String createReadAlias(String hibernateSearchIndexName) {
		return addPrefixIfNecessary(hibernateSearchIndexName + "-read");
	}

	private String addPrefixIfNecessary(String theCandidateName) {

		if (!StringUtils.isBlank(myDaoConfig.getElasticSearchIndexPrefix())) {
			return myDaoConfig.getElasticSearchIndexPrefix() + "-" + theCandidateName;
		} else {
			return theCandidateName;
		}
	}

	public String extractUniqueKeyFromHibernateSearchIndexName(String hibernateSearchIndexName) {
		return hibernateSearchIndexName;
	}

	public String extractUniqueKeyFromElasticsearchIndexName(String elasticsearchIndexName) {
		Matcher matcher = UNIQUE_KEY_EXTRACTION_PATTERN.matcher(elasticsearchIndexName);
		if (!matcher.matches()) {
			throw log.invalidIndexPrimaryName(elasticsearchIndexName, UNIQUE_KEY_EXTRACTION_PATTERN);
		} else {
			String candidateUniqueKey= matcher.group(1);
			return removePrefixIfNecessary(candidateUniqueKey);
		}
	}

	private String removePrefixIfNecessary(String theCandidateUniqueKey) {
		if (!StringUtils.isBlank(myDaoConfig.getElasticSearchIndexPrefix())) {
			return theCandidateUniqueKey.replace(myDaoConfig.getElasticSearchIndexPrefix() + "-", "");
		} else {
			return theCandidateUniqueKey;
		}
	}
}

@@ -34,16 +34,67 @@
 astic;%0A%0A
+import ca.uhn.fhir.context.ConfigurationException;%0A
 import c
@@ -1743,16 +1743,47 @@
 Name) %7B%0A
+%09%09validateDaoConfigIsPresent();
 %0A%09%09if (!
@@ -2596,16 +2596,48 @@
 eKey) %7B%0A
+%09%09validateDaoConfigIsPresent();%0A
 %09%09if (!S
@@ -2846,10 +2846,365 @@
 %0A%09%09%7D%0A%09%7D%0A
+%09private void validateDaoConfigIsPresent() %7B%0A%09%09if (myDaoConfig == null) %7B%0A%09%09%09throw new ConfigurationException(%22While attempting to boot HAPI FHIR, the Hibernate Search bootstrapper failed to find the DaoConfig. This probably means Hibernate Search has been recently upgraded, or somebody modified HapiFhirLocalContainerEntityManagerFactoryBean.%22);%0A%09%09%7D%0A%09%7D%0A
 %7D%0A

Throw error if misconfigured