package com.constellio.app.modules.rm.ui.pages.cart;
import static com.constellio.app.modules.rm.model.enums.FolderStatus.ACTIVE;
import static com.constellio.app.modules.rm.model.enums.FolderStatus.SEMI_ACTIVE;
import static com.constellio.app.ui.i18n.i18n.$;
import static com.constellio.model.services.search.query.logical.LogicalSearchQueryOperators.from;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import com.constellio.app.extensions.AppLayerCollectionExtensions;
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.DecommissioningListType;
import com.constellio.app.modules.rm.model.enums.FolderStatus;
import com.constellio.app.modules.rm.model.labelTemplate.LabelTemplate;
import com.constellio.app.modules.rm.model.labelTemplate.LabelTemplateManager;
import com.constellio.app.modules.rm.navigation.RMViews;
import com.constellio.app.modules.rm.reports.builders.search.SearchResultReportParameters;
import com.constellio.app.modules.rm.reports.builders.search.SearchResultReportWriterFactory;
import com.constellio.app.modules.rm.services.RMSchemasRecordsServices;
import com.constellio.app.modules.rm.services.cart.CartEmlService;
import com.constellio.app.modules.rm.services.decommissioning.DecommissioningService;
import com.constellio.app.modules.rm.wrappers.Cart;
import com.constellio.app.modules.rm.wrappers.ContainerRecord;
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.MetadataSchemaVO;
import com.constellio.app.ui.entities.RecordVO;
import com.constellio.app.ui.entities.RecordVO.VIEW_MODE;
import com.constellio.app.ui.framework.builders.MetadataSchemaToVOBuilder;
import com.constellio.app.ui.framework.builders.RecordToVOBuilder;
import com.constellio.app.ui.framework.components.NewReportPresenter;
import com.constellio.app.ui.framework.components.RecordFieldFactory;
import com.constellio.app.ui.framework.data.RecordVOWithDistinctSchemasDataProvider;
import com.constellio.app.ui.framework.reports.NewReportWriterFactory;
import com.constellio.app.ui.pages.base.SessionContext;
import com.constellio.app.ui.pages.base.SingleSchemaBasePresenter;
import com.constellio.app.ui.pages.search.batchProcessing.BatchProcessingPresenter;
import com.constellio.app.ui.pages.search.batchProcessing.BatchProcessingPresenterService;
import com.constellio.app.ui.pages.search.batchProcessing.entities.BatchProcessResults;
import com.constellio.model.entities.enums.BatchProcessingMode;
import com.constellio.model.entities.records.Record;
import com.constellio.model.entities.records.wrappers.RecordWrapper;
import com.constellio.model.entities.records.wrappers.User;
import com.constellio.model.entities.schemas.Schemas;
import com.constellio.model.services.records.RecordServicesException;
import com.constellio.model.services.reports.ReportServices;
import com.constellio.model.services.search.StatusFilter;
import com.constellio.model.services.search.query.logical.LogicalSearchQuery;
public class CartPresenter extends SingleSchemaBasePresenter<CartView> implements BatchProcessingPresenter, NewReportPresenter {
private transient RMSchemasRecordsServices rm;
private transient Cart cart;
private String cartId;
private String batchProcessSchemaType;
private transient BatchProcessingPresenterService batchProcessingPresenterService;
public CartPresenter(CartView view) {
super(view, Cart.DEFAULT_SCHEMA);
}
public void itemRemovalRequested(RecordVO record) {
Cart cart = cart();
switch (record.getSchema().getTypeCode()) {
case Folder.SCHEMA_TYPE:
cart.removeFolder(record.getId());
break;
case Document.SCHEMA_TYPE:
cart.removeDocument(record.getId());
break;
case ContainerRecord.SCHEMA_TYPE:
cart.removeContainer(record.getId());
break;
}
addOrUpdate(cart.getWrappedRecord());
view.navigate().to(RMViews.class).cart(cart.getId());
}
public boolean canEmptyCart() {
return cartHasRecords();
}
public void cartEmptyingRequested() {
addOrUpdate(cart().empty().getWrappedRecord());
view.navigate().to(RMViews.class).cart(cart().getId());
}
public boolean canPrepareEmail() {
// TODO: Maybe better test
return cartHasRecords() && cart().getContainers().isEmpty();
}
public void emailPreparationRequested() {
InputStream stream = new CartEmlService(collection, modelLayerFactory).createEmlForCart(cart());
view.startDownload(stream);
}
public boolean canDuplicate() {
return cartHasOnlyFolders() && canDuplicateFolders(getCurrentUser());
}
public void duplicationRequested() {
if (!canDuplicate()) {
view.showErrorMessage($("CartView.cannotDuplicate"));
return;
}
try {
DecommissioningService service = new DecommissioningService(view.getCollection(), appLayerFactory);
for (Folder folder : getCartFolders()) {
service.duplicateStructureAndSave(folder, getCurrentUser());
}
view.showMessage($("CartView.duplicated"));
} catch (RecordServicesException.ValidationException e) {
view.showErrorMessage($(e.getErrors()));
} catch (Exception e) {
view.showErrorMessage(e.getMessage());
}
}
public boolean canDelete() {
return cartHasRecords() && cart().getContainers().isEmpty()
&& canDeleteFolders(getCurrentUser()) && canDeleteDocuments(getCurrentUser());
}
public void deletionRequested() {
if (!canDelete()) {
view.showErrorMessage($("CartView.cannotDelete"));
return;
}
for (Record record : recordServices().getRecordsById(view.getCollection(), cart().getAllItems())) {
delete(record);
}
cartEmptyingRequested();
}
public RecordVOWithDistinctSchemasDataProvider getFolderRecords() {
return new RecordVOWithDistinctSchemasDataProvider(
getSchemas(), new RecordToVOBuilder(), modelLayerFactory, view.getSessionContext()) {
@Override
protected LogicalSearchQuery getQuery() {
return new LogicalSearchQuery(from(rm.folder.schemaType()).where(Schemas.IDENTIFIER).isIn(cart().getAllItems()))
.filteredWithUser(getCurrentUser()).filteredByStatus(StatusFilter.ACTIVES)
.sortAsc(Schemas.TITLE);
}
};
}
public RecordVOWithDistinctSchemasDataProvider getDocumentRecords() {
return new RecordVOWithDistinctSchemasDataProvider(
getSchemas(), new RecordToVOBuilder(), modelLayerFactory, view.getSessionContext()) {
@Override
protected LogicalSearchQuery getQuery() {
return new LogicalSearchQuery(from(rm.documentSchemaType()).where(Schemas.IDENTIFIER).isIn(cart().getAllItems()))
.filteredWithUser(getCurrentUser()).filteredByStatus(StatusFilter.ACTIVES)
.sortAsc(Schemas.TITLE);
}
};
}
public RecordVOWithDistinctSchemasDataProvider getContainerRecords() {
return new RecordVOWithDistinctSchemasDataProvider(
getSchemas(), new RecordToVOBuilder(), modelLayerFactory, view.getSessionContext()) {
@Override
protected LogicalSearchQuery getQuery() {
if (getCurrentUser().hasAny(RMPermissionsTo.DISPLAY_CONTAINERS, RMPermissionsTo.MANAGE_CONTAINERS).globally()) {
return new LogicalSearchQuery(
from(rm.containerRecord.schemaType()).where(Schemas.IDENTIFIER).isIn(cart().getAllItems()))
.filteredByStatus(StatusFilter.ACTIVES)
.sortAsc(Schemas.TITLE);
} else {
return LogicalSearchQuery.returningNoResults();
}
}
};
}
private List<MetadataSchemaVO> getSchemas() {
MetadataSchemaToVOBuilder builder = new MetadataSchemaToVOBuilder();
return Arrays.asList(
builder.build(schema(Folder.DEFAULT_SCHEMA), VIEW_MODE.TABLE, view.getSessionContext()),
builder.build(schema(Folder.DEFAULT_SCHEMA), VIEW_MODE.TABLE, view.getSessionContext()),
builder.build(schema(Folder.DEFAULT_SCHEMA), VIEW_MODE.TABLE, view.getSessionContext()));
}
Cart cart() {
if (cart == null) {
// cart = rm().getOrCreateUserCart(getCurrentUser());
cart = rm().getCart(cartId);
}
return cart;
}
private boolean cartHasRecords() {
return !cart().isEmpty();
}
private boolean cartHasOnlyFolders() {
return !cart().getFolders().isEmpty() && cart().getDocuments().isEmpty() && cart().getContainers().isEmpty();
}
private boolean canDuplicateFolders(User user) {
for (Folder folder : getCartFolders()) {
RecordWrapper parent = folder.getParentFolder() != null ?
rm().getFolder(folder.getParentFolder()) :
rm().getAdministrativeUnit(folder.getAdministrativeUnitEntered());
if (!user.hasWriteAccess().on(parent)) {
return false;
}
switch (folder.getPermissionStatus()) {
case SEMI_ACTIVE:
if (!user.has(RMPermissionsTo.DUPLICATE_SEMIACTIVE_FOLDER).on(folder)) {
return false;
}
break;
case INACTIVE_DEPOSITED:
case INACTIVE_DESTROYED:
if (!user.has(RMPermissionsTo.DUPLICATE_INACTIVE_FOLDER).on(folder)) {
return false;
}
break;
}
}
return true;
}
private boolean canDeleteFolders(User user) {
for (Folder folder : getCartFolders()) {
if (!user.hasDeleteAccess().on(folder)) {
return false;
}
switch (folder.getPermissionStatus()) {
case SEMI_ACTIVE:
if (!user.has(RMPermissionsTo.DELETE_SEMIACTIVE_FOLDERS).on(folder)) {
return false;
}
break;
case INACTIVE_DEPOSITED:
case INACTIVE_DESTROYED:
if (!user.has(RMPermissionsTo.DELETE_INACTIVE_FOLDERS).on(folder)) {
return false;
}
break;
}
}
return true;
}
private boolean canDeleteDocuments(User user) {
for (Document document : getCartDocuments()) {
if (!user.hasDeleteAccess().on(document)) {
return false;
}
switch (document.getArchivisticStatus()) {
case SEMI_ACTIVE:
if (!user.has(RMPermissionsTo.DELETE_SEMIACTIVE_DOCUMENT).on(document)) {
return false;
}
break;
case INACTIVE_DEPOSITED:
case INACTIVE_DESTROYED:
if (!user.has(RMPermissionsTo.DELETE_INACTIVE_DOCUMENT).on(document)) {
return false;
}
}
if (document.isPublished() && !user.has(RMPermissionsTo.DELETE_PUBLISHED_DOCUMENT).on(document)) {
return false;
}
if (getCurrentBorrowerOf(document) != null && !getCurrentUser().has(RMPermissionsTo.DELETE_BORROWED_DOCUMENT)
.on(document)) {
return false;
}
}
return true;
}
private String getCurrentBorrowerOf(Document document) {
return document.getContent() == null ? null : document.getContent().getCheckoutUserId();
}
List<Folder> getCartFolders() {
return rm().wrapFolders(recordServices().getRecordsById(view.getCollection(), cart().getFolders()));
}
List<String> getCartFolderIds() {
return cart().getFolders();
}
private List<Document> getCartDocuments() {
return rm().wrapDocuments(recordServices().getRecordsById(view.getCollection(), cart().getDocuments()));
}
private RMSchemasRecordsServices rm() {
if (rm == null) {
rm = new RMSchemasRecordsServices(collection, modelLayerFactory);
}
return rm;
}
@Override
protected boolean hasPageAccess(String params, User user) {
return true;
}
public void forParams(String parameters) {
cartId = parameters;
}
public List<String> getRecordsIds(String schemaType) {
switch (schemaType) {
case Folder.SCHEMA_TYPE:
return cart().getFolders();
case Document.SCHEMA_TYPE:
return cart().getDocuments();
case ContainerRecord.SCHEMA_TYPE:
return cart().getContainers();
default:
throw new RuntimeException("Unsupported type : " + schemaType);
}
}
@Override
public String getOriginType() {
return batchProcessingPresenterService().getOriginType(getRecordsIds(batchProcessSchemaType));
}
public String getOriginType(List<String> selectedRecordIds) {
return batchProcessingPresenterService().getOriginType(selectedRecordIds);
}
@Override
public RecordVO newRecordVO(String schema, SessionContext sessionContext) {
return newRecordVO(getRecordsIds(batchProcessSchemaType), schema, sessionContext);
}
public RecordVO newRecordVO(List<String> selectedRecordIds, String schema, SessionContext sessionContext) {
return batchProcessingPresenterService().newRecordVO(schema, sessionContext, selectedRecordIds);
}
@Override
public InputStream simulateButtonClicked(String selectedType, RecordVO viewObject)
throws RecordServicesException {
return simulateButtonClicked(selectedType, getRecordsIds(batchProcessSchemaType), viewObject);
}
public InputStream simulateButtonClicked(String selectedType, List<String> records, RecordVO viewObject)
throws RecordServicesException {
BatchProcessResults results = batchProcessingPresenterService()
.simulate(selectedType, records, viewObject, getCurrentUser());
return batchProcessingPresenterService().formatBatchProcessingResults(results);
}
@Override
public void processBatchButtonClicked(String selectedType, RecordVO viewObject)
throws RecordServicesException {
processBatchButtonClicked(selectedType, getRecordsIds(batchProcessSchemaType), viewObject);
}
public void processBatchButtonClicked(String selectedType, List<String> records, RecordVO viewObject)
throws RecordServicesException {
batchProcessingPresenterService()
.execute(selectedType, records, viewObject, getCurrentUser());
view.navigate().to(RMViews.class).cart(cartId);
}
@Override
public boolean hasWriteAccessOnAllRecords() {
return hasWriteAccessOnAllRecords(getRecordsIds(batchProcessSchemaType));
}
@Override
public long getNumberOfRecords() {
return (long) getRecordsIds(batchProcessSchemaType).size();
}
public boolean hasWriteAccessOnAllRecords(List<String> selectedRecordIds) {
return batchProcessingPresenterService().hasWriteAccessOnAllRecords(getCurrentUser(), selectedRecordIds);
}
@Override
public BatchProcessingMode getBatchProcessingMode() {
return batchProcessingPresenterService().getBatchProcessingMode();
}
@Override
public AppLayerCollectionExtensions getBatchProcessingExtension() {
return batchProcessingPresenterService().getBatchProcessingExtension();
}
@Override
public String getSchema(String schemaType, String type) {
return batchProcessingPresenterService().getSchema(schemaType, type);
}
@Override
public String getTypeSchemaType(String schemaType) {
return batchProcessingPresenterService().getTypeSchemaType(schemaType);
}
@Override
public RecordFieldFactory newRecordFieldFactory(String schemaType, String selectedType) {
return newRecordFieldFactory(schemaType, selectedType, getRecordsIds(batchProcessSchemaType));
}
public RecordFieldFactory newRecordFieldFactory(String schemaType, String selectedType, List<String> records) {
return batchProcessingPresenterService().newRecordFieldFactory(schemaType, selectedType, records);
}
public List<LabelTemplate> getCustomTemplates(String schemaType) {
LabelTemplateManager labelTemplateManager = appLayerFactory.getLabelTemplateManager();
return labelTemplateManager.listExtensionTemplates(schemaType);
}
public List<LabelTemplate> getDefaultTemplates(String schemaType) {
LabelTemplateManager labelTemplateManager = appLayerFactory.getLabelTemplateManager();
return labelTemplateManager.listTemplates(schemaType);
}
public boolean isLabelsButtonVisible(String schemaType) {
switch (schemaType) {
case Folder.SCHEMA_TYPE:
return cart().getFolders().size() != 0;
case ContainerRecord.SCHEMA_TYPE:
return cart().getContainers().size() != 0;
default:
throw new RuntimeException("No labels for type : " + schemaType);
}
}
public boolean isBatchProcessingButtonVisible(String schemaType) {
boolean hasRightToProcessSchemaType = true;
if (ContainerRecord.SCHEMA_TYPE.equals(schemaType) && !getCurrentUser().has(RMPermissionsTo.MANAGE_CONTAINERS)
.globally()) {
hasRightToProcessSchemaType = false;
}
return getRecordsIds(schemaType).size() != 0 && hasRightToProcessSchemaType;
}
public void shareWithUsersRequested(List<String> userids) {
cart().setSharedWithUsers(userids);
addOrUpdate(cart().getWrappedRecord());
}
BatchProcessingPresenterService batchProcessingPresenterService() {
if (batchProcessingPresenterService == null) {
Locale locale = view.getSessionContext().getCurrentLocale();
batchProcessingPresenterService = new BatchProcessingPresenterService(collection, appLayerFactory, locale);
}
return batchProcessingPresenterService;
}
List<DecommissioningListType> getCommonDecommissioningListTypes(List<Folder> folders) {
List<DecommissioningListType> commonTypes = new ArrayList<>();
boolean first = true;
FolderStatus folderStatus = null;
for (Folder folder : folders) {
if (folderStatus == null) {
folderStatus = folder.getArchivisticStatus();
} else if (folderStatus != folder.getArchivisticStatus()) {
return commonTypes;
}
}
for (Folder folder : folders) {
if (first) {
commonTypes.addAll(findDecommissioningListTypes(folder));
first = false;
} else {
List<DecommissioningListType> types = findDecommissioningListTypes(folder);
Iterator<DecommissioningListType> commonTypesIterator = commonTypes.iterator();
while (commonTypesIterator.hasNext()) {
if (!types.contains(commonTypesIterator.next())) {
commonTypesIterator.remove();
}
}
}
}
return commonTypes;
}
private List<DecommissioningListType> findDecommissioningListTypes(Folder folder) {
List<DecommissioningListType> types = new ArrayList<>();
if (folder.getCloseDate() == null) {
types.add(DecommissioningListType.FOLDERS_TO_CLOSE);
} else {
if (folder.getArchivisticStatus() == ACTIVE) {
types.add(DecommissioningListType.FOLDERS_TO_TRANSFER);
}
if (folder.getArchivisticStatus() == SEMI_ACTIVE || folder.getArchivisticStatus() == ACTIVE) {
if (folder.getExpectedDepositDate() != null) {
types.add(DecommissioningListType.FOLDERS_TO_DEPOSIT);
}
if (folder.getExpectedDestructionDate() != null) {
types.add(DecommissioningListType.FOLDERS_TO_DESTROY);
}
}
}
return types;
}
String getCommonAdministrativeUnit(List<Folder> folders) {
String administrativeUnit = null;
for (Folder folder : folders) {
if (administrativeUnit == null) {
administrativeUnit = folder.getAdministrativeUnit();
} else {
if (!administrativeUnit.equals(folder.getAdministrativeUnit())) {
return null;
}
}
}
return administrativeUnit;
}
public void buildDecommissioningListRequested(String title, DecommissioningListType decomType) {
DecommissioningList list = rm.newDecommissioningList();
list.setTitle(title);
list.setAdministrativeUnit(getCommonAdministrativeUnit(getCartFolders()));
list.setDecommissioningListType(decomType);
list.setFolderDetailsFor(getCartFolders());
try {
recordServices().add(list);
view.navigate().to(RMViews.class).displayDecommissioningList(list.getId());
} catch (RecordServicesException e) {
e.printStackTrace();
}
}
public void displayRecordRequested(RecordVO recordVO) {
switch (recordVO.getSchema().getTypeCode()) {
case Folder.SCHEMA_TYPE:
view.navigate().to(RMViews.class).displayFolder(recordVO.getId());
break;
case Document.SCHEMA_TYPE:
view.navigate().to(RMViews.class).displayDocument(recordVO.getId());
break;
case ContainerRecord.SCHEMA_TYPE:
view.navigate().to(RMViews.class).displayContainer(recordVO.getId());
break;
}
}
public void folderFilterButtonClicked() {
view.filterFolderTable();
}
public void documentFilterButtonClicked() {
view.filterDocumentTable();
}
public void containerFilterButtonClicked() {
view.filterContainerTable();
}
public RecordVOWithDistinctSchemasDataProvider getFilteredFolderRecords(final String freeText) {
return new RecordVOWithDistinctSchemasDataProvider(
getSchemas(), new RecordToVOBuilder(), modelLayerFactory, view.getSessionContext()) {
@Override
protected LogicalSearchQuery getQuery() {
return new LogicalSearchQuery(from(rm.folder.schemaType()).where(Schemas.IDENTIFIER).isIn(cart().getAllItems()))
.filteredWithUser(getCurrentUser()).filteredByStatus(StatusFilter.ACTIVES).setFreeTextQuery(freeText)
.sortAsc(Schemas.TITLE);
}
};
}
public RecordVOWithDistinctSchemasDataProvider getFilteredDocumentRecords(final String freeText) {
return new RecordVOWithDistinctSchemasDataProvider(
getSchemas(), new RecordToVOBuilder(), modelLayerFactory, view.getSessionContext()) {
@Override
protected LogicalSearchQuery getQuery() {
return new LogicalSearchQuery(from(rm.documentSchemaType()).where(Schemas.IDENTIFIER).isIn(cart().getAllItems()))
.filteredWithUser(getCurrentUser()).filteredByStatus(StatusFilter.ACTIVES).setFreeTextQuery(freeText)
.sortAsc(Schemas.TITLE);
}
};
}
public RecordVOWithDistinctSchemasDataProvider getFilteredContainerRecords(final String freeText) {
return new RecordVOWithDistinctSchemasDataProvider(
getSchemas(), new RecordToVOBuilder(), modelLayerFactory, view.getSessionContext()) {
@Override
protected LogicalSearchQuery getQuery() {
if (getCurrentUser().hasAny(RMPermissionsTo.DISPLAY_CONTAINERS, RMPermissionsTo.MANAGE_CONTAINERS).globally()) {
return new LogicalSearchQuery(
from(rm.containerRecord.schemaType()).where(Schemas.IDENTIFIER).isIn(cart().getAllItems()))
.filteredByStatus(StatusFilter.ACTIVES).setFreeTextQuery(freeText)
.sortAsc(Schemas.TITLE);
} else {
return LogicalSearchQuery.returningNoResults();
}
}
};
}
@Override
public List<String> getSupportedReports() {
List<String> supportedReports = new ArrayList<>();
ReportServices reportServices = new ReportServices(modelLayerFactory, collection);
List<String> userReports = reportServices.getUserReportTitles(getCurrentUser(), view.getCurrentSchemaType());
supportedReports.addAll(userReports);
return supportedReports;
}
@Override
public NewReportWriterFactory<SearchResultReportParameters> getReport(String report) {
return new SearchResultReportWriterFactory(appLayerFactory);
}
@Override
public Object getReportParameters(String report) {
List<String> recordids = getRecordsIds(view.getCurrentSchemaType());
LogicalSearchQuery query = new LogicalSearchQuery(from(rm.schemaType(view.getCurrentSchemaType())).returnAll());
return new SearchResultReportParameters(recordids, view.getCurrentSchemaType(),
collection, report, getCurrentUser(), query);
}
public void backButtonClicked() {
view.navigate().to(RMViews.class).listCarts();
}
public CartPresenter setBatchProcessSchemaType(String batchProcessSchemaType) {
this.batchProcessSchemaType = batchProcessSchemaType;
return this;
}
@Override
public void allSearchResultsButtonClicked() {
throw new RuntimeException("Should not have been called");
}
@Override
public void selectedSearchResultsButtonClicked() {
throw new RuntimeException("Should not have been called");
}
@Override
public boolean isSearchResultsSelectionForm() {
return false;
}
public boolean isAnyFolderBorrowed() {
return searchServices().getResultsCount(from(rm().folder.schemaType()).where(rm().folder.borrowed()).isTrue()
.andWhere(Schemas.IDENTIFIER).isIn(getCartFolderIds())) > 0;
}
public boolean isAnyFolderInDecommissioningList() {
return searchServices().getResultsCount(
from(rm().decommissioningList.schemaType()).where(rm().decommissioningList.status())
.isNotEqual(DecomListStatus.PROCESSED)
.andWhere(rm().decommissioningList.folders()).isContaining(getCartFolderIds())) > 0;
}
}