package com.psddev.cms.tool.page;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.servlet.ServletException;
import com.google.common.collect.ImmutableMap;
import com.psddev.cms.db.ToolUser;
import com.psddev.cms.tool.PageServlet;
import com.psddev.cms.tool.SearchResultField;
import com.psddev.cms.tool.ToolPageContext;
import com.psddev.dari.db.Database;
import com.psddev.dari.db.ObjectField;
import com.psddev.dari.db.ObjectType;
import com.psddev.dari.util.ClassFinder;
import com.psddev.dari.util.CompactMap;
import com.psddev.dari.util.ObjectUtils;
import com.psddev.dari.util.RoutingFilter;
import com.psddev.dari.util.TypeDefinition;
@RoutingFilter.Path(application = "cms", value = "/searchResultFields")
public class SearchResultFields extends PageServlet {
private static final long serialVersionUID = 1L;
@Override
protected String getPermissionId() {
return null;
}
@Override
protected void doService(ToolPageContext page) throws IOException, ServletException {
ObjectType type = ObjectType.getInstance(page.param(UUID.class, "typeId"));
ToolUser user = page.getUser();
Map<String, List<String>> fieldNamesByTypeId = user.getSearchResultFieldsByTypeId();
String typeId = type != null ? type.getId().toString() : "";
List<String> fieldNames = fieldNamesByTypeId.get(typeId);
if (page.isFormPost()) {
List<String> fieldNameParams = page.params(String.class, "fieldNames");
if (!ObjectUtils.isBlank(fieldNameParams)) {
fieldNamesByTypeId.put(typeId, fieldNameParams);
} else {
fieldNamesByTypeId.remove(typeId);
}
user.save();
page.writeStart("div", "id", page.createId());
page.writeEnd();
page.writeStart("script", "type", "text/javascript");
page.writeRaw("$('#" + page.getId() + "').popup('source').closest('.searchForm').find('.searchFiltersRest').submit();");
page.writeRaw("$('#" + page.getId() + "').popup('close');");
page.writeEnd();
return;
}
page.writeStart("div", "class", "widget searchResultFields");
page.writeStart("h1");
if (type == null) {
page.writeHtml(page.localize(SearchResultFields.class, "title"));
} else {
page.writeHtml(
page.localize(
SearchResultFields.class,
ImmutableMap.of("type", page.getObjectLabel(type)),
"typeTitle"));
}
page.writeEnd();
page.writeStart("form",
"method", "post",
"action", page.url(""));
Map<Boolean, List<Object>> fieldsMap = getSearchFieldsMap(type, fieldNames);
page.writeStart("div", "class", "searchResultFields-container");
page.writeStart("div", "class", "searchResultFields-hide");
page.writeHtml(page.localize(SearchResultFields.class, "label.hiddenFields"));
writeFieldItemsHtml(page, fieldsMap.get(false), false);
page.writeEnd();
page.writeStart("div",
"class", "searchResultFields-divider");
page.writeEnd();
page.writeStart("div", "class", "searchResultFields-display");
page.writeHtml(page.localize(SearchResultFields.class, "label.selectedFields"));
writeFieldItemsHtml(page, fieldsMap.get(true), true);
page.writeEnd();
page.writeEnd();
page.writeStart("div", "class", "actions");
page.writeStart("button");
page.writeHtml(page.localize(SearchResultFields.class, "action.update"));
page.writeEnd();
page.writeEnd();
page.writeEnd();
page.writeEnd();
}
private void writeFieldItemsHtml(ToolPageContext page, List<Object> fieldObjects, boolean checked) throws IOException {
if (!checked) {
page.writeTag("input",
"type", "text",
"placeholder", "Filter by name",
"class", "searchResultFields-filter");
}
page.writeStart("ul");
for (Object fieldObject : fieldObjects) {
String displayName = "";
String internalName = "";
if (fieldObject instanceof ObjectField) {
ObjectField field = (ObjectField) fieldObject;
displayName = field.getDisplayName();
internalName = field.getInternalName();
} else if (fieldObject instanceof SearchResultField) {
SearchResultField field = (SearchResultField) fieldObject;
displayName = field.getDisplayName();
internalName = field.getClass().getName();
}
page.writeStart("li");
page.writeStart("label", "data-display-name", displayName);
page.writeTag("input",
"type", "checkbox",
"name", "fieldNames",
"checked", checked ? "checked" : null,
"value", internalName);
page.writeStart("span");
page.writeHtml(displayName);
page.writeEnd();
page.writeEnd();
page.writeEnd();
}
page.writeEnd();
}
private Map<Boolean, List<Object>> getSearchFieldsMap(ObjectType type,
List<String> fieldsNames) {
List<Object> hiddenFields = new ArrayList<>();
List<Object> displayFields = new ArrayList<>();
if (fieldsNames == null) {
fieldsNames = new ArrayList<>();
}
if (type != null) {
for (ObjectField field : type.getFields()) {
String fieldName = field.getInternalName();
if (fieldsNames.contains(fieldName)) {
displayFields.add(field);
} else {
hiddenFields.add(field);
}
}
}
for (Class<? extends SearchResultField> f : ClassFinder.findConcreteClasses(SearchResultField.class)) {
SearchResultField field = TypeDefinition.getInstance(f).newInstance();
if (field.isSupported(type)) {
String fieldName = f.getName();
if (fieldsNames.contains(fieldName) || field.isDefault(type)) {
displayFields.add(field);
} else {
hiddenFields.add(field);
}
}
}
for (ObjectField field : Database.Static.getDefault().getEnvironment().getFields()) {
if (fieldsNames.contains(field.getInternalName())) {
displayFields.add(field);
} else {
hiddenFields.add(field);
}
}
// This field is currently required
hiddenFields.removeIf(o -> o instanceof ObjectField && ((ObjectField) o).getInternalName().equals("cms.content.updateDate"));
Collections.sort(hiddenFields, (f1, f2) -> {
String fieldName1 = "";
String fieldName2 = "";
if (f1 instanceof ObjectField) {
fieldName1 = ((ObjectField) f1).getDisplayName();
} else if (f1 instanceof SearchResultField) {
fieldName1 = ((SearchResultField) f1).getDisplayName();
}
if (f2 instanceof ObjectField) {
fieldName2 = ((ObjectField) f2).getDisplayName();
} else if (f2 instanceof SearchResultField) {
fieldName2 = ((SearchResultField) f2).getDisplayName();
}
return fieldName1.compareTo(fieldName2);
});
// Boolean key indicates whether field has been selected
Map<Boolean, List<Object>> mappedFields = new CompactMap<>();
mappedFields.put(false, hiddenFields);
mappedFields.put(true, displayFields);
return mappedFields;
}
}