package com.constellio.app.services.schemasDisplay;
import static com.constellio.app.entities.schemasDisplay.enums.MetadataDisplayType.VERTICAL;
import com.constellio.app.entities.schemasDisplay.MetadataDisplayConfig;
import com.constellio.app.entities.schemasDisplay.SchemaDisplayConfig;
import com.constellio.app.entities.schemasDisplay.SchemaTypeDisplayConfig;
import com.constellio.app.entities.schemasDisplay.SchemaTypesDisplayConfig;
import com.constellio.app.entities.schemasDisplay.enums.MetadataDisplayType;
import com.constellio.model.entities.Language;
import org.apache.commons.lang.StringUtils;
import org.jdom2.Document;
import org.jdom2.Element;
import java.util.*;
import java.util.Map.Entry;
public class SchemasDisplayWriter {
private static final String ROOT = "display";
private static final String SCHEMA_TYPES_DISPLAY_CONFIG = "SchemaTypesDisplayConfig";
private static final String COLLECTION = "collection";
private static final String SCHEMA_TYPE_DISPLAY_CONFIGS = "SchemaTypeDisplayConfigs";
private static final String MANAGEABLE = "manageable";
private static final String SIMPLE_SEARCH = "simpleSearch";
private static final String ADVANCED_SEARCH = "advancedSearch";
private static final String TRUE = "true";
private static final String FALSE = "false";
private static final String SCHEMA_DISPLAY_CONFIGS = "SchemaDisplayConfigs";
private static final String DISPLAY_METADATA_CODES = "DisplayMetadataCodes";
private static final String SCHEMA_CODE = "SchemaCode";
private static final String FORM_METADATA_CODES = "FormMetadataCodes";
private static final String SEARCH_RESULTS_METADATA_CODES = "SearchResultsMetadataCodes";
private static final String TABLE_METADATA_CODES = "TableMetadataCodes";
private static final String METADATA_DISPLAY_CONFIGS = "MetadataDisplayConfigs";
private static final String INPUT_TYPE = "InputType";
private static final String DISPLAY_TYPE = "DisplayType";
private static final String VISIBLE_IN_ADVANCED_SEARCH = "VisibleInAdvancedSearch";
private static final String HIGHLIGHT = "Highlight";
private static final String METADATA_GROUP_LABEL = "MetadataGroupLabel";
private static final String METADATA_GROUPS_LABELS = "MetadataGroupsLabels";
private static final String LABELS = "labels";
private static final String METADATA_GROUP_CODE = "code";
private static final String METADATA_GROUP = "metadataGroup";
public static final String FORMAT_ATTRIBUTE = "format";
public static final String FORMAT_VERSION = SchemasDisplayReader2.FORMAT_VERSION;
public static final String LABEL_SEPARATOR = ";;";
Document document;
public SchemasDisplayWriter(Document document) {
this.document = document;
}
public void writeEmptyDocument() {
Element display = new Element(ROOT);
document.setRootElement(display);
document.getRootElement().setAttribute(FORMAT_ATTRIBUTE, FORMAT_VERSION);
}
public void saveTypes(SchemaTypesDisplayConfig config) {
Element rootElement = document.getRootElement();
Element schemaTypesDisplayConfigElement = getOrCreateElementFromParent(rootElement, SCHEMA_TYPES_DISPLAY_CONFIG);
for (String facetMetadataCode : config.getFacetMetadataCodes()) {
Element facetMetadataCodeElement = schemaTypesDisplayConfigElement.getChild(facetMetadataCode);
if (facetMetadataCodeElement == null) {
facetMetadataCodeElement = new Element(facetMetadataCode);
schemaTypesDisplayConfigElement.addContent(facetMetadataCodeElement);
}
}
Set<String> codesToKeep = new HashSet<>(config.getFacetMetadataCodes());
for (Element elementToCheckForRemoval : schemaTypesDisplayConfigElement.getChildren()) {
if (!codesToKeep.contains(elementToCheckForRemoval.getName())) {
schemaTypesDisplayConfigElement.removeChild(elementToCheckForRemoval.getName());
}
}
}
private Element getOrCreateElementFromParent(Element rootElement, String elementName) {
return getOrCreateElementFromParent(rootElement, elementName, "", "");
}
private void removeElementFromParent(Element rootElement, String elementName, String attributeName,
String attributeValue) {
List<Element> elements = rootElement.getChildren(elementName);
for (Element element : elements) {
if (StringUtils.isNotBlank(attributeName)) {
if (attributeValue.equals(element.getAttributeValue(attributeName))) {
element.detach();
return;
}
} else {
element.detach();
return;
}
}
}
private Element getOrCreateElementFromParent(Element rootElement, String elementName, String attributeName,
String attributeValue) {
Element newElement = null;
List<Element> elements = rootElement.getChildren(elementName);
for (Element element : elements) {
if (StringUtils.isNotBlank(attributeName)) {
if (attributeValue.equals(element.getAttributeValue(attributeName))) {
newElement = element.clone();
rootElement.addContent(newElement);
element.detach();
return newElement;
}
} else {
newElement = element.clone();
rootElement.addContent(newElement);
element.detach();
return newElement;
}
}
if (newElement == null) {
newElement = createAndAddElement(rootElement, elementName, attributeName, attributeValue);
}
return newElement;
}
private Element createAndAddElement(Element rootElement, String elementName, String attributeName, String attributeValue) {
Element newElement;
newElement = new Element(elementName);
if (StringUtils.isNotBlank(attributeName)) {
newElement.setAttribute(attributeName, attributeValue);
}
rootElement.addContent(newElement);
return newElement;
}
private Element createMetadataGroupLabel(Element rootElement, String codeValue, Map<Language, String> labelsValue) {
Element newElement;
newElement = new Element(METADATA_GROUP_LABEL);
if (StringUtils.isNotBlank(METADATA_GROUP_CODE)) {
newElement.setAttribute(METADATA_GROUP_CODE, codeValue != null ? codeValue : "");
newElement.setAttribute(LABELS, labelToSemiColonStringSeparated(labelsValue));
}
rootElement.addContent(newElement);
return newElement;
}
private String labelToSemiColonStringSeparated(Map<Language, String> labels) {
StringBuilder stringBuilder = new StringBuilder();
List<Entry<Language, String>> entries = new ArrayList<>(labels.entrySet());
Collections.sort(entries, new Comparator<Entry<Language, String>>() {
@Override
public int compare(Entry<Language, String> o1, Entry<Language, String> o2) {
return o1.getKey().getCode().compareTo(o2.getKey().getCode());
}
});
for (Entry<Language, String> entry : entries) {
stringBuilder.append(entry.getKey().getCode() + "=" + entry.getValue() + LABEL_SEPARATOR);
}
return stringBuilder.toString();
}
public void saveType(SchemaTypeDisplayConfig config) {
Element rootElement = document.getRootElement();
Element schemaTypeDisplayConfigs = getOrCreateElementFromParent(rootElement, SCHEMA_TYPE_DISPLAY_CONFIGS);
Element schemaTypeDisplayConfig = schemaTypeDisplayConfigs.getChild(config.getSchemaType());
if (schemaTypeDisplayConfig == null) {
schemaTypeDisplayConfig = new Element(config.getSchemaType());
schemaTypeDisplayConfigs.addContent(schemaTypeDisplayConfig);
}
schemaTypeDisplayConfig.setAttribute(MANAGEABLE, config.isManageable() ? TRUE : FALSE);
schemaTypeDisplayConfig.setAttribute(SIMPLE_SEARCH, config.isSimpleSearch() ? TRUE : FALSE);
schemaTypeDisplayConfig.setAttribute(ADVANCED_SEARCH, config.isAdvancedSearch() ? TRUE : FALSE);
Element metadataGroups = getOrCreateElementFromParent(schemaTypeDisplayConfig, METADATA_GROUPS_LABELS);
for (Element child : metadataGroups.getChildren()) {
metadataGroups.removeChildren(METADATA_GROUP_LABEL);
}
for (String code : config.getMetadataGroup().keySet()) {
createMetadataGroupLabel(metadataGroups, code, config.getMetadataGroup().get(code));
}
}
public void saveSchema(SchemaDisplayConfig config) {
Element rootElement = document.getRootElement();
Element schemaDisplayConfigsElement = getOrCreateElementFromParent(rootElement, SCHEMA_DISPLAY_CONFIGS,
SCHEMA_CODE, config.getSchemaCode());
process(config, schemaDisplayConfigsElement, DISPLAY_METADATA_CODES, config.getDisplayMetadataCodes());
process(config, schemaDisplayConfigsElement, FORM_METADATA_CODES, config.getFormMetadataCodes());
process(config, schemaDisplayConfigsElement, SEARCH_RESULTS_METADATA_CODES,
config.getSearchResultsMetadataCodes());
process(config, schemaDisplayConfigsElement, TABLE_METADATA_CODES,
config.getTableMetadataCodes());
}
private void process(SchemaDisplayConfig config, Element schemaDisplayConfigsElement, String metadataCodeName,
List<String> metadataCodes) {
Element metadataCodesElement = getOrCreateElementFromParent(schemaDisplayConfigsElement, metadataCodeName);
for (String metadataCode : metadataCodes) {
getOrCreateElementFromParent(metadataCodesElement, metadataCode);
}
removeInvalidStringsFromElement(metadataCodes, metadataCodesElement);
}
private void removeInvalidStringsFromElement(List<String> validStrings, Element existingStringsElement) {
List<Element> elementsToRemove = new ArrayList<>();
Set<String> stringsToKeep = new HashSet<>(validStrings);
for (Element elementToCheckForRemoval : existingStringsElement.getChildren()) {
if (!stringsToKeep.contains(elementToCheckForRemoval.getName())) {
// existingStringsElement.removeChild(elementToCheckForRemoval.getName());
elementsToRemove.add(existingStringsElement.getChild(elementToCheckForRemoval.getName()));
}
}
for (Element elementoRemove : elementsToRemove) {
elementoRemove.detach();
}
}
public void saveMetadata(MetadataDisplayConfig config) {
Element rootElement = document.getRootElement();
Element metadataDisplayConfigs = getOrCreateElementFromParent(rootElement, METADATA_DISPLAY_CONFIGS);
Element metadata = getOrCreateElementFromParent(metadataDisplayConfigs, config.getMetadataCode());
metadata.setAttribute(VISIBLE_IN_ADVANCED_SEARCH, config.isVisibleInAdvancedSearch() ? TRUE : FALSE);
metadata.setAttribute(INPUT_TYPE, config.getInputType().name());
if (config.getDisplayType() != null && config.getDisplayType() != MetadataDisplayType.VERTICAL) {
metadata.setAttribute(DISPLAY_TYPE, config.getDisplayType().name());
} else {
metadata.removeAttribute(DISPLAY_TYPE);
}
metadata.setAttribute(HIGHLIGHT, config.isHighlight() ? TRUE : FALSE);
metadata.setAttribute(METADATA_GROUP,
StringUtils.isBlank(config.getMetadataGroupCode()) ? "" : config.getMetadataGroupCode());
}
public void resetSchema(String code) {
Element rootElement = document.getRootElement();
removeElementFromParent(rootElement, SCHEMA_DISPLAY_CONFIGS, SCHEMA_CODE, code);
Element metadatas = rootElement.getChild(METADATA_DISPLAY_CONFIGS);
if (metadatas != null) {
List<Element> elementsToDetach = new ArrayList<>();
List<Element> elements = metadatas.getChildren();
if (elements != null) {
for (Element element : elements) {
if (element.getName().startsWith(code)) {
elementsToDetach.add(element);
}
}
}
for (Element elementToDetach : elementsToDetach) {
elementToDetach.detach();
}
}
}
}