Projekt

Obecné

Profil

Stáhnout (19.6 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
            //Naparsuj pouze pokud datum do existuje
177
            if (!dateToHardCode.equals("")) {
178
                hardCodeDateFrom = LocalDate.parse(dateFromHardCode, formatter);
179
                hardCodeDateTo = LocalDate.parse(dateToHardCode, formatter);
180

    
181
                if (hardCodeDateFrom.isBefore(dateFrom) && hardCodeDateTo.isAfter(dateTo)) {
182
                    return true;
183
                }
184

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

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

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

    
197
            }
198

    
199
            //Pokud se jedná pouze o jeden den
200
            else {
201
                hardCodeDateFrom = LocalDate.parse(dateFromHardCode, formatter);
202

    
203
                if (!hardCodeDateFrom.isBefore(dateFrom) && !hardCodeDateFrom.isAfter(dateTo)) {
204
                    return true;
205
                }
206

    
207
            }
208

    
209
        return false;
210

    
211
    }
212

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

    
226
        LocalDate[] hardCodeRange = new LocalDate[2];
227
        LocalDate hardCodeDateFrom;
228
        LocalDate hardCodeDateTo;
229

    
230
            //Naparsuj pouze pokud datum existuje
231
            if (!dateToHardCode.equals("")) {
232
                hardCodeDateFrom = LocalDate.parse(dateFromHardCode, formatter);
233
                hardCodeDateTo = LocalDate.parse(dateToHardCode, formatter);
234

    
235

    
236
                if (!hardCodeDateFrom.isBefore(dateFrom) && !hardCodeDateFrom.isAfter(dateTo)) {
237
                    hardCodeRange[0] = hardCodeDateFrom;
238
                }
239
                else hardCodeRange[0] = dateFrom;
240

    
241
                if (!hardCodeDateTo.isAfter(dateTo) && !hardCodeDateTo.isBefore(dateFrom)) {
242
                    hardCodeRange[1] = hardCodeDateTo;
243
                }
244
                else hardCodeRange[1] = dateTo;
245

    
246
            }
247

    
248
            //Existuje vždy
249
            else {
250
                hardCodeDateFrom = LocalDate.parse(dateFromHardCode, formatter);
251
                hardCodeRange[0] = hardCodeDateFrom;
252
                hardCodeRange[1] = null;
253
            }
254

    
255
            return hardCodeRange;
256

    
257
        }
258

    
259
    /**
260
     * Metoda overi zda-li zadany retezec odpovida cislene hodnote
261
     *
262
     * @param inputData retezec pro overeni
263
     * @return Vrati {@code true} pokud je retezec cislem, v opacnem pripade vrati {@code false}
264
     */
265
    private static boolean isNumeric(String inputData) {
266
        return inputData.matches("[-+]?\\d+(\\.\\d+)?");
267
    }
268

    
269

    
270
    /**
271
     * Zavola prislusne metody bitmapy pro naplneni podle casoveho kodu
272
     *
273
     * @param bitmap bitmapa pro naplneni
274
     * @param dateFrom pocatek obdobi pro naplneni
275
     * @param dateTo konec obdobi pro naplneni
276
     * @param TimeCodeType cislo casoveho kodu
277
     */
278
    private void fillBitmap (Bitmap bitmap, LocalDate dateFrom, LocalDate dateTo, int TimeCodeType) {
279

    
280
        switch (TimeCodeType) {
281
            case 1: {
282
                if (dateTo!=null) bitmap.setHardCodeDays(dateFrom, dateTo, 1);
283
                else bitmap.setDay(dateFrom, 1);
284
                break;
285
            }
286
            case 2: {
287
                bitmap.setHardCodeDays(bitmap.getDateFrom(), bitmap.getDateTo(), 1);
288
                if (dateTo!=null) bitmap.setDaysInRange(dateFrom, dateTo, 1);
289
                else bitmap.setDay(dateFrom, 1);
290
                break;
291
            }
292
            case 3: {
293
                bitmap.setDay(dateFrom, 1);
294
                break;
295
            }
296
            case 4: {
297
                bitmap.setHardCodeDays(bitmap.getDateFrom(), bitmap.getDateTo(), 1);
298
                if (dateTo!=null) bitmap.unsetDaysInRange(dateFrom, dateTo);
299
                else bitmap.setDay(dateFrom, 0);
300
                break;
301
            }
302
            case 5: {
303
                bitmap.setHardCodeWeeks(1, 1);
304
                break;
305
            }
306
            case 6: {
307
                bitmap.setHardCodeWeeks(1, 0);
308
                break;
309
            }
310
            case 7: {
311
                bitmap.setHardCodeWeeksInRange(dateFrom, dateTo, 1, 1);
312
                break;
313
            }
314
            case 8: {
315
                bitmap.setHardCodeWeeksInRange(dateFrom, dateTo, 1, 0);
316
                break;
317
            }
318
            default: break;
319
        }
320

    
321
    }
322

    
323
    /**
324
     * Vygeneruje, naplni a prida do vysledneho seznamu vsechny pseudo bitmapy
325
     *
326
     * @param dateFrom pocatek obdobi pro bitmapu
327
     * @param dateTo konec obdobi pro bitmapu
328
     */
329
    public void generatePseudoBitmaps(LocalDate dateFrom, LocalDate dateTo) {
330

    
331
        for (String psLine : pseudoLines) {
332

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

    
335
            LocalDate[] hardCodeRange;
336
            String[] plRecord = psLine.split("-");
337
            Bitmap generatedBitmap = new Bitmap(dateFrom, dateTo, "000000", "0", plRecord[0], plRecord[1], "0");
338

    
339
            //Pokud nemá žádné časové omezení a žádný pevnýkód -> naplň jedničkami
340
            if (plRecord[0].equals("00") && plRecord[1].length() == 0) {
341
                generatedBitmap.fillWithOnes();
342
                bitmaps.add(generatedBitmap);
343
                continue;
344
            }
345

    
346
            //Pokud nemá spoj žádná omezení -> napln bitmapu podle pevnych kodu a přidej
347
            else if (plRecord[0].equals("00") && plRecord[1].length() > 0) {
348
                generatedBitmap.setHardCodeDays(dateFrom, dateTo, 1);
349
                bitmaps.add(generatedBitmap);
350
                continue;
351
            }
352

    
353
            else {
354
                for (JDFCaskodyRecord caskod : caskody) {
355
                    if (caskod.getTimeCode().equals(plRecord[0])) {
356
                        if (isInRange(dateFrom, dateTo, caskod.getStartDate(), caskod.getEndDate())) {
357
                            hardCodeRange = setHardCodeRange(dateFrom, dateTo, caskod.getStartDate(), caskod.getEndDate());
358
                            fillBitmap(generatedBitmap, hardCodeRange[0], hardCodeRange[1], Integer.parseInt(caskod.getTypeTimeCode()));
359
                        }
360
                    }
361
                }
362
            }
363

    
364

    
365
            //Jinak bitmapa byla již naplněna -> přidej
366
                bitmaps.add(generatedBitmap);
367

    
368

    
369
        }
370
    }
371

    
372
    /**
373
     * Metoda projde seznamy spoju, caskodu, pevnychkodu a linek na jejichz zaklade vygeneruje a naplni bitmapy v zadanem obdobi
374
     * vysledne bitmapy vypise v pozadovanem formatu do vystupniho souboru
375
     *
376
     * @param dateFrom pocatek obdobi pro bitmapu
377
     * @param dateTo konec obdobi pro bitmapu
378
     */
379
    public void writeBitmaps(LocalDate dateFrom, LocalDate dateTo) {
380
        
381
        try(BufferedWriter writer = Files.newBufferedWriter(outputFile, Charset.defaultCharset(), StandardOpenOption.APPEND)) {
382
            DateTimeFormatter format = DateTimeFormatter.ofPattern("d.M.yyyy");
383
            String currentLine =  spoje.get(0).getNumberLine();
384
            String currentTimeCode;
385
            String previousTimeCode;
386
            LocalDate[] hardCodeRange;
387

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

    
391
            window.printMessage("Zpracovávám bitmapy...");
392
            window.printMessage("Zpracovávám linku: "+currentLine);
393

    
394

    
395
            //Pro každý spoj
396
            for (JDFSpojeRecord spoj : spoje) {
397
                currentTimeCode = "00";
398

    
399
                //Pokud se jedná o novou linku - Vypiš _______ ??? (Je potřeba) ???
400
                if (!currentLine.equals(spoj.getNumberLine())) {
401
                    currentLine = spoj.getNumberLine();
402
                    window.printMessage("Zpracovávám linku: "+currentLine);
403
                }
404

    
405
                //Výpis právě prozkoumávaného spoje
406
                String currentJoin = spoj.getNumberJoin();
407
                window.printMessage("- spoj: "+currentJoin);
408

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

    
413
                previousTimeCode = "";
414

    
415
                for (JDFCaskodyRecord caskod : caskody) {
416

    
417

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

    
421
                        currentTimeCode =  caskod.getTimeCode();
422
                        generatedBitmap.setTimeCode(currentTimeCode);
423

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

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

    
432

    
433
                         //Pokud je zkoumaný časový kód v rozsahu bitmapy
434
                        if (isInRange(dateFrom, dateTo, caskod.getStartDate(), caskod.getEndDate())) {
435
                            timeCodesInRange++;
436
                            hardCodeRange = setHardCodeRange(dateFrom, dateTo, caskod.getStartDate(), caskod.getEndDate());
437
                            fillBitmap(generatedBitmap, hardCodeRange[0], hardCodeRange[1], Integer.parseInt(caskod.getTypeTimeCode()));
438
                        }
439

    
440
                        previousTimeCode = currentTimeCode;
441
                    }
442
                }
443

    
444

    
445

    
446
                //Pokud nemá žádné časové omezení a žádný pevnýkód -> naplň jedničkami
447
                if (timeCodesInRange == 0 && spoj.getHardCodes().size() == 0 && viableTimeCodes == 0) {
448
                    generatedBitmap.fillWithOnes();
449
                    bitmaps.add(generatedBitmap);
450
                }
451

    
452
                //Pokud nemá spoj žádná omezení -> napln bitmapu podle pevnych kodu a přidej
453
                else if (timeCodesInRange == 0 && spoj.getHardCodes().size() > 0 && viableTimeCodes == 0) {
454
                    generatedBitmap.setHardCodeDays(dateFrom, dateTo, 1);
455
                    bitmaps.add(generatedBitmap);
456
                }
457

    
458
                //Jinak bitmapa byla již naplněna -> přidej
459
                else {
460
                    bitmaps.add(generatedBitmap);
461
                }
462
            }
463

    
464
                //Pokud existují nějaké pseudolinky -> naplň a přidej do seznamu generovaných bitmap
465
                if(pseudoLines.size() > 0) {
466
                    generatePseudoBitmaps(dateFrom, dateTo);
467
                }
468

    
469
                //Odstraň duplikátní bitmapy
470
                removeDuplicates();
471

    
472
                //Seřaď seznam bitmap
473
                Collections.sort(bitmaps);
474

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

    
478
                //Vypiš bitmapy do souboru
479
            for (Bitmap bitmap : bitmaps) {
480
                writer.write(bitmap.toString()+"\r\n");
481
            }
482

    
483

    
484
        } catch (IOException e) {
485
            e.printStackTrace();
486
            window.printMessage("Neočekávaná chyba při zapisování bitmapy");
487
        }
488
        window.printMessage("Bitmapy úspěšně zapsány");
489
    }
490

    
491
    /**
492
     * Odstraní duplikatni bitmapy
493
     */
494
    public void removeDuplicates() {
495
        Set<Bitmap> bitmapsWODuplicates = new TreeSet<>();
496
        bitmapsWODuplicates.addAll(this.bitmaps);
497
        this.bitmaps = new ArrayList<>(bitmapsWODuplicates);
498

    
499
    }
500

    
501
    /**
502
     * Vrati seznam uzivatelskych linek pro generovani
503
     *
504
     * @return seznam uzivatelskych linek pro generovani
505
     */
506
    public List<String> getLineList() {
507
        return lineList;
508
    }
509

    
510
    /**
511
     * Nastavi seznam uzivatelskych linek na hodnotu {@code lineList}
512
     *
513
     * @param lineList seznam uzivatelskych linek
514
     */
515
    public void setLineList(List<String> lineList) {
516
        this.lineList = lineList;
517
    }
518

    
519
    /**
520
     * Vrati cestu k vystupnimu souboru
521
     *
522
     * @return cesta k vystupnimu souboru
523
     */
524
    public Path getOutputFile() {
525
        return outputFile;
526
    }
527

    
528
    /**
529
     * Nastavi cestu vystupniho souboru na hodnut {@code outputFile}
530
     *
531
     * @param outputFile cesta vystupniho souboru
532
     */
533
    public void setOutputFile(Path outputFile) {
534
        this.outputFile = outputFile;
535
    }
536
}
(2-2/7)