package de.duehl.basics.start;

/*
 * Copyright 2019 Christian Dühl. All rights reserved.
 *
 * This program is free software. You can redistribute it and/or
 * modify it under the same terms as perl:
 *
 * general:  http://dev.perl.org/licenses/
 * GPL:      http://dev.perl.org/licenses/gpl1.html
 * artistic: http://dev.perl.org/licenses/artistic.html
 */

import java.util.ArrayList;
import java.util.List;

import de.duehl.basics.io.Charset;
import de.duehl.basics.io.FileHelper;
import de.duehl.basics.io.FineFileWriter;
import de.duehl.basics.io.Writer;
import de.duehl.basics.io.textfile.split.SplittedTextFileJoiner;
import de.duehl.basics.io.textfile.split.TextFileSplitter;
import de.duehl.basics.test.TestHelper;

/**
 * Diese Klasse testet das Aufteilen und wieder zusammensetzen einer Textdatei.
 *
 * @version 1.01     2019-12-01
 * @author Christian Dühl
 */

public class TextFileSplitterAndJoinerTest {

    private static final int NUMBER_OF_LINES_IN_BIG_FILE = 12_345;

    private static final int NUMBER_OF_LINES_PER_SPLITTED_FILE = 500;

    private static final Charset CHARSET = Charset.UTF_8;
    private static final boolean HAS_TITLES = true;

    /** Name der aufzuteilenden Ausgangsdatei. */
    private final String bigFilename;

    /** Name der wieder zusammengesetzten Datei. */
    private final String bigJoinedFilename;

    /** Namen der erzeugten aufgeteilten Dateien. */
    private List<String> filenamesOfCreatedSplitFiles;

    /** Konstruktor. */
    public TextFileSplitterAndJoinerTest() {
        TestHelper testHelper = TestHelper.createForBasics(getClass(), 6);
        String dir =  testHelper.getTestDir("split_and_join");

        FileHelper.deleteTreeIgnoreErrors(dir);
        FileHelper.createDirectoryIfNotExists(dir);

        bigFilename = FileHelper.concatPathes(dir, "big_file_to_split.txt");
        bigJoinedFilename = FileHelper.concatPathes(dir, "big_joined_file.txt");
    }

    /** Führt den Test durch. */
    public void run() {
        createRandomBigFile();
        splitFile();
        checkEveryLineIsFoundViceVersa();
        joinSplittedFiles();
        checkjoinedSpliitedFileIsEqualToOriginalBigFile();
    }

    private void createRandomBigFile() {
        Writer writer = new FineFileWriter(bigFilename, CHARSET);
        writer.writeFieldsLine("ID", "Name", "Kommentar");

        for (int i = 0; i < NUMBER_OF_LINES_IN_BIG_FILE; ++i) {
            writer.writeFieldsLine(Integer.toString(i + 1), "Name " + (i + 1), "äöüÄÖÜß");
        }

        writer.close();

        System.out.println("Erzeugt: " + bigFilename);
    }

    private void splitFile() {
        TextFileSplitter splitter = new TextFileSplitter(bigFilename, CHARSET,
                NUMBER_OF_LINES_PER_SPLITTED_FILE, HAS_TITLES);
        splitter.beQuiet();
        splitter.work();

        filenamesOfCreatedSplitFiles = splitter.getFilenamesOfCreatedSplitFiles();
        System.out.println("Aufgeteilt in " + splitter.getNumberOfCreatedSplitFiles() + " Dateien.");
    }

    private void checkEveryLineIsFoundViceVersa() {
        List<String> linesFromBigFile = FileHelper.readFileToList(bigFilename);

        List<List<String>> listOfLinesFromSplittedFiles = new ArrayList<>();
        for (String spliitedFilename : filenamesOfCreatedSplitFiles) {
            listOfLinesFromSplittedFiles.add(FileHelper.readFileToList(spliitedFilename));
        }

        for (String lineFromBigFile : linesFromBigFile) {
            boolean found = false;
            for (List<String> linesFromSplittedFile : listOfLinesFromSplittedFiles) {
                if (linesFromSplittedFile.contains(lineFromBigFile)) {
                    found = true;
                    break;
                }
            }
            if (!found) {
                throw new RuntimeException("Die Zeile\n\t" + lineFromBigFile
                        + "\naus der großen Datei wurde in keiner der aufgeteilten Dateien "
                        + "gefunden!");
            }
        }
        System.out.println(
                "Jede Zeile der großen Datei wurde in den aufgetelten Dateien gefunden.");

        for (List<String> linesFromSplittedFile : listOfLinesFromSplittedFiles) {
            for (String lineFromSplittedFile : linesFromSplittedFile) {
                if (!linesFromBigFile.contains(lineFromSplittedFile)) {
                    throw new RuntimeException("Die Zeile\n\t" + lineFromSplittedFile
                            + "\naus einer der aufgeteilten Dateien wurde nicht in der großen "
                            + "Datei gefunden!");
                }
            }
        }
        System.out.println(
                "Jede Zeile aus den aufgetelten Dateien wurde in der großen Datei gefunden.");
    }

    private void joinSplittedFiles() {
        SplittedTextFileJoiner joiner = new SplittedTextFileJoiner(filenamesOfCreatedSplitFiles,
                bigJoinedFilename, CHARSET, HAS_TITLES);
        joiner.beQuiet();
        joiner.work();

        System.out.println(
                "Zusammengefügt aus " + filenamesOfCreatedSplitFiles.size() + " Dateien.");
        System.out.println("Geschrieben nach " + bigJoinedFilename + ".");
    }

    private void checkjoinedSpliitedFileIsEqualToOriginalBigFile() {
        List<String> linesFromBigFile = FileHelper.readFileToList(bigFilename);
        List<String> linesFromJoinedBigFile = FileHelper.readFileToList(bigJoinedFilename);

        if (linesFromBigFile.size() != linesFromJoinedBigFile.size()) {
            throw new RuntimeException("Dateien enthalten unterschiedlich viele Zeilen!");
        }

        for (int index = 0; index < linesFromBigFile.size(); ++index) {
            String lineIn = linesFromBigFile.get(index);
            String lineOut = linesFromJoinedBigFile.get(index);

            if (!lineIn.equals(lineOut)) {
                throw new RuntimeException("Die Zeile mit der Nummer " + (index + 1)
                        + " sind unterschiedlich!");
            }
        }

        System.out.println("Vergleich der zusammengesetzten mit der originalen Datei ist ok.");
    }

    public static void main(String[] args) {
        TextFileSplitterAndJoinerTest test = new TextFileSplitterAndJoinerTest();
        test.run();
    }

}
