package com.constellio.model.services.schemas;
import static com.constellio.data.utils.LangUtils.compareStrings;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import com.constellio.model.entities.Language;
import com.constellio.model.entities.schemas.Metadata;
import com.constellio.model.entities.schemas.MetadataValueType;
import com.constellio.model.entities.schemas.Schemas;
import com.constellio.model.entities.schemas.entries.DataEntryType;
public class MetadataList implements List<Metadata> {
boolean readOnly = false;
List<Metadata> nestedList = new ArrayList<>();
Map<String, Metadata> localCodeIndex = new HashMap<>();
Map<String, Metadata> codeIndex = new HashMap<>();
Map<String, Metadata> datastoreCodeIndex = new HashMap<>();
public MetadataList() {
super();
}
public MetadataList(Metadata... metadatas) {
super();
addAll(Arrays.asList(metadatas));
}
public MetadataList(Collection<? extends Metadata> collection) {
super();
addAll(collection);
}
@Override
public int size() {
return nestedList.size();
}
@Override
public boolean isEmpty() {
return nestedList.isEmpty();
}
@Override
public boolean contains(Object o) {
if (o instanceof Metadata) {
String code = ((Metadata) o).getInheritanceCode();
return codeIndex.containsKey(code);
} else {
return false;
}
}
@Override
public Iterator<Metadata> iterator() {
return nestedList.iterator();
}
@Override
public Object[] toArray() {
return nestedList.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return nestedList.toArray(a);
}
@Override
public boolean add(Metadata metadata) {
ensureNotReadOnly();
if (!contains(metadata)) {
addToIndex(metadata);
return nestedList.add(metadata);
} else {
return false;
}
}
@Override
public boolean remove(Object o) {
ensureNotReadOnly();
if (o instanceof Metadata) {
removeFromIndex((Metadata) o);
}
return nestedList.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
ensureNotReadOnly();
return nestedList.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends Metadata> c) {
ensureNotReadOnly();
boolean added = false;
for (Metadata metadata : c) {
if (!localCodeIndex.containsKey(metadata.getLocalCode())) {
addToIndex(metadata);
added = nestedList.add(metadata);
}
}
return added;
}
@Override
public boolean addAll(int index, Collection<? extends Metadata> c) {
ensureNotReadOnly();
boolean added = false;
for (Metadata metadata : c) {
if (!localCodeIndex.containsKey(metadata.getLocalCode())) {
addToIndex(metadata);
nestedList.add(index, metadata);
added = true;
}
index++;
}
return added;
}
@Override
public boolean removeAll(Collection<?> c) {
ensureNotReadOnly();
for (Object object : c) {
removeFromIndex((Metadata) object);
}
return nestedList.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
ensureNotReadOnly();
retainAllInIndexes(c);
return nestedList.retainAll(c);
}
@Override
public void clear() {
ensureNotReadOnly();
clearIndexes();
nestedList.clear();
}
@Override
public boolean equals(Object o) {
return nestedList.equals(o) || ((o instanceof MetadataList) && nestedList.equals(((MetadataList) o).nestedList));
}
@Override
public int hashCode() {
return nestedList.hashCode();
}
@Override
public Metadata get(int index) {
return nestedList.get(index);
}
@Override
public Metadata set(int index, Metadata element) {
ensureNotReadOnly();
setIndexes(index, element);
return nestedList.set(index, element);
}
@Override
public void add(int index, Metadata element) {
ensureNotReadOnly();
if (!localCodeIndex.containsKey(element.getLocalCode())) {
addToIndex(element);
nestedList.add(index, element);
}
}
@Override
public Metadata remove(int index) {
ensureNotReadOnly();
removeFromIndex(nestedList.get(index));
return nestedList.remove(index);
}
@Override
public int indexOf(Object o) {
if (o instanceof Metadata) {
String searchedLocalCode = ((Metadata) o).getLocalCode();
List<Metadata> nestedList1 = this.nestedList;
for (int i = 0; i < nestedList1.size(); i++) {
Metadata metadata = nestedList1.get(i);
if (metadata.getLocalCode().equals(searchedLocalCode)) {
return i;
}
}
}
return -1;
}
@Override
public int lastIndexOf(Object o) {
return nestedList.lastIndexOf(o);
}
@Override
public ListIterator<Metadata> listIterator() {
return nestedList.listIterator();
}
@Override
public ListIterator<Metadata> listIterator(int index) {
return nestedList.listIterator(index);
}
@Override
public List<Metadata> subList(int fromIndex, int toIndex) {
ensureNotReadOnly();
return nestedList.subList(fromIndex, toIndex);
}
public List<String> toMetadatasCodesList() {
return new SchemaUtils().toMetadataCodes(this);
}
public List<String> toLocalCodesList() {
return new SchemaUtils().toMetadataLocalCodes(this);
}
public MetadataList onlyReferencesToType(String schemaTypeCode) {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.getType() == MetadataValueType.REFERENCE && metadata.getAllowedReferences().getTypeWithAllowedSchemas()
.equals(
schemaTypeCode)) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyAlwaysRequired() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.isDefaultRequirement()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyPopulatedByStyles() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (!metadata.getPopulateConfigs().getStyles().isEmpty()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyPopulated() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (!metadata.getPopulateConfigs().isEmpty()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyPopulatedByProperties() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (!metadata.getPopulateConfigs().getProperties().isEmpty()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyNonParentReferences() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.getType() == MetadataValueType.REFERENCE && !metadata.isChildOfRelationship()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyParentReferences() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.getType() == MetadataValueType.REFERENCE && metadata.isChildOfRelationship()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyParentReferenceToSchemaType(String typeCode) {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.getType() == MetadataValueType.REFERENCE && metadata.isChildOfRelationship()
&& metadata.getAllowedReferences().getTypeWithAllowedSchemas().equals(typeCode)) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyTaxonomyReferences() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.getType() == MetadataValueType.REFERENCE && metadata.isTaxonomyRelationship()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList only(MetadataListFilter filter) {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (filter.isReturned(metadata)) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlySearchable() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.isSearchable()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyEnabled() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.isEnabled()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyNonSystemReserved() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (!metadata.isSystemReserved()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyWithType(MetadataValueType... types) {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
for (MetadataValueType type : types) {
if (metadata.getType() == type) {
filteredMetadatasList.add(metadata);
}
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
private void addToIndex(Metadata metadata) {
localCodeIndex.put(metadata.getLocalCode(), metadata);
codeIndex.put(metadata.getInheritanceCode(), metadata);
datastoreCodeIndex.put(metadata.getDataStoreCode(), metadata);
}
private void removeFromIndex(Metadata metadata) {
localCodeIndex.remove(metadata.getLocalCode());
codeIndex.remove(metadata.getInheritanceCode());
datastoreCodeIndex.remove(metadata.getDataStoreCode());
}
private void clearIndexes() {
localCodeIndex.clear();
codeIndex.clear();
datastoreCodeIndex.clear();
}
private void setIndexes(int index, Metadata element) {
removeFromIndex(nestedList.get(index));
localCodeIndex.put(element.getLocalCode(), element);
codeIndex.put(element.getInheritanceCode(), element);
datastoreCodeIndex.put(element.getDataStoreCode(), element);
}
private void retainAllInIndexes(Collection<?> c) {
clearIndexes();
for (Object object : c) {
addToIndex((Metadata) object);
}
}
private void ensureNotReadOnly() {
if (readOnly) {
throw new UnsupportedOperationException("Operation cannot be done on read-only list");
}
}
public MetadataList unModifiable() {
readOnly = true;
return this;
}
public MetadataList onlyEssentialInSummary() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.isEssentialInSummary()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyEssentialMetadatasAndCodeTitle() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.isEssential()) {
filteredMetadatasList.add(metadata);
} else if (metadata.getLocalCode().equals("code") || metadata.getLocalCode().equals("title")) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyManuals() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.getDataEntry().getType() == DataEntryType.MANUAL) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyCalculated() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.getDataEntry().getType() == DataEntryType.CALCULATED) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlySequence() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.getDataEntry().getType() == DataEntryType.SEQUENCE) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyNotSystemReserved() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (!metadata.isSystemReserved()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlySchemaAutocomplete() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.isSchemaAutocomplete()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public Metadata getMetadataWithLocalCode(String localCode) {
for (Metadata metadata : this) {
if (metadata.getLocalCode().equals(localCode)) {
return metadata;
}
}
return null;
}
public MetadataList onlyUniques() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.isUniqueValue()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyWithDefaultValue() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.getDefaultValue() != null) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyNotGlobals() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (!metadata.isGlobal()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public List<Metadata> onlyWithoutInheritance() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.getInheritance() == null) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList sortAscTitle(final Language language) {
return sortedUsing(new Comparator<Metadata>() {
@Override
public int compare(Metadata o1, Metadata o2) {
return compareStrings(o1.getLabel(language), o2.getLabel(language));
}
});
}
public MetadataList sortedUsing(Comparator<Metadata> comparator) {
List<Metadata> filteredMetadatasList = new ArrayList<>(nestedList);
Collections.sort(filteredMetadatasList, comparator);
return new MetadataList(filteredMetadatasList).unModifiable();
}
public boolean containsMetadataWithLocalCode(String localCode) {
return localCodeIndex.containsKey(localCode);
}
public MetadataList onlyDuplicable() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.isDuplicable()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public MetadataList onlyUSR() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.getLocalCode().startsWith("USR")) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
public List<Metadata> onlyMarkedForDeletion() {
List<Metadata> filteredMetadatasList = new ArrayList<>();
for (Metadata metadata : nestedList) {
if (metadata.isMarkedForDeletion()) {
filteredMetadatasList.add(metadata);
}
}
return new MetadataList(filteredMetadatasList).unModifiable();
}
}