package com.constellio.model.services.search.query.logical.valueCondition;
import static com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators.all;
import static com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators.allConditions;
import static com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators.any;
import static com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators.not;
import static com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators.query;
import static com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators.whereAny;
import static java.util.Arrays.asList;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import com.constellio.data.utils.AccentApostropheCleaner;
import com.constellio.model.entities.schemas.Metadata;
import com.constellio.model.entities.schemas.MetadataSchemaType;
import com.constellio.model.entities.schemas.Schemas;
import com.constellio.model.services.factories.ModelLayerFactory;
import com.constellio.model.services.parser.LanguageDetectionManager;
import com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators;
import com.constellio.model.services.search.query.logical.LogicalSearchValueCondition;
import com.constellio.model.services.search.query.logical.condition.ConditionTemplate;
import com.constellio.model.services.search.query.logical.condition.LogicalSearchCondition;
import com.constellio.model.services.search.query.logical.condition.LogicalSearchConditionBuilder;
import com.constellio.model.services.search.query.logical.criteria.IsEqualCriterion;
import com.constellio.model.services.search.query.logical.criteria.IsStartingWithTextCriterion;
import com.constellio.model.services.search.query.logical.ongoing.OngoingLogicalSearchCondition;
public class ConditionTemplateFactory {
private String collection;
private ModelLayerFactory modelLayerFactory;
public ConditionTemplateFactory(ModelLayerFactory modelLayerFactory, String collection) {
this.modelLayerFactory = modelLayerFactory;
this.collection = collection;
}
public static ConditionTemplate schemaTypeIs(MetadataSchemaType type) {
return schemaTypeIs(type.getCode());
}
public static ConditionTemplate schemaTypeIs(String type) {
return schemaTypeIsIn(asList(type));
}
public static ConditionTemplate schemaTypeIsIn(List<String> types) {
List<LogicalSearchValueCondition> schemaTypesCriteria = new ArrayList<>();
for (String type : types) {
schemaTypesCriteria.add(LogicalSearchQueryOperators.startingWithText(type));
}
return ConditionTemplate.field(Schemas.SCHEMA, any(schemaTypesCriteria));
}
public static ConditionTemplate schemaTypeIsNotIn(List<String> types) {
List<LogicalSearchValueCondition> schemaTypesCriteria = new ArrayList<>();
for (String type : types) {
schemaTypesCriteria.add(LogicalSearchQueryOperators.startingWithText(type));
}
return ConditionTemplate.field(Schemas.SCHEMA, not(any(schemaTypesCriteria)));
}
public static LogicalSearchConditionBuilder autocompleteFieldMatching(String text) {
return autocompleteFieldMatchingInMetadatas(text, asList(Schemas.SCHEMA_AUTOCOMPLETE_FIELD));
}
public static LogicalSearchConditionBuilder autocompleteFieldMatchingInMetadatas(String text, List<Metadata> metadatas) {
if (StringUtils.isBlank(text)) {
return new LogicalSearchConditionBuilder() {
@Override
public LogicalSearchCondition build(OngoingLogicalSearchCondition ongoing) {
return ongoing.where(Schemas.IDENTIFIER).isEqualTo("a38");
}
};
}
String cleanedText = AccentApostropheCleaner.removeAccents(text).toLowerCase();
String[] cleanedTextWords = cleanedText.split(" ");
final LogicalSearchCondition condition;
metadatas = new ArrayList<>(metadatas);
boolean schemaAutocomplete = false;
for (Metadata metadata : metadatas) {
schemaAutocomplete |= metadata.getLocalCode().equals(Schemas.SCHEMA_AUTOCOMPLETE_FIELD.getLocalCode());
}
if (!schemaAutocomplete) {
metadatas.add(Schemas.SCHEMA_AUTOCOMPLETE_FIELD);
}
if (cleanedTextWords.length == 1) {
if (cleanedText.endsWith(" ")) {
condition = whereAny(metadatas).isEqualTo(cleanedText.trim());
} else {
condition = whereAny(metadatas).isStartingWithText(cleanedText.trim());
}
} else {
List<LogicalSearchCondition> conditions = new ArrayList<>();
for (int i = 0; i < cleanedTextWords.length; i++) {
if (i + 1 == cleanedTextWords.length) {
if (cleanedText.endsWith(" ")) {
conditions.add(whereAny(metadatas).isEqualTo(cleanedTextWords[i]));
} else {
conditions.add(whereAny(metadatas).isStartingWithText(cleanedTextWords[i])
.orWhereAny(metadatas).isEqualTo(cleanedTextWords[i]));
}
} else {
conditions.add(whereAny(metadatas).isEqualTo(cleanedTextWords[i]));
}
}
condition = allConditions(conditions);
}
return new LogicalSearchConditionBuilder() {
@Override
public LogicalSearchCondition build(OngoingLogicalSearchCondition ongoing) {
return ongoing.where(condition);
}
};
}
public ConditionTemplate metadatasHasAnalyzedValue(String value, Metadata... metadatas) {
return metadatasHasAnalyzedValue(value, asList(metadatas));
}
public ConditionTemplate metadatasHasAnalyzedValue(String value, List<Metadata> metadatas) {
List<String> availableLanguages = modelLayerFactory.getCollectionsListManager().getCollectionLanguages(collection);
LanguageDetectionManager languageDetectionManager = modelLayerFactory.getLanguageDetectionManager();
String language =
availableLanguages.size() == 1 ? availableLanguages.get(0) : languageDetectionManager.tryDetectLanguage(value);
List<Metadata> searchedMetadatas = new ArrayList<>();
for (Metadata metadata : metadatas) {
if (!availableLanguages.contains(language) || language == null) {
for (String availableLanguage : availableLanguages) {
searchedMetadatas.add(metadata.getSearchableMetadataWithLanguage(availableLanguage));
}
} else {
searchedMetadatas.add(metadata.getSearchableMetadataWithLanguage(language));
}
}
return ConditionTemplate.anyField(searchedMetadatas, query(value));
}
public ConditionTemplate titleHasAnalyzedValue(String value) {
return metadatasHasAnalyzedValue(value, asList(Schemas.TITLE));
}
}