package com.constellio.app.services.records;
import static com.constellio.app.ui.i18n.i18n.$;
import static com.constellio.model.entities.Language.withCode;
import static com.constellio.model.entities.schemas.MetadataValueType.REFERENCE;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import com.constellio.app.extensions.AppLayerExtensions;
import com.constellio.app.extensions.sequence.AvailableSequence;
import com.constellio.app.services.factories.AppLayerFactory;
import com.constellio.data.utils.KeySetMap;
import com.constellio.model.entities.Language;
import com.constellio.model.entities.records.Record;
import com.constellio.model.entities.schemas.Metadata;
import com.constellio.model.entities.schemas.MetadataSchema;
import com.constellio.model.entities.schemas.MetadataSchemaType;
import com.constellio.model.entities.schemas.MetadataSchemaTypes;
import com.constellio.model.entities.schemas.entries.SequenceDataEntry;
import com.constellio.model.services.collections.CollectionsListManager;
import com.constellio.model.services.schemas.MetadataSchemasManager;
import com.constellio.model.services.schemas.SchemaUtils;
public class AvailableSequencesServices {
AppLayerFactory appLayerFactory;
AppLayerExtensions extensions;
MetadataSchemasManager metadataSchemasManager;
CollectionsListManager collectionsListManager;
public AvailableSequencesServices(AppLayerFactory appLayerFactory) {
this.appLayerFactory = appLayerFactory;
extensions = this.appLayerFactory.getExtensions();
metadataSchemasManager = appLayerFactory.getModelLayerFactory().getMetadataSchemasManager();
collectionsListManager = appLayerFactory.getModelLayerFactory().getCollectionsListManager();
}
public List<AvailableSequence> getAvailableSequencesForRecord(Record record) {
List<AvailableSequence> availableSequences = new ArrayList<>();
availableSequences.addAll(appLayerFactory.getExtensions().forCollectionOf(record).getAvailableSequencesForRecord(record));
availableSequences.addAll(getAvailableSequencesUsingSchemaTypeOn(record));
return withoutDuplicates(availableSequences);
}
public List<AvailableSequence> getAvailableGlobalSequences() {
List<AvailableSequence> availableSequences = new ArrayList<>();
availableSequences.addAll(extensions.getSystemWideExtensions().getAvailableSequences());
availableSequences.addAll(getAvailableSequencesUsingCollectionsSchemaTypes());
return withoutDuplicates(availableSequences);
}
private List<AvailableSequence> getAvailableSequencesUsingSchemaTypeOn(Record record) {
List<AvailableSequence> availableSequences = new ArrayList<>();
MetadataSchemaTypes types = metadataSchemasManager.getSchemaTypes(record.getCollection());
Set<String> typesWithSequenceFeedingRecord = new HashSet<>();
for (MetadataSchemaType schemaType : types.getSchemaTypes()) {
for (Metadata metadata : schemaType.getAllMetadatas().onlySequence()) {
SequenceDataEntry dataEntry = (SequenceDataEntry) metadata.getDataEntry();
if (dataEntry.getMetadataProvidingSequenceCode() != null) {
MetadataSchema schema = types.getSchema(metadata.getSchemaCode());
Metadata metadataProvidingSequence = schema.getMetadata(dataEntry.getMetadataProvidingSequenceCode());
if (metadataProvidingSequence.getType() == REFERENCE) {
if (record.isOfSchemaType(metadataProvidingSequence.getAllowedReferences().getTypeWithAllowedSchemas())) {
typesWithSequenceFeedingRecord.add(new SchemaUtils().getSchemaTypeCode(schema.getCode()));
}
}
}
}
}
if (!typesWithSequenceFeedingRecord.isEmpty()) {
AvailableSequence seq = new AvailableSequence(record.getId(),
getAvailableSequenceLabelForTypes(types, typesWithSequenceFeedingRecord));
availableSequences.add(seq);
}
return availableSequences;
}
private Map<Language, String> getAvailableSequenceLabelForTypes(MetadataSchemaTypes types,
Set<String> typesWithSequenceFeedingRecord) {
Map<Language, String> labels = new HashMap<>();
for (Language language : types.getLanguages()) {
StringBuilder stringBuilder = new StringBuilder();
if (typesWithSequenceFeedingRecord.size() > 1) {
stringBuilder.append($("AvailableSequencesServices.sequenceForTypes") + " ");
} else {
stringBuilder.append($("AvailableSequencesServices.sequenceForType") + " ");
}
List<String> typeLabels = new ArrayList<>();
for (Iterator<String> i = typesWithSequenceFeedingRecord.iterator(); i.hasNext(); ) {
String typeWithSequenceFeedingRecord = i.next();
MetadataSchemaType type = types.getSchemaType(typeWithSequenceFeedingRecord);
typeLabels.add(type.getLabel(language));
}
Collections.sort(typeLabels);
stringBuilder.append(StringUtils.join(typeLabels, ", "));
labels.put(language, stringBuilder.toString());
}
return labels;
}
private List<AvailableSequence> getAvailableSequencesUsingCollectionsSchemaTypes() {
Language mainLanguage = withCode(appLayerFactory.getModelLayerFactory().getConfiguration().getMainDataLanguage());
List<AvailableSequence> availableSequences = new ArrayList<>();
KeySetMap<String, String> globalSequencesAndTypesUsingIt = new KeySetMap<>();
for (String collection : collectionsListManager.getCollectionsExcludingSystem()) {
MetadataSchemaTypes types = metadataSchemasManager.getSchemaTypes(collection);
for (MetadataSchemaType type : types.getSchemaTypes()) {
for (Metadata metadata : type.getAllMetadatas().onlySequence()) {
SequenceDataEntry dataEntry = (SequenceDataEntry) metadata.getDataEntry();
if (dataEntry.getFixedSequenceCode() != null) {
globalSequencesAndTypesUsingIt.add(dataEntry.getFixedSequenceCode(), type.getLabel(mainLanguage));
}
}
}
}
for (Map.Entry<String, Set<String>> entry : globalSequencesAndTypesUsingIt.getMapEntries()) {
StringBuilder labelBuilder = new StringBuilder();
if (entry.getValue().size() > 1) {
labelBuilder.append($("AvailableSequencesServices.sequenceForTypes") + " ");
} else {
labelBuilder.append($("AvailableSequencesServices.sequenceForType") + " ");
}
List<String> typeLabels = new ArrayList<>(entry.getValue());
Collections.sort(typeLabels);
labelBuilder.append(StringUtils.join(typeLabels, ", "));
Map<Language, String> languageStringMap = new HashMap<>();
languageStringMap.put(mainLanguage, labelBuilder.toString());
availableSequences.add(new AvailableSequence(entry.getKey(), languageStringMap));
}
return availableSequences;
}
private List<AvailableSequence> withoutDuplicates(List<AvailableSequence> sequences) {
Set<String> codes = new HashSet<>();
List<AvailableSequence> availableSequences = new ArrayList<>();
for (AvailableSequence sequence : sequences) {
if (!codes.contains(sequence.getCode())) {
codes.add(sequence.getCode());
availableSequences.add(sequence);
}
}
return availableSequences;
}
}