Skip to content

Package: StandardStrategie

StandardStrategie

nameinstructionbranchcomplexitylinemethod
befuelleSchicht(Schicht, List, Collection, Fraction)
M: 0 C: 135
100%
M: 0 C: 16
100%
M: 0 C: 9
100%
M: 0 C: 42
100%
M: 0 C: 1
100%
berechneAnzahlDerSchichtenInDieDieseVoraussichtlicheDokumentenklasseFallenKoennte(VoraussichtlicheDokumentenklasse, Collection)
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
copy(List)
M: 0 C: 8
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
dokumentenklassenToProduktionsauftraege(List)
M: 0 C: 17
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
erstelleMittelfristigePlanung(Zeitraum, Collection, List, Collection, Collection, Fraction)
M: 6 C: 71
92%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 2 C: 15
88%
M: 0 C: 1
100%
erstelleOptimalenSchichtplan(List, Collection, List, Collection, Fraction, MittelfristigePlanung.SZENARIO, Collection)
M: 5 C: 86
95%
M: 1 C: 5
83%
M: 1 C: 4
80%
M: 1 C: 25
96%
M: 0 C: 1
100%
erstelleSchichtenFuerZeitraum(Collection, Zeitraum)
M: 0 C: 144
100%
M: 0 C: 12
100%
M: 0 C: 7
100%
M: 0 C: 29
100%
M: 0 C: 1
100%
getInstance()
M: 0 C: 8
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
lambda$befuelleSchicht$10(ProduktionsAuftrag, Maschine)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$befuelleSchicht$11(Schicht, ProduktionsAuftrag, Maschine)
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$befuelleSchicht$12(Schicht, ProduktionsAuftrag, Maschine)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$erstelleMittelfristigePlanung$0(Schicht)
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$erstelleMittelfristigePlanung$1(List, Collection, List, Collection, Fraction, Collection)
M: 0 C: 15
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
lambda$erstelleMittelfristigePlanung$2(List, Collection, List, Collection, Fraction, Collection)
M: 0 C: 15
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
lambda$erstelleMittelfristigePlanung$3(List, Collection, List, Collection, Fraction, Collection)
M: 0 C: 15
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
lambda$erstelleOptimalenSchichtplan$4(Schicht, Collection, VoraussichtlicheDokumentenklasse)
M: 0 C: 10
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
lambda$erstelleOptimalenSchichtplan$5(Schicht, VoraussichtlicheDokumentenklasse)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$erstelleOptimalenSchichtplan$8(List, Dokumentenklasse)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
lambda$erstelleOptimalenSchichtplan$9(Map, ProduktionsAuftrag)
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
lambda$null$6(Dokumentenklasse, Dokumentenklasse)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
lambda$null$7(Dokumentenklasse, ProduktionsAuftrag)
M: 0 C: 7
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%

Coverage

1: package planung.wochenplanung;
2:
3: import auftraege.Dokumentenklasse;
4: import auftraege.ProduktionsAuftrag;
5: import auftraege.VoraussichtlicheDokumentenklasse;
6: import auftraege.auftragsBildungsParameter.MaxKundenauftraege;
7: import maschine.Maschine;
8: import maschine.faehigkeit.MaschinenFaehigkeit;
9: import planung.Begruendung;
10: import planung.MittelfristigePlanung;
11: import planung.Schicht;
12: import planung.SchichtZeit;
13: import produktionsauftrag.ProduktionsAuftragServiceImpl;
14: import rollenbelegung.Produktionsplaner;
15: import util.Fraction;
16: import util.Pair;
17: import util.exceptions.SollteNichtPassierenException;
18: import zeit.eintraege.UhrzeitZeitraum;
19: import zeit.eintraege.Zeitraum;
20:
21: import java.time.DayOfWeek;
22: import java.time.LocalDateTime;
23: import java.util.ArrayList;
24: import java.util.Collection;
25: import java.util.Comparator;
26: import java.util.HashMap;
27: import java.util.Iterator;
28: import java.util.LinkedList;
29: import java.util.List;
30: import java.util.Map;
31: import java.util.Optional;
32: import java.util.concurrent.CompletableFuture;
33: import java.util.concurrent.ExecutionException;
34: import java.util.stream.Collectors;
35: import java.util.stream.Stream;
36:
37: /**
38: * Hier wird eine Planungsstrategie festgelegt, die beschreibt, was alles am Anfang gemacht werden muss.
39: */
40: public final class StandardStrategie implements PlanungsStrategie {
41:         private static volatile StandardStrategie instance;
42:
43:         private StandardStrategie() {
44:         }
45:
46:         /**
47:          * @return liefert die Instanz der Klasse StandardStrategie.
48:          */
49:         public static StandardStrategie getInstance() {
50:•                if (StandardStrategie.instance == null) {
51:                         StandardStrategie.instance = new StandardStrategie();
52:                 }
53:                 return StandardStrategie.instance;
54:         }
55:
56:         @Override
57:         public MittelfristigePlanung erstelleMittelfristigePlanung(
58:                         final Zeitraum zeitraum,
59:                         final Collection<SchichtZeit> schichtZeiten,
60:                         final List<Dokumentenklasse> dokumentenklassen,
61:                         final Collection<VoraussichtlicheDokumentenklasse> voraussichtlicheDokumentenklassen,
62:                         final Collection<Maschine> maschinen,
63:                         final Fraction produktionssatz) {
64:
65:                 final List<Schicht> schichten = this.erstelleSchichtenFuerZeitraum(schichtZeiten, zeitraum);
66:                 schichten.sort(Comparator.comparing(schicht -> schicht.getZeitraum().getVon()));
67:                 final CompletableFuture<Pair<List<Schicht>, Map<ProduktionsAuftrag, Begruendung>>> bestCase =
68:                                 CompletableFuture.supplyAsync(() -> this.erstelleOptimalenSchichtplan(
69:                                 this.copy(schichten),
70:                                 maschinen,
71:                                 new ArrayList<>(dokumentenklassen),
72:                                 voraussichtlicheDokumentenklassen,
73:                                 produktionssatz,
74:                                 MittelfristigePlanung.SZENARIO.BestCase,
75:                                 schichtZeiten));
76:                 final CompletableFuture<Pair<List<Schicht>, Map<ProduktionsAuftrag, Begruendung>>> averageCase =
77:                                 CompletableFuture.supplyAsync(() -> this.erstelleOptimalenSchichtplan(
78:                                 this.copy(schichten),
79:                                 maschinen,
80:                                 new ArrayList<>(dokumentenklassen),
81:                                 voraussichtlicheDokumentenklassen,
82:                                 produktionssatz,
83:                                 MittelfristigePlanung.SZENARIO.AverageCase,
84:                                 schichtZeiten));
85:                 final CompletableFuture<Pair<List<Schicht>, Map<ProduktionsAuftrag, Begruendung>>> worstCase =
86:                                 CompletableFuture.supplyAsync(() -> this.erstelleOptimalenSchichtplan(
87:                                 this.copy(schichten),
88:                                 maschinen,
89:                                 new ArrayList<>(dokumentenklassen),
90:                                 voraussichtlicheDokumentenklassen,
91:                                 produktionssatz,
92:                                 MittelfristigePlanung.SZENARIO.WorstCase,
93:                                 schichtZeiten));
94:
95:                 try {
96:                         return MittelfristigePlanung.create(
97:                                         bestCase.get().getFirst(),
98:                                         bestCase.get().getSecond(),
99:                                         averageCase.get().getFirst(),
100:                                         averageCase.get().getSecond(),
101:                                         worstCase.get().getFirst(),
102:                                         worstCase.get().getSecond());
103:                 } catch (final InterruptedException | ExecutionException e) {
104:                         throw new SollteNichtPassierenException("es ist ein Fehler beim Ausführen des CompletableFuture passiert :(");
105:                 }
106:         }
107:
108:         /**
109:          * @param schichten
110:          *                 zu kopierende Schichten
111:          *
112:          * @return erstellt eine Liste von den Schichten, in welcher Jede dieser Schichten eine Kopie von sich ist.
113:          */
114:         private List<Schicht> copy(final List<Schicht> schichten) {
115:                 return schichten.stream().map(Schicht::copy).collect(Collectors.toList());
116:         }
117:
118:
119:         /**
120:          * Der Schichtplan wird erstellt, indem sowohl die Produktionsaufträge aufsteigend nach ihrer Frist, als auch die Schichten aufsteigend nach ihrem Beginnzeitpunkt
121:          * sortiert werden. Diese beiden Prozesse könnten parallel ablaufen, was im aktuellen Implementierungsstand jedoch nicht geschieht. Daraufhin wird über die
122:          * Schichten iteriert und jede Schicht wird mit Produktionsaufträgen aufgefüllt.
123:          *
124:          * @param schichten
125:          *                 Schichten, die belegt werden sollen.
126:          * @param maschinen
127:          *                 Maschinen, die zur Verfügung stehen.
128:          * @param dokumentenklassen
129:          *                 Dokumentenklassen, die alle vor Ablauf ihrer Frist fertig gestellt werden sollen.
130:          * @param produktionssatz
131:          *                 Produktionssatz, welcher zur Sicherheit gesetzt werden kann. Wenn er bei <b>100%</b> liegt, laufen sämtliche Maschinen auf voller Last.
132:          *                 <p>
133:          *                 Um eine Planungssicherheit einbauen zu können, kann der Satz beispielsweise auf <b>80%</b> festgelegt werden, um mit nur 80%igen
134:          *                 Maschinengeschwindigkeiten zu rechnen.
135:          *
136:          * @return eine Collection von {@link Schicht Schichten}, die die Belegung repräsentiert.
137:          */
138:         private Pair<List<Schicht>, Map<ProduktionsAuftrag, Begruendung>> erstelleOptimalenSchichtplan(
139:                         final List<Schicht> schichten,
140:                         final Collection<Maschine> maschinen,
141:                         final List<Dokumentenklasse> dokumentenklassen,
142:                         final Collection<VoraussichtlicheDokumentenklasse> voraussichtlicheDokumentenklassen,
143:                         final Fraction produktionssatz,
144:                         final MittelfristigePlanung.SZENARIO szenario,
145:                         final Collection<SchichtZeit> schichtzeiten) {
146:                 final Map<ProduktionsAuftrag, Begruendung> uebrigeAuftraege = new HashMap<>();
147:                 final List<ProduktionsAuftrag> produktionsAuftraege = this.dokumentenklassenToProduktionsauftraege(dokumentenklassen);
148:                 produktionsAuftraege.sort(Comparator.comparing(ProduktionsAuftrag::getFrist));
149:•                for (final Schicht schicht : schichten) {
150:•                        switch (szenario) {
151:                                 case BestCase://donothing
152:                                         break;
153:                                 case AverageCase:
154:                                         produktionsAuftraege.addAll(this.dokumentenklassenToProduktionsauftraege(voraussichtlicheDokumentenklassen
155:                                                         .stream()
156:                                                         .map(v -> v.toDokumentenklasseAverageCase(schicht.getZeitraum().getVon(),
157:                                                                         this.berechneAnzahlDerSchichtenInDieDieseVoraussichtlicheDokumentenklasseFallenKoennte(v, schichtzeiten)))
158:                                                         .filter(Optional::isPresent)
159:                                                         .map(Optional::get)
160:                                                         .collect(Collectors.toList())));
161:                                         break;
162:                                 case WorstCase:
163:                                         produktionsAuftraege.addAll(this.dokumentenklassenToProduktionsauftraege(voraussichtlicheDokumentenklassen
164:                                                         .stream()
165:                                                         .map(v -> v.toDokumentenklasseWorstCase(schicht.getZeitraum().getVon()))
166:                                                         .filter(Optional::isPresent)
167:                                                         .map(Optional::get)
168:                                                         .filter(dokumentenklasse -> produktionsAuftraege
169:                                                                         .stream()
170:                                                                         .noneMatch(produktionsAuftrag -> produktionsAuftrag.getDokumentenklassen()
171:                                                                                         .stream()
172:                                                                                         .anyMatch(dokumentenklasseDesProduktionsauftrags -> dokumentenklasse.getId()
173:                                                                                                         .equals(dokumentenklasseDesProduktionsauftrags.getId()))))
174:                                                         .collect(Collectors.toList())));
175:                                         break;
176:                                 default:
177:                                         throw new SollteNichtPassierenException("Hier muss ein weiteres Szenario aus MittelfristigePlanung.SZENARIO implementiert werden");
178:
179:                         }
180:                         uebrigeAuftraege.putAll(this.befuelleSchicht(schicht, produktionsAuftraege, maschinen, produktionssatz));
181:                 }
182:                 produktionsAuftraege.forEach(p -> uebrigeAuftraege.put(p, Begruendung.AlleSchichtenVoll));
183:                 return Pair.create(schichten, uebrigeAuftraege);
184:         }
185:
186:         private int berechneAnzahlDerSchichtenInDieDieseVoraussichtlicheDokumentenklasseFallenKoennte(
187:                         final VoraussichtlicheDokumentenklasse v,
188:                         final Collection<SchichtZeit> schichtzeiten) {
189:                 return this.erstelleSchichtenFuerZeitraum(schichtzeiten, v.getZeitraum()).size();
190:         }
191:
192:         private List<ProduktionsAuftrag> dokumentenklassenToProduktionsauftraege(final List<Dokumentenklasse> dokumentenklassen) {
193:                 return new ProduktionsAuftragServiceImpl()
194:                                 .erstelleProduktionsauftraege(Stream.of(new MaxKundenauftraege(1)).collect(Collectors.toSet()), dokumentenklassen)
195:                                 .getSecond();
196:         }
197:
198:         /**
199:          * Die Befüllung einer Schicht mit Produktionsaufträgen geschieht, indem für jeden Produktionsauftrag eine Liste von kompatiblen Maschinen für jede seiner
200:          * benötigten Fähigkeiten (Drucken, Kuvertieren, ggf irgendwann noch weitere) gesammelt wird. Ist für eine dieser Fähigkeiten keine Maschine verfügbar, wird hier
201:          * eine Exception ausgelöst. Falls doch, werden die Maschinen nach ihrer Geschwindigkeit sortiert, woraufhin über sie iteriert wird. Wenn eine Maschine in der
202:          * Schicht bereits so voll belegt ist, dass sie den hinzuzufügenden Produktionsauftrag nicht mehr in dieser Schicht verarbeiten kann, wird versucht, ihn auf die
203:          * nächste Maschine zu legen. Falls dies auch nicht möglich ist, wird dieser Vorgang so häufig wiederholt, bis keine Maschinen mehr zur Verfügung stehen. In
204:          * diesem Fall muss der Produktionsauftrag wohl oder übel in der darauffolgenden Schicht verarbeitet werden. Falls doch eine Maschine zur Verfügung stehen sollte,
205:          * wird der Auftrag dieser Maschine hinzugefügt und, falls keine weitere Fähigkeit für die Verarbeitung des Auftrags benötigt wird, aus der Liste der
206:          * Produktionsaufträge entfernt, um nicht in der folgenden Schicht erneut verarbeitet zu werden.
207:          *
208:          * @param schicht
209:          *                 Schicht, welche befüllt werden soll.
210:          * @param produktionsAuftraege
211:          *                 Produktionsaufträge, die alle innerhalb ihrer Frist verarbeitet werden sollen.
212:          * @param maschinen
213:          *                 sämtliche Maschinen, die für die zu befüllende Schicht zur Verfügung stehen sollen.
214:          * @param produktionssatz
215:          *                 Produktionssatz, welcher zur Sicherheit gesetzt werden kann. Wenn er bei <b>100%</b> liegt, laufen sämtliche Maschinen auf voller Last. Um eine
216:          *                 Planungssicherheit einbauen zu können, kann der Satz beispielsweise auf <b>80%</b> festgelegt werden,
217:          */
218:         private Map<ProduktionsAuftrag, Begruendung> befuelleSchicht(
219:                         final Schicht schicht,
220:                         final List<ProduktionsAuftrag> produktionsAuftraege,
221:                         final Collection<Maschine> maschinen,
222:                         final Fraction produktionssatz) {
223:
224:                 final Map<ProduktionsAuftrag, Begruendung> uebrigeAuftraege = new HashMap<>();
225:                 produktionsAuftraege.sort(Comparator.comparing(ProduktionsAuftrag::getFrist));
226:
227:                 final Produktionsplaner produktionsplaner = new Produktionsplaner();
228:                 final Iterator<ProduktionsAuftrag> produktionsAuftragIterator = produktionsAuftraege.iterator();
229:•                while (produktionsAuftragIterator.hasNext()) {
230:                         final ProduktionsAuftrag produktionsAuftrag = produktionsAuftragIterator.next();
231:•                        if (produktionsAuftrag.getFrist().isBefore(schicht.getZeitraum().getBis())) {
232:                                 uebrigeAuftraege.put(produktionsAuftrag, Begruendung.SLAVerpennt);
233:                                 produktionsAuftragIterator.remove();
234:                                 continue;
235:                         }
236:                         //eine Liste (1) von Listen (2) von Maschinen, in welcher aus jeder Liste (1) genau eine Maschine aus der Liste (2) dem Produktionsauftrag zugeordnet
237:                         // werden muss.
238:                         final List<Map.Entry<MaschinenFaehigkeit, Collection<Maschine>>> entries =
239:                                         produktionsplaner
240:                                                         .getQualifizierteMaschinenProBenoetigteFaehigkeit(maschinen, produktionsAuftrag)
241:                                                         .entrySet()
242:                                                         .stream()
243:                                                         .sorted(Comparator.comparing(Map.Entry::getKey))
244:                                                         .collect(Collectors.toList());
245:
246:                         final Iterator<Map.Entry<MaschinenFaehigkeit, Collection<Maschine>>> listeVonMaschinenListenProBenoetigteFaehigkeitIterator = entries.iterator();
247:•                        while (listeVonMaschinenListenProBenoetigteFaehigkeitIterator.hasNext()) {
248:                                 final Map.Entry<MaschinenFaehigkeit, Collection<Maschine>> entry = listeVonMaschinenListenProBenoetigteFaehigkeitIterator.next();
249:                                 final List<Maschine> maschinenListe = entry.getValue()
250:                                                 .stream()
251:                                                 .sorted(Comparator.comparing(maschine -> maschine.berechneBenoetigteZeit(produktionsAuftrag)))
252:                                                 .collect(Collectors.toList());
253:•                                if (maschinenListe.isEmpty()) {
254:                                         uebrigeAuftraege.put(produktionsAuftrag, Begruendung.erstelleBegruendungFuerFaehigkeit(entry.getKey()));
255:                                         maschinen.stream()
256:                                                         .filter(maschine -> schicht.getDokumentenklassen(maschine).containsAll(produktionsAuftrag.getDokumentenklassen()))
257:                                                         .forEach(maschine -> schicht.getMaschinenProduktionsauftraegeMap().get(maschine).remove(produktionsAuftrag));
258:                                         produktionsAuftragIterator.remove();
259:                                         break;
260:                                 }
261:                                 Maschine maschineDieDenAuftragHabenSollte = null; // nach Durchlauf der folgenden Schleife liegt hier die Maschine drin, die den Auftrag letztenendes
262:                                 // verarbeiten soll. Wenn Sie nicht diesen Auftrag in der Schicht zugeordnet haben, darf er auch keiner weiteren Maschine (mit anderen
263:                                 // Maschinenfähigkeit) zugeordnet werden, da ein Auftrag, der in dieser Schicht nicht gedruckt werden kann, erst recht nicht kuvertiert werden kann.
264:•                                for (final Maschine maschine : maschinenListe) {
265:                                         maschineDieDenAuftragHabenSollte = maschine;
266:                                         //der schnellsten Maschine, die noch Kapazitäten hat, wird der Produktionsauftrag hinzugefügt und dann diese Schleife verlassen
267:•                                        if (schicht.addProduktionsauftrag(produktionsAuftrag, maschine, produktionssatz)) {
268:•                                                if (!listeVonMaschinenListenProBenoetigteFaehigkeitIterator.hasNext()) {
269:                                                         produktionsAuftragIterator.remove();
270:                                                 }
271:                                                 break; //hier braucht keiner weiteren von diesen Maschinen ein Produktionsauftrag zugeordnet werden, es kann weiter gemacht werden mit
272:                                                 // der ersten Liste (1), die Schleife wird verlassen
273:                                         }
274:                                 }
275:•                                if (!schicht.getDokumentenklassen(maschineDieDenAuftragHabenSollte).containsAll(produktionsAuftrag.getDokumentenklassen())) {
276:                                         // hier ist der oben beschriebene Fall eingetreten:
277:                                         // Der Maschine ist der Auftrag in der Schicht NCIHT zugeordnet worden. Somit darf er auch keiner weiteren Maschine (mit anderen
278:                                         // Maschinenfähigkeit) zugeordnet werden, da ein Auftrag, der in dieser Schicht nicht gedruckt werden kann, erst recht nicht kuvertiert werden
279:                                         // kann.
280:                                         break;
281:                                 }
282:                         }
283:                 }
284:                 return uebrigeAuftraege;
285:         }
286:
287:
288:         /**
289:          * diese Methode liefert eine Liste von Schichten für ein gegebenen Zeitraum auf der Basis der “schichtZeiten” ohne Berücksichtigung der Maschinen. Dabei wird
290:          * der zeitraum in einzelne Tage gesplittet und es wird über die Liste der “Sub-Zeiträumen” iteriert, wobei für jeden Wochentag eine “passende” Planung aus
291:          * der vordefinierten schichtZeiten geholt wird. Wenn für einen Tag des Zeitraums keine schichtZeiten existieren (z. B. Samstag und Sonntag), wird dieser Tag nicht
292:          * weiter berücksichtigt und es wird ein nächstes Sub-Zeitraum angeguckt.
293:          *
294:          * @param schichtZeiten
295:          *                 Schichtzeiten, zu welchen gearbeitet wird (siehe {@link SchichtZeit}).
296:          * @param zeitraum
297:          *                 Zeitraum, für welchen die Schichtzeiten erstellt werden sollen.
298:          *
299:          * @return erstellt eine Liste von Schichten, welche in den gegebenen Zeitraum fallen auf Basis der übergebenen Schichtzeiten.
300:          */
301:         public List<Schicht> erstelleSchichtenFuerZeitraum(final Collection<SchichtZeit> schichtZeiten, final Zeitraum zeitraum) {
302:
303:                 //zu jedem wochentag eine Liste von Schichtzeiten
304:                 final Map<DayOfWeek, List<SchichtZeit>> wochentagSchichtzeitenMap = schichtZeiten.stream().collect(Collectors.groupingBy(SchichtZeit::getWochentag));
305:
306:                 // die Schichtplanung, die von der Methode als Ergebnis geliefert wird
307:                 final List<Schicht> schichtPlan = new LinkedList<>();
308:
309:                 //gegebenes Zeitraum wird in einzelne Tagen gesplittet
310:                 final Collection<Zeitraum> tagesZeitraeume = zeitraum.splitInEinzelneTage();
311:
312:                 // es wird über die Tageszeiträume iteriert und solange es die Tagen gibt
313:                 final Iterator<Zeitraum> tagesZeitraeumeIterator = tagesZeitraeume.iterator();
314:•                while (tagesZeitraeumeIterator.hasNext()) {
315:                         final Zeitraum tagesZeitraum = tagesZeitraeumeIterator.next();
316:
317:                         // wenn in der Planung solche Wochentag existiert, geht es weiter mit der Uhrzeiträumen:
318:•                        if (wochentagSchichtzeitenMap.containsKey(tagesZeitraum.getWochentag())) {
319:                                 //das hier ist eine Liste sämtlicher Uhzeiträume, für die Schichten anfallen an dem Tag, der von dem Tageszeitraum umspannt wird.
320:                                 final List<UhrzeitZeitraum> uhrzeitraeumeDesTages = wochentagSchichtzeitenMap.get(tagesZeitraum.getWochentag())
321:                                                 //hier if solcher Tag in der Planung vorhanden,
322:                                                 // dann weitermachen, sonst nächsten tagesZeitraum angucken!!! holen der Schichtzeiten
323:                                                 // des Wochentages dieses einen Tageszeitraumes,
324:                                                 // den wir gerade an der Hand haben
325:                                                 .stream() //daraus wieder einen Stream basteln
326:                                                 .map(SchichtZeit::getUhrzeitRaum) //aus jeder dieser Schichtzeiten holen wir uns den Uhrzeitraum
327:                                                 .collect(Collectors.toList()); //das Ergebnis in eine Liste verpacken
328:
329:                                 // es wird über gelieferte Uhrzeiträume iteriert:
330:•                                for (final UhrzeitZeitraum current : uhrzeitraeumeDesTages) {
331:•                                        if (tagesZeitraum.getBis().toLocalTime().isAfter(current.getBis())
332:•                                                        || (tagesZeitraum.getBis().toLocalTime().equals(current.getBis()))) {
333:•                                                if (current.getBis().isAfter(current.getVon())) {
334:
335:                                                         final LocalDateTime bis = tagesZeitraum.getVon().withHour(current.getBis().getHour()).withMinute(current.getBis().getMinute());
336:                                                         final LocalDateTime von = tagesZeitraum.getVon().withHour(current.getVon().getHour()).withMinute(current.getVon().getMinute());
337:                                                         final Zeitraum neueZeitraum = Zeitraum.create(von, bis);
338:                                                         final Schicht schicht = Schicht.createOhneMaschinen(neueZeitraum);
339:                                                         schichtPlan.add(schicht);
340:                                                 } else {
341:                                                         final LocalDateTime von = tagesZeitraum.getVon().withHour(current.getVon().getHour()).withMinute(current.getVon().getMinute());
342:                                                         final LocalDateTime bis = tagesZeitraum.getVon().plusDays(1).withHour(current.getBis().getHour()).withMinute(current.getBis().getMinute());
343:                                                         final Zeitraum neueZeitraum2 = Zeitraum.create(von, bis);
344:                                                         final Schicht schicht = Schicht.createOhneMaschinen(neueZeitraum2);
345:                                                         schichtPlan.add(schicht);
346:                                                 }
347:                                         }
348:                                 }
349:                         }
350:
351:                 }
352:                 return schichtPlan;
353:         }
354:
355: }