001/*
002 *  Copyright 2020 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.repository.data.holder.values;
017
018import java.util.List;
019import java.util.Map;
020import java.util.Set;
021import java.util.function.Function;
022import java.util.stream.Collectors;
023import java.util.stream.IntStream;
024
025/**
026 * Wrapper for a synchronizable repeater.<br>
027 * Contains the repeater values and a mapping between stored entry positions and new ones.
028 */
029public final class SynchronizableRepeater
030{
031    private List<Map<String, Object>> _entries;
032    private Map<Integer, Integer> _positionsMapping;
033    private List<Integer> _replacePositions;
034    private Set<Integer> _removedEntries;
035    private Mode _mode;
036    
037    /**
038     * The entries write mode.
039     */
040    public static enum Mode
041    {
042        /** The entries will replace all existing values */
043        REPLACE_ALL,
044        /** The entries will replace specific entries */
045        REPLACE,
046        /** The entries will be appended after existing entries */
047        APPEND
048    }
049    
050    private SynchronizableRepeater(List<Map<String, Object>> entries, Mode mode)
051    {
052        _entries = entries;
053        _mode = mode;
054    }
055    
056    private SynchronizableRepeater(List<Map<String, Object>> entries, Map<Integer, Integer> positionsMapping, List<Integer> replacePositions, Set<Integer> removedEntries, Mode mode)
057    {
058        _entries = entries;
059        _positionsMapping = positionsMapping;
060        _replacePositions = replacePositions;
061        _removedEntries = removedEntries;
062        _mode = mode;
063    }
064    
065    /**
066     * Replace all values in a repeater, optionally moving or removing entries. Entries not present in the mapping will be removed.
067     * @param entries the new repeater values.
068     * @param positionsMapping a mapping from stored positions to new ones. No mapping for an existing entry means removal. A null mapping means the identity mapping.
069     * @return a {@link SynchronizableRepeater} in replace mode.
070     */
071    public static SynchronizableRepeater replaceAll(List<Map<String, Object>> entries, Map<Integer, Integer> positionsMapping)
072    {
073        SynchronizableRepeater repeater = new SynchronizableRepeater(entries, Mode.REPLACE_ALL);
074        repeater._positionsMapping = positionsMapping != null ? positionsMapping : IntStream.rangeClosed(1, entries.size()).boxed().collect(Collectors.toMap(Function.identity(), Function.identity()));
075        
076        return repeater;
077    }
078    
079    /**
080     * Replace values in a repeater.
081     * @param entries the new repeater values.
082     * @param positions the positions of the provided entries in the repeater. A null List means replacing the first entries.
083     * @return a {@link SynchronizableRepeater} in replace mode.
084     */
085    public static SynchronizableRepeater replace(List<Map<String, Object>> entries, List<Integer> positions)
086    {
087        assert positions == null || positions.size() == entries.size();
088        SynchronizableRepeater repeater = new SynchronizableRepeater(entries, Mode.REPLACE);
089        repeater._replacePositions = positions != null ? positions : IntStream.rangeClosed(1, entries.size()).boxed().collect(Collectors.toList());
090        
091        return repeater;
092    }
093    
094    /**
095     * Append and/or remove entries in a repeater.
096     * @param newEntries the entries to be appended to the repeater.
097     * @param removedEntries the entries to be removed from the repeater.
098     * @return a {@link SynchronizableRepeater} in append mode.
099     */
100    public static SynchronizableRepeater appendOrRemove(List<Map<String, Object>> newEntries, Set<Integer> removedEntries)
101    {
102        SynchronizableRepeater repeater = new SynchronizableRepeater(newEntries, Mode.APPEND);
103        repeater._removedEntries = removedEntries;
104        
105        return repeater;
106    }
107    
108    /**
109     * Copy the provided repeater, optionally replacing entries with given ones.
110     * @param repeater the SynchronizableRepeater to copy
111     * @param newEntries the new entries values
112     * @return a new SynchronizableRepeater
113     */
114    public static SynchronizableRepeater copy(SynchronizableRepeater repeater, List<Map<String, Object>> newEntries)
115    {
116        return new SynchronizableRepeater(newEntries != null ? newEntries : repeater.getEntries(), repeater.getPositionsMapping(), repeater.getReplacePositions(), repeater.getRemovedEntries(), repeater.getMode());
117    }
118    
119    /**
120     * Returns the mapping from stored positions to new ones.
121     * @return the mapping from stored positions to new ones.
122     */
123    public Map<Integer, Integer> getPositionsMapping()
124    {
125        return _positionsMapping;
126    }
127    
128    /**
129     * Returns the positions of replacing entries.
130     * @return the positions of replacing entries.
131     */
132    public List<Integer> getReplacePositions()
133    {
134        return _replacePositions;
135    }
136    
137    /**
138     * Returns the new repeater values.
139     * @return the new repeater values.
140     */
141    public List<Map<String, Object>> getEntries()
142    {
143        return _entries;
144    }
145    
146    /**
147     * Returns the entries to be removed. <br>
148     * Only relevant for append mode.<br>
149     * For replace mode, removed entries are carried trough the positions mapping.
150     * @return the new repeater values.
151     */
152    public Set<Integer> getRemovedEntries()
153    {
154        return _removedEntries;
155    }
156    
157    /**
158     * Returns the write mode for provided entries.
159     * @return the write mode
160     */
161    public Mode getMode()
162    {
163        return _mode;
164    }
165}