package com.constellio.app.modules.rm.ui.pages.decommissioning;
import com.constellio.app.modules.rm.constants.RMPermissionsTo;
import com.constellio.app.modules.rm.model.enums.DecomListStatus;
import com.constellio.app.modules.rm.model.enums.FolderMediaType;
import com.constellio.app.modules.rm.navigation.RMViews;
import com.constellio.app.modules.rm.services.RMSchemasRecordsServices;
import com.constellio.app.modules.rm.services.decommissioning.DecommissioningListParams;
import com.constellio.app.modules.rm.services.decommissioning.DecommissioningSearchConditionFactory;
import com.constellio.app.modules.rm.services.decommissioning.DecommissioningService;
import com.constellio.app.modules.rm.services.decommissioning.SearchType;
import com.constellio.app.modules.rm.wrappers.DecommissioningList;
import com.constellio.app.modules.rm.wrappers.Document;
import com.constellio.app.modules.rm.wrappers.Folder;
import com.constellio.app.ui.entities.MetadataVO;
import com.constellio.app.ui.pages.search.AdvancedSearchCriteriaComponent.SearchCriteriaPresenter;
import com.constellio.app.ui.pages.search.SearchPresenter;
import com.constellio.app.ui.pages.search.criteria.ConditionBuilder;
import com.constellio.app.ui.pages.search.criteria.ConditionException;
import com.constellio.app.ui.pages.search.criteria.ConditionException.ConditionException_EmptyCondition;
import com.constellio.app.ui.pages.search.criteria.ConditionException.ConditionException_TooManyClosedParentheses;
import com.constellio.app.ui.pages.search.criteria.ConditionException.ConditionException_UnclosedParentheses;
import com.constellio.app.ui.pages.search.criteria.Criterion;
import com.constellio.app.ui.params.ParamUtils;
import com.constellio.model.entities.records.Record;
import com.constellio.model.entities.records.wrappers.SavedSearch;
import com.constellio.model.entities.records.wrappers.User;
import com.constellio.model.entities.schemas.MetadataSchema;
import com.constellio.model.entities.schemas.MetadataSchemaType;
import com.constellio.model.entities.schemas.Schemas;
import com.constellio.model.services.search.query.logical.condition.LogicalSearchCondition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.Serializable;
import java.util.*;
import static com.constellio.app.ui.i18n.i18n.$;
import static com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators.*;
import static java.util.Arrays.asList;
public class DecommissioningBuilderPresenter extends SearchPresenter<DecommissioningBuilderView>
implements SearchCriteriaPresenter {
private static final Logger LOGGER = LoggerFactory.getLogger(DecommissioningBuilderPresenter.class);
private transient LogicalSearchCondition condition;
private transient RMSchemasRecordsServices rmRecordServices;
private transient DecommissioningService decommissioningService;
SearchType searchType;
String adminUnitId;
String decommissioningListId;
List<String> foldersToExclude;
List<String> documentsToExclude;
boolean displayResults;
boolean addMode;
int pageNumber;
public DecommissioningBuilderPresenter(DecommissioningBuilderView view) {
super(view);
}
@Override
public DecommissioningBuilderPresenter forRequestParameters(String params) {
String[] parts = params.split("/", 3);
if (!addMode) {
Map<String, String> paramsMap = ParamUtils.getParamsMap(params);
searchType = SearchType.valueOf(parts[0]);
view.setCriteriaSchemaType(getSchemaType());
view.addEmptyCriterion();
view.addEmptyCriterion();
this.displayResults = false;
pageNumber = 1;
} else if (parts.length > 1) {
searchType = SearchType.valueOf(parts[0]);
SavedSearch search = getSavedSearch(parts[2]);
setSavedSearch(search);
this.displayResults = true;
} else {
searchType = SearchType.valueOf(params);
view.setCriteriaSchemaType(getSchemaType());
view.addEmptyCriterion();
view.addEmptyCriterion();
this.displayResults = false;
pageNumber = 1;
}
if(searchType.isFolderSearch()) {
foldersToExclude = getFoldersAlreadyInNonProcessedDecommissioningLists();
documentsToExclude = null;
} else {
foldersToExclude = null;
documentsToExclude = getDocumentsAlreadyInNonProcessedDecommissioningLists();
}
return this;
}
public void forParams(String params) {
List<String> parts = asList(params.split("/", 3));
Map<String, String> paramsMap = ParamUtils.getParamsMap(params);
if (parts.size() == 3 && parts.get(1).equals("id")) {
addMode = false;
decommissioningListId = parts.get(2);
DecommissioningList decommissioningList = rmRecordServices().getDecommissioningList(decommissioningListId);
administrativeUnitSelected(decommissioningList.getAdministrativeUnit());
view.setAdministrativeUnit(decommissioningList.getAdministrativeUnit());
} else {
addMode = true;
}
}
@Override
protected boolean hasPageAccess(String params, User user) {
String[] parts = params.split("/", 3);
if (SearchType.transfer.equals(SearchType.valueOf(parts[0]))) {
return user.has(RMPermissionsTo.PROCESS_DECOMMISSIONING_LIST).onSomething() ||
user.has(RMPermissionsTo.CREATE_TRANSFER_DECOMMISSIONING_LIST).globally();
} else {
return user.has(RMPermissionsTo.PROCESS_DECOMMISSIONING_LIST).onSomething();
}
}
@Override
public boolean mustDisplayResults() {
return this.displayResults;
}
@Override
public int getPageNumber() {
return pageNumber;
}
@Override
public void setPageNumber(int pageNumber) {
this.pageNumber = pageNumber;
}
@Override
public void suggestionSelected(String suggestion) {
// Do nothing
}
private void setSavedSearch(SavedSearch search) {
view.setCriteriaSchemaType(search.getSearchType());
List<Criterion> criteria = search.getAdvancedSearch();
if (criteria.isEmpty()) {
view.addEmptyCriterion();
view.addEmptyCriterion();
} else {
view.setSearchCriteria(criteria);
}
this.pageNumber = search.getPageNumber();
this.setFacetSelections(search.getSelectedFacets());
this.adminUnitId = search.getFreeTextSearch();
setSelectedPageLength(search.getPageLength());
view.setAdministrativeUnit(this.adminUnitId);
}
public SearchType getSearchType() {
return searchType;
}
public DecommissioningList getDecommissioningList() {
return decommissioningListId == null ? null : rmRecordServices().getDecommissioningList(decommissioningListId);
}
public void searchRequested() {
try {
buildSearchCondition();
resetFacetSelection();
view.refreshSearchResultsAndFacets();
} catch (ConditionException_EmptyCondition e) {
view.showErrorMessage($("AdvancedSearchView.emptyCondition"));
} catch (ConditionException_TooManyClosedParentheses e) {
view.showErrorMessage($("AdvancedSearchView.tooManyClosedParentheses"));
} catch (ConditionException_UnclosedParentheses e) {
view.showErrorMessage($("AdvancedSearchView.unclosedParentheses"));
} catch (ConditionException e) {
throw new RuntimeException("BUG: Uncaught ConditionException", e);
}
}
public void decommissioningListCreationRequested(DecommissioningListParams params) {
DecommissioningService decommissioningService = new DecommissioningService(view.getCollection(), appLayerFactory);
params.setAdministrativeUnit(adminUnitId);
params.setSearchType(searchType);
try {
DecommissioningList decommissioningList = decommissioningService.createDecommissioningList(params, getCurrentUser());
if (decommissioningList.getDecommissioningListType().isFolderList()) {
view.navigate().to(RMViews.class).displayDecommissioningList(decommissioningList.getId());
} else {
view.navigate().to(RMViews.class).displayDocumentDecommissioningList(decommissioningList.getId());
}
} catch (Exception e) {
LOGGER.error("Error while creating decommissioning list", e);
view.showErrorMessage($("DecommissioningBuilderView.unableToSave"));
}
}
public void addToListButtonClicked(List<String> selected) {
try {
DecommissioningList decommissioningList = rmRecordServices().getDecommissioningList(decommissioningListId);
if (decommissioningList.getDecommissioningListType().isFolderList()) {
decommissioningList.addFolderDetailsFor(rmRecordServices.getFolders(selected).toArray(new Folder[0]));
recordServices().update(decommissioningList.getWrappedRecord());
view.navigate().to(RMViews.class).displayDecommissioningList(decommissioningList.getId());
} else {
decommissioningList.addDocuments(selected.toArray(new String[0]));
recordServices().update(decommissioningList.getWrappedRecord());
view.navigate().to(RMViews.class).displayDocumentDecommissioningList(decommissioningList.getId());
}
} catch (Exception e) {
LOGGER.error("Error while creating decommissioning list", e);
view.showErrorMessage($("DecommissioningBuilderView.unableToSave"));
}
}
public List<SelectItemVO> getAdministrativeUnits() {
User currentUser = presenterService().getCurrentUser(view.getSessionContext());
List<SelectItemVO> results = new ArrayList<>();
List<String> conceptIds = decommissioningService().getAdministrativeUnitsForUser(currentUser);
List<Record> concepts = recordServices().getRecordsById(currentUser.getCollection(), conceptIds);
for (Record record : concepts) {
results.add(new SelectItemVO(record.getId(), (String) record.get(Schemas.TITLE)));
}
return results;
}
@Override
public void addCriterionRequested() {
view.addEmptyCriterion();
}
public void administrativeUnitSelected(String adminUnitId) {
this.adminUnitId = adminUnitId;
}
@Override
public List<MetadataVO> getMetadataAllowedInCriteria() {
return getMetadataAllowedInAdvancedSearch(getSchemaType());
}
@Override
public MetadataVO getMetadataVO(String metadataCode) {
return super.getMetadataVO(metadataCode);
}
@Override
protected boolean saveSearch(String title, boolean publicAccess) {
throw new UnsupportedOperationException();
}
@Override
public List<MetadataVO> getMetadataAllowedInSort() {
return getMetadataAllowedInSort(getSchemaType());
}
@Override
public boolean isPreferAnalyzedFields() {
return false;
}
@Override
protected LogicalSearchCondition getSearchCondition() {
if (condition == null) {
try {
buildSearchCondition();
} catch (ConditionException e) {
throw new RuntimeException("Unexpected exception (should be unreachable)", e);
}
}
return condition;
}
protected LogicalSearchCondition buildSearchCondition()
throws ConditionException {
List<Criterion> criteria = view.getSearchCriteria();
if (criteria.isEmpty()) {
condition = selectByDecommissioningStatus();
} else {
condition = allConditions(selectByDecommissioningStatus(), selectByAdvancedSearchCriteria(criteria));
}
if(searchType.isFolderSearch()) {
condition = condition.andWhere(rmRecordServices().folder.borrowed()).isFalseOrNull();
condition = condition.andWhere(Schemas.IDENTIFIER).isNotIn(foldersToExclude);
} else {
condition = condition.andWhere(Schemas.IDENTIFIER).isNotIn(documentsToExclude);
}
if (!getCurrentUser().has(RMPermissionsTo.PROCESS_DECOMMISSIONING_LIST).onSomething() &&
getCurrentUser().has(RMPermissionsTo.CREATE_TRANSFER_DECOMMISSIONING_LIST).globally()) {
if (searchType.isFolderSearch()) {
condition = condition.andWhere(rmRecordServices().folder.mediaType()).isEqualTo(FolderMediaType.ANALOG);
}
}
return condition;
}
protected List<String> getFoldersAlreadyInNonProcessedDecommissioningLists() {
RMSchemasRecordsServices rm = rmRecordServices();
Set<String> foldersToHide = new HashSet<>();
List<DecommissioningList> decommissioningLists = rm.searchDecommissioningLists(where(rm.decommissioningList.status()).isNotEqual(DecomListStatus.PROCESSED)
.andWhere(rm.decommissioningList.folders()).isNotNull());
for(DecommissioningList list: decommissioningLists) {
foldersToHide.addAll(list.getFolders());
}
return new ArrayList<>(foldersToHide);
}
protected List<String> getDocumentsAlreadyInNonProcessedDecommissioningLists() {
RMSchemasRecordsServices rm = rmRecordServices();
Set<String> documentsToHide = new HashSet<>();
List<DecommissioningList> decommissioningLists = rm.searchDecommissioningLists(where(rm.decommissioningList.status()).isNotEqual(DecomListStatus.PROCESSED)
.andWhere(rm.decommissioningList.documents()).isNotNull());
for(DecommissioningList list: decommissioningLists) {
documentsToHide.addAll(list.getFolders());
}
return new ArrayList<>(documentsToHide);
}
private String getSchemaType() {
return searchType.isFolderSearch() ? Folder.SCHEMA_TYPE : Document.SCHEMA_TYPE;
}
private LogicalSearchCondition selectByDecommissioningStatus() {
return new DecommissioningSearchConditionFactory(view.getCollection(), appLayerFactory)
.bySearchType(searchType, adminUnitId);
}
private LogicalSearchCondition selectByAdvancedSearchCriteria(List<Criterion> criteria)
throws ConditionException {
String languageCode = searchServices().getLanguageCode(view.getCollection());
MetadataSchemaType type = searchType.isFolderSearch() ?
rmRecordServices().folder.schemaType() : rmRecordServices().documentSchemaType();
return new ConditionBuilder(type, languageCode).build(criteria);
}
private DecommissioningService decommissioningService() {
if (decommissioningService == null) {
decommissioningService = new DecommissioningService(view.getCollection(), appLayerFactory);
}
return decommissioningService;
}
private RMSchemasRecordsServices rmRecordServices() {
if (rmRecordServices == null) {
rmRecordServices = new RMSchemasRecordsServices(view.getCollection(), appLayerFactory);
}
return rmRecordServices;
}
public static class SelectItemVO implements Serializable {
private final String id;
private final String label;
public SelectItemVO(String id, String label) {
this.id = id;
this.label = label;
}
public String getId() {
return id;
}
public String getLabel() {
return label;
}
}
protected SavedSearch saveTemporarySearch(boolean refreshPage) {
Record tmpSearchRecord = getTemporarySearchRecord();
if (tmpSearchRecord == null) {
tmpSearchRecord = recordServices().newRecordWithSchema(schema(SavedSearch.DEFAULT_SCHEMA));
}
SavedSearch search = new SavedSearch(tmpSearchRecord, types())
.setTitle("temporaryDecommission")
.setSearchType(DecommissioningBuilderView.SEARCH_TYPE)
.setUser(getCurrentUser().getId())
.setPublic(false)
.setTemporary(true)
.setSchemaFilter(getSchemaType())
.setFreeTextSearch(adminUnitId)
.setAdvancedSearch(view.getSearchCriteria())
.setPageNumber(pageNumber)
.setSelectedFacets(this.getFacetSelections().getNestedMap())
.setPageLength(getSelectedPageLength());
modelLayerFactory.getRecordsCaches().getCache(view.getCollection()).insert(search.getWrappedRecord());
//recordServices().update(search);
if (refreshPage) {
view.navigate().to(RMViews.class).decommissioningListBuilderReplay(searchType.name(), search.getId());
}
return search;
}
@Override
public Record getTemporarySearchRecord() {
MetadataSchema schema = schema(SavedSearch.DEFAULT_SCHEMA);
try {
return searchServices().searchSingleResult(from(schema)
.where(schema.getMetadata(SavedSearch.USER)).isEqualTo(getCurrentUser().getId())
.andWhere(schema.getMetadata(SavedSearch.TEMPORARY)).isEqualTo(true)
.andWhere(schema.getMetadata(SavedSearch.SEARCH_TYPE)).isEqualTo(DecommissioningBuilderView.SEARCH_TYPE));
} catch (Exception e) {
//TODO exception
e.printStackTrace();
}
return null;
}
public boolean isAddMode() {
return addMode;
}
}