001/*
002 * #%L
003 * GwtMaterial
004 * %%
005 * Copyright (C) 2015 - 2017 GwtMaterialDesign
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 * 
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 * 
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package gwt.material.design.client.data;
021
022import gwt.material.design.client.data.component.CategoryComponent;
023import gwt.material.design.client.data.loader.LoadCallback;
024import gwt.material.design.client.data.loader.LoadConfig;
025import gwt.material.design.client.data.loader.LoadResult;
026
027import java.util.ArrayList;
028import java.util.Collection;
029import java.util.HashMap;
030import java.util.List;
031import java.util.Map;
032import java.util.logging.Level;
033import java.util.logging.Logger;
034
035/**
036 * Map {@link DataSource} that supports infinite loading with categories.
037 */
038public class MapDataSource<T> implements DataSource<T>, HasDataView<T> {
039
040    private final static Logger logger = Logger.getLogger(ListDataSource.class.getName());
041
042    private Map<String, List<T>> dataMap = new HashMap<>();
043    private DataView<T> dataView;
044
045    @Override
046    public void load(LoadConfig<T> loadConfig, LoadCallback<T> callback) {
047        try {
048            List<T> flatData = new ArrayList<>();
049            List<CategoryComponent> categories = loadConfig.getOpenCategories();
050            if(dataView.isUseCategories() && categories != null) {
051                for (CategoryComponent category : categories) {
052                    flatData.addAll(dataMap.get(category.getName()));
053                }
054            } else {
055                for(Map.Entry<String, List<T>> entry : dataMap.entrySet()) {
056                    flatData.addAll(entry.getValue());
057                }
058            }
059
060            List<T> data = new ArrayList<>();
061            int offset = loadConfig.getOffset();
062            for(int i = offset; i < (offset + loadConfig.getLimit()); i++) {
063                try {
064                    data.add(flatData.get(i));
065                } catch (IndexOutOfBoundsException e) {
066                    // ignored.
067                }
068            }
069            callback.onSuccess(new LoadResult<>(data, loadConfig.getOffset(), flatData.size(), cacheData()));
070        }
071        catch (IndexOutOfBoundsException ex) {
072            // Silently ignore index out of bounds exceptions
073            logger.log(Level.FINE, "ListDataSource threw index out of bounds.", ex);
074            callback.onFailure(ex);
075        }
076    }
077
078    public void add(Collection<T> list) {
079        for(T item : list) {
080            String category = null;
081            if(dataView.isUseCategories()) {
082                category = dataView.getRowFactory().getCategory(item);
083            }
084            if(category == null) {
085                category = AbstractDataView.ORPHAN_PATTERN;
086            }
087            List<T> data = dataMap.computeIfAbsent(category, k -> new ArrayList<>());
088            data.add(item);
089        }
090    }
091
092    public void clear() {
093        if (dataMap != null) {
094            dataMap.clear();
095        }
096    }
097
098    public boolean cacheData() {
099        return true;
100    }
101
102    @Override
103    public boolean useRemoteSort() {
104        return false;
105    }
106
107    @Override
108    public final void setDataView(DataView<T> dataView) {
109        this.dataView = dataView;
110    }
111
112    @Override
113    public final DataView<T> getDataView() {
114        return dataView;
115    }
116}