1
2
3
4
5
6
7 package ch.colabproject.colab.api.controller.common;
8
9 import ch.colabproject.colab.api.model.WithIndex;
10 import ch.colabproject.colab.generator.model.exceptions.HttpErrorMessage;
11 import ch.colabproject.colab.generator.model.exceptions.MessageI18nKey;
12 import ch.colabproject.colab.generator.model.interfaces.WithId;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.Comparator;
16 import java.util.List;
17 import javax.ejb.LocalBean;
18 import javax.ejb.Stateless;
19 import org.apache.commons.collections4.CollectionUtils;
20
21
22
23
24
25
26
27
28
29
30
31 @Stateless
32 @LocalBean
33 public class IndexWithEmptySlotManager<T extends WithIndex & WithId> {
34
35
36
37
38 private static final int DEFAULT_MAX_INDEX = Integer.MAX_VALUE;
39
40
41 private final Comparator<T> idComparator = Comparator
42 .comparingLong(entity -> entity.getId());
43
44
45 private final Comparator<T> indexComparator = Comparator
46 .comparingLong(entity -> entity.getIndex() != 0 ? entity.getIndex() : DEFAULT_MAX_INDEX);
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66 public void changeItemPosition(T itemToMove, int newIndex, Collection<T> collection) {
67 if (CollectionUtils.isEmpty(collection)) {
68 throw HttpErrorMessage.dataError(MessageI18nKey.DATA_INTEGRITY_FAILURE);
69 }
70
71 if (!collection.contains(itemToMove)) {
72 throw HttpErrorMessage.dataError(MessageI18nKey.DATA_INTEGRITY_FAILURE);
73 }
74
75 List<T> sortedList = sort(collection);
76
77 harmonizeIndexes(sortedList);
78
79 int oldIndex = itemToMove.getIndex();
80
81 if (oldIndex != newIndex) {
82 boolean isMovingToEmptySlot = sortedList.stream()
83 .filter(anItem -> anItem.getIndex() == newIndex).findAny().isEmpty();
84
85 if (isMovingToEmptySlot) {
86
87
88
89 itemToMove.setIndex(newIndex);
90 } else {
91 List<Integer> fixedEmptySlots = listEmptySlots(sortedList);
92
93 boolean isMovingToBiggerIndex = newIndex > oldIndex;
94
95
96 if (isMovingToBiggerIndex) {
97 for (T anItem : sortedList) {
98 if (anItem.getIndex() > oldIndex && anItem.getIndex() <= newIndex) {
99 int anItemIndex = anItem.getIndex() - 1;
100
101 while (fixedEmptySlots.contains(anItemIndex)) {
102 anItemIndex--;
103 }
104 anItem.setIndex(anItemIndex);
105 }
106 }
107 } else {
108 for (T anItem : sortedList) {
109 if (anItem.getIndex() >= newIndex && anItem.getIndex() < oldIndex) {
110 int anItemIndex = anItem.getIndex() + 1;
111
112 while (fixedEmptySlots.contains(anItemIndex)) {
113 anItemIndex++;
114 }
115 anItem.setIndex(anItemIndex);
116 }
117 }
118 }
119
120 itemToMove.setIndex(newIndex);
121 }
122 }
123 }
124
125
126
127
128
129
130
131
132
133
134
135
136 private List<T> sort(Collection<T> collection) {
137 List<T> sortedList = new ArrayList<>(collection);
138
139 sortedList.sort(idComparator);
140
141 sortedList.sort(indexComparator);
142
143 return sortedList;
144 }
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159 private void harmonizeIndexes(List<T> sortedList) {
160 int lastIndex = 0;
161
162
163
164 for (T item : sortedList) {
165 if (item.getIndex() <= lastIndex) {
166 item.setIndex(lastIndex + 1);
167 }
168
169 lastIndex = item.getIndex();
170 }
171 }
172
173
174
175
176
177
178
179
180
181
182
183
184 private List<Integer> listEmptySlots(List<T> sortedList) {
185 List<Integer> emptySlots = new ArrayList<>();
186
187 int lastIndex = 0;
188
189 for (T item : sortedList) {
190 lastIndex++;
191
192 while (lastIndex < item.getIndex()) {
193 emptySlots.add(lastIndex);
194 lastIndex++;
195 }
196 }
197
198 return emptySlots;
199 }
200
201 }