package com.constellio.app.ui.framework.containers;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.vaadin.addons.lazyquerycontainer.LazyQueryContainer;
import org.vaadin.addons.lazyquerycontainer.LazyQueryDefinition;
import org.vaadin.addons.lazyquerycontainer.Query;
import org.vaadin.addons.lazyquerycontainer.QueryDefinition;
import org.vaadin.addons.lazyquerycontainer.QueryFactory;
import com.constellio.app.services.factories.ConstellioFactories;
import com.constellio.app.ui.entities.MetadataSchemaVO;
import com.constellio.app.ui.entities.MetadataVO;
import com.constellio.app.ui.entities.RecordVO;
import com.constellio.app.ui.framework.data.DataProvider.DataRefreshListener;
import com.constellio.app.ui.framework.data.RecordVODataProvider;
import com.constellio.app.ui.framework.items.RecordVOItem;
import com.constellio.model.services.migrations.ConstellioEIMConfigs;
import com.vaadin.data.Item;
@SuppressWarnings("serial")
public class RecordVOLazyContainer extends LazyQueryContainer implements RefreshableContainer {
private List<RecordVODataProvider> dataProviders;
public RecordVOLazyContainer(RecordVODataProvider dataProvider) {
this(Arrays.asList(dataProvider));
}
public RecordVOLazyContainer(List<RecordVODataProvider> dataProviders) {
this(dataProviders, 100);
}
public RecordVOLazyContainer(List<RecordVODataProvider> dataProviders, int batchSize) {
super(new RecordVOLazyQueryDefinition(dataProviders, isOnlyTableMetadatasShown(), batchSize),
new RecordVOLazyQueryFactory(dataProviders));
this.dataProviders = dataProviders;
for (RecordVODataProvider dataProvider : dataProviders) {
dataProvider.setBatchSize(batchSize);
}
for (RecordVODataProvider dataProvider : dataProviders) {
dataProvider.addDataRefreshListener(new DataRefreshListener() {
@Override
public void dataRefresh() {
RecordVOLazyContainer.this.refresh();
}
});
}
}
public List<RecordVODataProvider> getDataProviders() {
return dataProviders;
}
private static boolean isOnlyTableMetadatasShown() {
ConstellioFactories constellioFactories = ConstellioFactories.getInstance();
ConstellioEIMConfigs configs = new ConstellioEIMConfigs(
constellioFactories.getModelLayerFactory().getSystemConfigurationsManager());
return !configs.isTableDynamicConfiguration();
}
public List<MetadataSchemaVO> getSchemas() {
List<MetadataSchemaVO> schemas = new ArrayList<>();
for (RecordVODataProvider dataProvider : dataProviders) {
schemas.add(dataProvider.getSchema());
}
return schemas;
}
private static RecordVODataProviderAndRecordIndex forRecordIndex(List<RecordVODataProvider> dataProviders, int index) {
RecordVODataProviderAndRecordIndex result = null;
int lastSize = 0;
for (RecordVODataProvider dataProvider : dataProviders) {
int dataProviderSize = dataProvider.size();
if ((lastSize + dataProviderSize) > index) {
int actualIndex = index - lastSize;
result = new RecordVODataProviderAndRecordIndex(dataProvider, actualIndex);
break;
}
lastSize += dataProviderSize;
}
return result;
}
public RecordVO getRecordVO(int index) {
RecordVODataProviderAndRecordIndex dataProviderAndRecordIndex = forRecordIndex(dataProviders, index);
int recordIndexForDataProvider = dataProviderAndRecordIndex.recordIndex;
return dataProviderAndRecordIndex.dataProvider.getRecordVO(recordIndexForDataProvider);
}
private static class RecordVODataProviderAndRecordIndex implements Serializable {
private RecordVODataProvider dataProvider;
private int recordIndex;
public RecordVODataProviderAndRecordIndex(RecordVODataProvider dataProvider, int recordIndex) {
this.dataProvider = dataProvider;
this.recordIndex = recordIndex;
}
}
public static class RecordVOLazyQueryDefinition extends LazyQueryDefinition {
List<RecordVODataProvider> dataProviders;
/**
* final boolean compositeItems, final int batchSize, final Object idPropertyId
*
* //@param dataProviders
* //@param compositeItems
* //@param batchSize
* //@param idPropertyId
*/
public RecordVOLazyQueryDefinition(List<RecordVODataProvider> dataProviders, boolean tableMetadatasOnly, int batchSize) {
super(true, batchSize, null);
this.dataProviders = dataProviders;
List<MetadataVO> propertyMetadataVOs = new ArrayList<>();
List<MetadataVO> tablePropertyMetadataVOs = new ArrayList<>();
List<MetadataVO> extraPropertyMetadataVOs = new ArrayList<>();
List<MetadataVO> queryMetadataVOs = new ArrayList<>();
for (RecordVODataProvider dataProvider : dataProviders) {
MetadataSchemaVO schema = dataProvider.getSchema();
List<MetadataVO> dataProviderTableMetadataVOs = schema.getTableMetadatas();
tablePropertyMetadataVOs.addAll(dataProviderTableMetadataVOs);
List<MetadataVO> dataProviderQueryMetadataVOs = new ArrayList<>(dataProviderTableMetadataVOs);
if (!tableMetadatasOnly) {
List<MetadataVO> dataProviderDisplayMetadataVOs = schema.getDisplayMetadatas();
for (MetadataVO metadataVO : dataProviderDisplayMetadataVOs) {
if (!dataProviderQueryMetadataVOs.contains(metadataVO)) {
dataProviderQueryMetadataVOs.add(metadataVO);
}
}
}
for (MetadataVO metadataVO : dataProviderQueryMetadataVOs) {
if (!queryMetadataVOs.contains(metadataVO)) {
if (dataProviderTableMetadataVOs.contains(metadataVO)) {
tablePropertyMetadataVOs.add(metadataVO);
} else {
extraPropertyMetadataVOs.add(metadataVO);
}
}
}
}
Collections.sort(extraPropertyMetadataVOs, new Comparator<MetadataVO>() {
@Override
public int compare(MetadataVO o1, MetadataVO o2) {
return o1.getLabel().compareTo(o2.getLabel());
}
});
propertyMetadataVOs.addAll(tablePropertyMetadataVOs);
propertyMetadataVOs.addAll(extraPropertyMetadataVOs);
for (MetadataVO metadataVO : propertyMetadataVOs) {
super.addProperty(metadataVO, metadataVO.getJavaType(), null, true, true);
}
}
}
public static class RecordVOLazyQueryFactory implements QueryFactory, Serializable {
List<RecordVODataProvider> dataProviders;
public RecordVOLazyQueryFactory(List<RecordVODataProvider> dataProviders) {
this.dataProviders = dataProviders;
}
@Override
public Query constructQuery(final QueryDefinition queryDefinition) {
Object[] sortPropertyIds = queryDefinition.getSortPropertyIds();
if (sortPropertyIds != null && sortPropertyIds.length > 0) {
List<MetadataVO> sortMetadatas = new ArrayList<MetadataVO>();
for (int i = 0; i < sortPropertyIds.length; i++) {
MetadataVO sortMetadata = (MetadataVO) sortPropertyIds[i];
sortMetadatas.add(sortMetadata);
}
for (RecordVODataProvider dataProvider : dataProviders) {
dataProvider.sort(sortMetadatas.toArray(new MetadataVO[0]), queryDefinition.getSortPropertyAscendingStates());
}
}
return new SerializableQuery() {
@Override
public int size() {
int totalSizes = 0;
for (RecordVODataProvider dataProvider : dataProviders) {
totalSizes += dataProvider.size();
}
return totalSizes;
}
@Override
public void saveItems(List<Item> addedItems, List<Item> modifiedItems, List<Item> removedItems) {
throw new UnsupportedOperationException("Query is read-only");
}
@Override
public List<Item> loadItems(int startIndex, int count) {
List<Item> items = new ArrayList<Item>();
RecordVODataProviderAndRecordIndex dataProviderAndRecordIndex = forRecordIndex(dataProviders, startIndex);
RecordVODataProvider firstDataProvider = dataProviderAndRecordIndex.dataProvider;
int startIndexForFirstDataProvider = dataProviderAndRecordIndex.recordIndex;
List<RecordVO> recordVOsFromFirstDataProvider = firstDataProvider
.listRecordVOs(startIndexForFirstDataProvider, count);
for (RecordVO recordVO : recordVOsFromFirstDataProvider) {
Item item = new RecordVOItem(recordVO);
items.add(item);
}
if (items.size() < count) {
// We need to add results from extra dataProviders
boolean firstDataProviderFound = false;
for (RecordVODataProvider dataProvider : dataProviders) {
if (dataProvider.equals(firstDataProvider)) {
firstDataProviderFound = true;
} else if (firstDataProviderFound) {
// Only records belonging to dataProviders after the first are relevant
int startIndexForDataProvider = 0;
int countForDataProvider = count - items.size();
List<RecordVO> recordVOsFromDataProvider = dataProvider
.listRecordVOs(startIndexForDataProvider, countForDataProvider);
for (RecordVO recordVO : recordVOsFromDataProvider) {
Item item = new RecordVOItem(recordVO);
items.add(item);
}
if (items.size() >= count) {
break;
}
}
}
}
return items;
}
@Override
public boolean deleteAllItems() {
throw new UnsupportedOperationException("Query is read-only");
}
@Override
public Item constructItem() {
throw new UnsupportedOperationException("Query is read-only");
}
};
}
private interface SerializableQuery extends Query, Serializable {
}
}
}