Projekt

Obecné

Profil

Stáhnout (19.9 KB) Statistiky
| Větev: | Revize:
1
package data;
2

    
3
import gui.Window;
4

    
5
import java.io.BufferedWriter;
6
import java.io.File;
7
import java.io.IOException;
8
import java.nio.charset.Charset;
9
import java.nio.file.Files;
10
import java.nio.file.Path;
11
import java.nio.file.StandardOpenOption;
12
import java.time.LocalDate;
13
import java.time.format.DateTimeFormatter;
14
import java.util.*;
15

    
16
/**
17
 *
18
 * Trida prochazi seznam spoju, casovych kodu, linek a pevnych kodu a na jejich zaklade naplnuje a generuje bitmapy,
19
 * ktere zapisuje do vystupniho souboru
20
 *
21
 * @author  Daniel Stus, Marek Sobota, Lukas Scurko, Jan Jirman
22
 * @version 1.0
23
 *
24
 */
25
public class BitmapBuilder {
26

    
27
    //-------------- Atributy --------------/
28

    
29
    /** Seznam uchovavajici vsechny zaznamy souboru pevnykod.txt */
30
    private ArrayList<JDFPevnykodRecord> pevnykod = new ArrayList<>();
31

    
32
    /** Seznam uchovavajici vsechny zaznamy pozadovanych linek souboru caskody.txt */
33
    private ArrayList<JDFCaskodyRecord> caskody = new ArrayList<>();
34

    
35
    /** Seznam uchovavajici vsechny zaznamy pozadovanych linek souboru spoje.txt */
36
    private ArrayList<JDFSpojeRecord> spoje = new ArrayList<>();
37

    
38
    /** Seznam uchovavajici vsechny vygenerovane bitmapy */
39
    private ArrayList<Bitmap> bitmaps = new ArrayList<>();
40

    
41
    /** Seznam uchovavajici vsechny uzivatelem zadane linky pro generaci */
42
    private List<String> lineList;
43

    
44
    /** Seznam uchovavajici vsechny uzivatelem zadane neuplne linky pro generaci */
45
    private List<String> pseudoLines;
46

    
47
    /** Cesta k vystupnimu souboru pro vypis vygenerovanych bitmap */
48
    private Path outputFile;
49

    
50
    /** Instance GUI pro vypis kontrolnich zprav */
51
    private Window window;
52

    
53

    
54
    //-------------- Konstruktor -------------/
55

    
56

    
57
    /**
58
     * Konstruktor, prebira instanci okna pro vypisy, vytvari a kontroluje vystupni soubor
59
     *
60
     * @param window Instance tridy pro vypisy
61
     * @param outputPath Cesta k vystupnimu souboru
62
     */
63
    public BitmapBuilder(Window window, File outputPath){
64
    	this.window = window;
65
    	window.printMessage("Vytvořen BitmapBuilder");
66

    
67
    	// Vytvoření výstupního souboru
68
    	this.outputFile = outputPath.toPath();
69
        try {
70
            if (Files.notExists(outputFile)) {
71
                Files.createFile(outputFile);
72
                window.printMessage("Vytvořen soubor: "+outputFile.toString());
73
            }
74
            else {
75
                window.printMessage("Výstupní soubor již existuje, přepisuji...");
76
                Files.deleteIfExists(outputFile);
77
                Files.createFile(outputFile);
78
            }
79

    
80
        } catch (IOException e) {
81
            e.printStackTrace();
82
            window.printMessage("Neočekávaná chyba při práci s výstupním souborem");
83
        }
84
    }
85

    
86
    //----------------- Metody ----------------/
87

    
88
    /**
89
     * Metoda naplni seznam pevnych kodu
90
     *
91
     * @param loadedData kompletni nactena dana souboru pevnykod
92
     */
93
    public void getPevnyKod(ArrayList<String[]> loadedData){
94
        JDFPevnykodRecord pevnykodRecord;
95
        for(String[] record : loadedData){
96
                pevnykodRecord = new JDFPevnykodRecord(record);
97
                pevnykod.add(pevnykodRecord);
98
        }
99
        window.printMessage("Načten soubor Pevnykod.txt");
100
    }
101

    
102
    /**
103
     * Metoda naplni seznam caskody, vsemi zaznamy odpovidajicih pozadovanym linkam a caskodum s numerickou hodnotou
104
     *
105
     * @param loadedData kompletni nactena dana souboru caskody
106
     */
107
    public void getCaskody(ArrayList<String[]> loadedData){
108
        JDFCaskodyRecord caskodyRecord;
109
        for(String[] record : loadedData){
110
            if (lineList.contains(record[0]) && record[4].matches("\\d+")) {
111
                caskodyRecord = new JDFCaskodyRecord(record);
112
                caskody.add(caskodyRecord);
113
            }
114
        }
115
        window.printMessage("Načteny požadované linky ze souboru Caskody.txt");
116
    }
117

    
118
    /**
119
     * Metoda naplni seznam spoju, vsemi zaznamy odpovidajicih pozadovanym linkam
120
     *
121
     * @param loadedData kompletni nactena dana souboru spoje
122
     */
123
    public void getSpoje(ArrayList<String[]> loadedData){
124
        JDFSpojeRecord spojeRecord;
125
        for(String[] record : loadedData){
126
            if (lineList.contains(record[0])) {
127
                spojeRecord = new JDFSpojeRecord(record);
128
                spoje.add(spojeRecord);
129
            }
130
        }
131
        window.printMessage("Načteny požadované linky ze souboru Spoje.txt");
132
    }
133

    
134
    /**
135
     * Naplni seznam uzivatelsky zadanych linek
136
     *
137
     * @param lineList seznam uzivatelskych linek
138
     * @return true - pokud se podarilo naplnit seznam
139
     *          false - pokud se nepodarilo naplnit seznam
140
     */
141
    public boolean initLineList(List[] lineList){
142
        this.lineList = lineList[0];
143
        this.pseudoLines = lineList[1];
144
        window.printMessage("Načten uživatelský seznam linek");
145
        window.printMessage("Nalezené linky: "+this.lineList);
146
        if(this.lineList.size() < 1){
147
        	window.printMessage("Seznam linek je prázdný!");
148
        	return false;
149
        }
150

    
151
        if(this.pseudoLines.size() > 0) {
152
            window.printMessage("Načten uživatelský seznam pseudo linek");
153
            window.printMessage("Nalezené pseudo linky: "+pseudoLines);
154
        }
155
        return true;
156

    
157
    }
158

    
159

    
160
    /**
161
     * Metoda overi jestli je obdobi casoveho omezeni spada do obdobi pro generovanou bitmapu
162
     *
163
     * @param dateFrom pocatek generovaneho obdobi bitmapy
164
     * @param dateTo konec generovaneho obdobi bitmapy
165
     * @param dateFromHardCode pocatek obdobi caskoveho omezeni
166
     * @param dateToHardCode konec obdobi casoveho omezeni
167
     * @return Vrati {@code true} pokud casove omezeni spada do odobi generavaneho bitmapou, {@code false} pokud casove omezeni nespada do obdobi generovaneho bitmapou
168
     */
169
    public boolean isInRange(LocalDate dateFrom, LocalDate dateTo, String dateFromHardCode, String dateToHardCode) {
170
        //Formát datumu v Caskody.txt např: - 09022018
171
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("ddMMyyyy");
172

    
173
        LocalDate hardCodeDateFrom;
174
        LocalDate hardCodeDateTo;
175

    
176
        //Pokud neni zadano rozmezi
177
        if (dateFromHardCode.equals("") && dateToHardCode.equals("")) {
178
            return true;
179
        }
180
            //Naparsuj pouze pokud datum do existuje
181
         else if (!dateToHardCode.equals("")) {
182
                hardCodeDateFrom = LocalDate.parse(dateFromHardCode, formatter);
183
                hardCodeDateTo = LocalDate.parse(dateToHardCode, formatter);
184

    
185
                if (hardCodeDateFrom.isBefore(dateFrom) && hardCodeDateTo.isAfter(dateTo)) {
186
                    return true;
187
                }
188

    
189
                if (!hardCodeDateFrom.isBefore(dateFrom) && !hardCodeDateTo.isAfter(dateTo)) {
190
                    return true;
191
                }
192

    
193
                if (hardCodeDateFrom.isBefore(dateFrom) && !hardCodeDateTo.isAfter(dateTo) && hardCodeDateTo.isAfter(dateFrom)) {
194
                    return true;
195
                }
196

    
197
                if (hardCodeDateFrom.isAfter(dateFrom) && hardCodeDateTo.isAfter(dateTo) && !hardCodeDateFrom.isAfter(dateTo)) {
198
                    return true;
199
                }
200

    
201
            }
202

    
203
            //Pokud se jedná pouze o jeden den
204
            else {
205
                hardCodeDateFrom = LocalDate.parse(dateFromHardCode, formatter);
206

    
207
                if (!hardCodeDateFrom.isBefore(dateFrom) && !hardCodeDateFrom.isAfter(dateTo)) {
208
                    return true;
209
                }
210

    
211
            }
212

    
213
        return false;
214

    
215
    }
216

    
217
    /**
218
     * Metoda orizne, nastavi a vrati obdobi pro casove omezeni, tak aby spadalo do obdobi generavaneho bitmapou, pro naplneni
219
     *
220
     * @param dateFrom pocatek generovaneho obdobi bitmapy
221
     * @param dateTo konec generovaneho obdobi bitmapy
222
     * @param dateFromHardCode pocatek obdobi casoveho omezeni
223
     * @param dateToHardCode konec obdobi casoveho omezeni
224
     * @return pole s pocatkem a koncem obdobi casoveho omezeni, index 0 -> pocatek, index 1 -> konec
225
     */
226
    private LocalDate[] setHardCodeRange(LocalDate dateFrom, LocalDate dateTo, String dateFromHardCode, String dateToHardCode) {
227
        //Formát datumu v Caskody.txt např: - 09022018
228
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("ddMMyyyy");
229

    
230
        LocalDate[] hardCodeRange = new LocalDate[2];
231
        LocalDate hardCodeDateFrom;
232
        LocalDate hardCodeDateTo;
233

    
234
        //Pokud neni zadano rozmezi
235
        if (dateFromHardCode.equals("") && dateToHardCode.equals("")) {
236
            hardCodeRange[0] = dateFrom;
237
            hardCodeRange[1] = dateTo;
238
        }
239

    
240
            //Naparsuj pouze pokud datum existuje
241
            else if (!dateToHardCode.equals("")) {
242
                hardCodeDateFrom = LocalDate.parse(dateFromHardCode, formatter);
243
                hardCodeDateTo = LocalDate.parse(dateToHardCode, formatter);
244

    
245

    
246
                if (!hardCodeDateFrom.isBefore(dateFrom) && !hardCodeDateFrom.isAfter(dateTo)) {
247
                    hardCodeRange[0] = hardCodeDateFrom;
248
                }
249
                else hardCodeRange[0] = dateFrom;
250

    
251
                if (!hardCodeDateTo.isAfter(dateTo) && !hardCodeDateTo.isBefore(dateFrom)) {
252
                    hardCodeRange[1] = hardCodeDateTo;
253
                }
254
                else hardCodeRange[1] = dateTo;
255

    
256
            }
257

    
258
            //Existuje jeden den
259
            else {
260
                hardCodeDateFrom = LocalDate.parse(dateFromHardCode, formatter);
261
                hardCodeRange[0] = hardCodeDateFrom;
262
                hardCodeRange[1] = null;
263
            }
264

    
265
            return hardCodeRange;
266

    
267
        }
268

    
269
    /**
270
     * Metoda overi zda-li zadany retezec odpovida cislene hodnote
271
     *
272
     * @param inputData retezec pro overeni
273
     * @return Vrati {@code true} pokud je retezec cislem, v opacnem pripade vrati {@code false}
274
     */
275
    private static boolean isNumeric(String inputData) {
276
        return inputData.matches("[-+]?\\d+(\\.\\d+)?");
277
    }
278

    
279

    
280
    /**
281
     * Zavola prislusne metody bitmapy pro naplneni podle casoveho kodu
282
     *
283
     * @param bitmap bitmapa pro naplneni
284
     * @param dateFrom pocatek obdobi pro naplneni
285
     * @param dateTo konec obdobi pro naplneni
286
     * @param TimeCodeType cislo casoveho kodu
287
     */
288
    private void fillBitmap (Bitmap bitmap, LocalDate dateFrom, LocalDate dateTo, int TimeCodeType) {
289

    
290
        switch (TimeCodeType) {
291
            case 1: {
292
                if (dateTo!=null) bitmap.setHardCodeDays(dateFrom, dateTo, 1);
293
                else bitmap.setDay(dateFrom, 1);
294
                break;
295
            }
296
            case 2: {
297
                bitmap.setHardCodeDays(bitmap.getDateFrom(), bitmap.getDateTo(), 1);
298
                if (dateTo!=null) bitmap.setDaysInRange(dateFrom, dateTo, 1);
299
                else bitmap.setDay(dateFrom, 1);
300
                break;
301
            }
302
            case 3: {
303
                bitmap.setDay(dateFrom, 1);
304
                break;
305
            }
306
            case 4: {
307
                bitmap.setHardCodeDays(bitmap.getDateFrom(), bitmap.getDateTo(), 1);
308
                if (dateTo!=null) bitmap.unsetDaysInRange(dateFrom, dateTo);
309
                else bitmap.setDay(dateFrom, 0);
310
                break;
311
            }
312
            case 5: {
313
                bitmap.setHardCodeWeeks(1, 1);
314
                break;
315
            }
316
            case 6: {
317
                bitmap.setHardCodeWeeks(1, 0);
318
                break;
319
            }
320
            case 7: {
321
                bitmap.setHardCodeWeeksInRange(dateFrom, dateTo, 1, 1);
322
                break;
323
            }
324
            case 8: {
325
                bitmap.setHardCodeWeeksInRange(dateFrom, dateTo, 1, 0);
326
                break;
327
            }
328
            default: break;
329
        }
330

    
331
    }
332

    
333
    /**
334
     * Vygeneruje, naplni a prida do vysledneho seznamu vsechny pseudo bitmapy
335
     *
336
     * @param dateFrom pocatek obdobi pro bitmapu
337
     * @param dateTo konec obdobi pro bitmapu
338
     */
339
    public void generatePseudoBitmaps(LocalDate dateFrom, LocalDate dateTo) {
340

    
341
        for (String psLine : pseudoLines) {
342

    
343
            window.printMessage("Zpracovávám pseudo linku: "+psLine);
344

    
345
            LocalDate[] hardCodeRange;
346
            String[] plRecord = psLine.split("-", 2);
347
            Bitmap generatedBitmap = new Bitmap(dateFrom, dateTo, "000000", "0", plRecord[0], plRecord[1], "0");
348

    
349
            //Pokud nemá žádné časové omezení a žádný pevnýkód -> naplň jedničkami
350
            if (plRecord[0].equals("00") && plRecord[1].length() == 0) {
351
                generatedBitmap.fillWithOnes();
352
                bitmaps.add(generatedBitmap);
353
                continue;
354
            }
355

    
356
            //Pokud nemá spoj žádná omezení -> napln bitmapu podle pevnych kodu a přidej
357
            else if (plRecord[0].equals("00") && plRecord[1].length() > 0) {
358
                generatedBitmap.setHardCodeDays(dateFrom, dateTo, 1);
359
                bitmaps.add(generatedBitmap);
360
                continue;
361
            }
362

    
363
            else {
364
                for (JDFCaskodyRecord caskod : caskody) {
365
                    if (caskod.getTimeCode().equals(plRecord[0])) {
366
                        if (isInRange(dateFrom, dateTo, caskod.getStartDate(), caskod.getEndDate())) {
367
                            hardCodeRange = setHardCodeRange(dateFrom, dateTo, caskod.getStartDate(), caskod.getEndDate());
368
                            fillBitmap(generatedBitmap, hardCodeRange[0], hardCodeRange[1], Integer.parseInt(caskod.getTypeTimeCode()));
369
                        }
370
                    }
371
                }
372
            }
373

    
374

    
375
            //Jinak bitmapa byla již naplněna -> přidej
376
                bitmaps.add(generatedBitmap);
377

    
378

    
379
        }
380
    }
381

    
382
    /**
383
     * Metoda projde seznamy spoju, caskodu, pevnychkodu a linek na jejichz zaklade vygeneruje a naplni bitmapy v zadanem obdobi
384
     * vysledne bitmapy vypise v pozadovanem formatu do vystupniho souboru
385
     *
386
     * @param dateFrom pocatek obdobi pro bitmapu
387
     * @param dateTo konec obdobi pro bitmapu
388
     */
389
    public void writeBitmaps(LocalDate dateFrom, LocalDate dateTo) {
390
        
391
        try(BufferedWriter writer = Files.newBufferedWriter(outputFile, Charset.defaultCharset(), StandardOpenOption.APPEND)) {
392
            DateTimeFormatter format = DateTimeFormatter.ofPattern("d.M.yyyy");
393
            String currentLine =  spoje.get(0).getNumberLine();
394
            String currentTimeCode;
395
            String previousTimeCode;
396
            LocalDate[] hardCodeRange;
397

    
398
            //Výpis období do výstupního souboru, ve formátu: Období;dateFrom(d.M.yyyy);dateTo(d.M.yyyy)
399
            writer.write("Období;" + dateFrom.format(format)+ ";" + dateTo.format(format) + "\r\n\r\n");
400

    
401
            window.printMessage("Zpracovávám bitmapy...");
402
            window.printMessage("Zpracovávám linku: "+currentLine);
403

    
404

    
405
            //Pro každý spoj
406
            for (JDFSpojeRecord spoj : spoje) {
407
                currentTimeCode = "00";
408

    
409
                //Pokud se jedná o novou linku - Vypiš _______ ??? (Je potřeba) ???
410
                if (!currentLine.equals(spoj.getNumberLine())) {
411
                    currentLine = spoj.getNumberLine();
412
                    window.printMessage("Zpracovávám linku: "+currentLine);
413
                }
414

    
415
                //Výpis právě prozkoumávaného spoje
416
                String currentJoin = spoj.getNumberJoin();
417
                window.printMessage("- spoj: "+currentJoin);
418

    
419
                Bitmap generatedBitmap = new Bitmap(dateFrom, dateTo, currentLine, currentJoin, currentTimeCode, spoj.hardCodesToString(pevnykod), spoj.getNumberLineVersion());
420
                int viableTimeCodes = 0; //Počet časových kódu číslo 3 daného spoje
421
                int timeCodesInRange = 0; //Počet časových kódu aplikovaných na spoj
422

    
423
                previousTimeCode = "";
424

    
425
                for (JDFCaskodyRecord caskod : caskody) {
426

    
427

    
428
                    // Zda se jedná o aktuálně zkoumanou linku a spoj
429
                    if (currentLine.equals(caskod.getNumberLine()) && currentJoin.equals(caskod.getNumberJoin())) {
430

    
431
                        currentTimeCode =  caskod.getTimeCode();
432
                        generatedBitmap.setTimeCode(currentTimeCode);
433

    
434
                        if(caskod.getTypeTimeCode().matches("1|3|7|8")) viableTimeCodes++;
435

    
436
                        // Pokud se jedná o stejný spoj, ale jiný časový kód vytvoř novou bitmapu a přidej předchozí
437
                        if (!currentTimeCode.equals(previousTimeCode) && isNumeric(currentTimeCode) && !previousTimeCode.equals("")) {
438
                            bitmaps.add(generatedBitmap);
439
                            generatedBitmap = new Bitmap(dateFrom, dateTo, currentLine, currentJoin, currentTimeCode, spoj.hardCodesToString(pevnykod), spoj.getNumberLineVersion());
440
                        }
441

    
442

    
443
                         //Pokud je zkoumaný časový kód v rozsahu bitmapy
444
                        if (isInRange(dateFrom, dateTo, caskod.getStartDate(), caskod.getEndDate())) {
445
                            timeCodesInRange++;
446
                            hardCodeRange = setHardCodeRange(dateFrom, dateTo, caskod.getStartDate(), caskod.getEndDate());
447
                            fillBitmap(generatedBitmap, hardCodeRange[0], hardCodeRange[1], Integer.parseInt(caskod.getTypeTimeCode()));
448
                        }
449

    
450
                        previousTimeCode = currentTimeCode;
451
                    }
452
                }
453

    
454

    
455

    
456
                //Pokud nemá žádné časové omezení a žádný pevnýkód -> naplň jedničkami
457
                if (timeCodesInRange == 0 && spoj.getHardCodes().size() == 0 && viableTimeCodes == 0) {
458
                    generatedBitmap.fillWithOnes();
459
                    bitmaps.add(generatedBitmap);
460
                }
461

    
462
                //Pokud nemá spoj žádná omezení -> napln bitmapu podle pevnych kodu a přidej
463
                else if (timeCodesInRange == 0 && spoj.getHardCodes().size() > 0 && viableTimeCodes == 0) {
464
                    generatedBitmap.setHardCodeDays(dateFrom, dateTo, 1);
465
                    bitmaps.add(generatedBitmap);
466
                }
467

    
468
                //Jinak bitmapa byla již naplněna -> přidej
469
                else {
470
                    bitmaps.add(generatedBitmap);
471
                }
472
            }
473

    
474
                //Pokud existují nějaké pseudolinky -> naplň a přidej do seznamu generovaných bitmap
475
                if(pseudoLines.size() > 0) {
476
                    generatePseudoBitmaps(dateFrom, dateTo);
477
                }
478

    
479
                //Odstraň duplikátní bitmapy
480
                removeDuplicates();
481

    
482
                //Seřaď seznam bitmap
483
                Collections.sort(bitmaps);
484

    
485
                //Celkový počet vygenerovaných bitmap
486
                window.printMessage("Celkem vygenerováno: "+bitmaps.size()+" Bitmap");
487

    
488
                //Vypiš bitmapy do souboru
489
            for (Bitmap bitmap : bitmaps) {
490
                writer.write(bitmap.toString()+"\r\n");
491
            }
492

    
493

    
494
        } catch (IOException e) {
495
            e.printStackTrace();
496
            window.printMessage("Neočekávaná chyba při zapisování bitmapy");
497
        }
498
        window.printMessage("Bitmapy úspěšně zapsány");
499
    }
500

    
501
    /**
502
     * Odstraní duplikatni bitmapy
503
     */
504
    public void removeDuplicates() {
505
        Set<Bitmap> bitmapsWODuplicates = new TreeSet<>();
506
        bitmapsWODuplicates.addAll(this.bitmaps);
507
        this.bitmaps = new ArrayList<>(bitmapsWODuplicates);
508

    
509
    }
510

    
511
    /**
512
     * Vrati seznam uzivatelskych linek pro generovani
513
     *
514
     * @return seznam uzivatelskych linek pro generovani
515
     */
516
    public List<String> getLineList() {
517
        return lineList;
518
    }
519

    
520
    /**
521
     * Nastavi seznam uzivatelskych linek na hodnotu {@code lineList}
522
     *
523
     * @param lineList seznam uzivatelskych linek
524
     */
525
    public void setLineList(List<String> lineList) {
526
        this.lineList = lineList;
527
    }
528

    
529
    /**
530
     * Vrati cestu k vystupnimu souboru
531
     *
532
     * @return cesta k vystupnimu souboru
533
     */
534
    public Path getOutputFile() {
535
        return outputFile;
536
    }
537

    
538
    /**
539
     * Nastavi cestu vystupniho souboru na hodnut {@code outputFile}
540
     *
541
     * @param outputFile cesta vystupniho souboru
542
     */
543
    public void setOutputFile(Path outputFile) {
544
        this.outputFile = outputFile;
545
    }
546
}
(2-2/7)