package de.duehl.basics.java;

import static org.junit.Assert.*;

import java.util.List;

import org.junit.Test;

import de.duehl.basics.io.Charset;
import de.duehl.basics.io.FileHelper;
import de.duehl.basics.java.data.EnumDefinition;
import de.duehl.basics.text.Text;

public class JavaEnumAnalyserTest {

    @Test
    public void definitonsWithoutBraceSemikolonOnSameLine() {
        String text = """
                public enum EnumAnalyseState {

                    FIRST_NOT_FOUND,
                    DEFINITION_STARTED_BUT_NOT_CLOSED,
                    DEFINITION_CLOSED,
                    ALL_DEFINITIONS_CLOSED;

                }
                """;
        List<String> lines = Text.splitByLineBreaks(text );
        JavaEnumAnalyser analyser = new JavaEnumAnalyser(lines);
        analyser.analyse();

        List<EnumDefinition> enumDefinitons = analyser.getEnumDefinitons();
        assertEquals(4, enumDefinitons.size());

        EnumDefinition enumDefinitons01 = enumDefinitons.get(0);
        EnumDefinition enumDefinitons02 = enumDefinitons.get(1);
        EnumDefinition enumDefinitons03 = enumDefinitons.get(2);
        EnumDefinition enumDefinitons04 = enumDefinitons.get(3);

        assertEquals("FIRST_NOT_FOUND", enumDefinitons01.getDefinition());
        assertEquals("", enumDefinitons01.getBraceContent());

        assertEquals("DEFINITION_STARTED_BUT_NOT_CLOSED", enumDefinitons02.getDefinition());
        assertEquals("", enumDefinitons02.getBraceContent());

        assertEquals("DEFINITION_CLOSED", enumDefinitons03.getDefinition());
        assertEquals("", enumDefinitons03.getBraceContent());

        assertEquals("ALL_DEFINITIONS_CLOSED", enumDefinitons04.getDefinition());
        assertEquals("", enumDefinitons04.getBraceContent());
    }

    @Test
    public void definitonsWithoutBraceSemikolonWothoutCommaOnNextLine() {
        String text = """
                public enum EnumAnalyseState {

                    FIRST_NOT_FOUND,
                    DEFINITION_STARTED_BUT_NOT_CLOSED,
                    DEFINITION_CLOSED,
                    ALL_DEFINITIONS_CLOSED
                    ;

                }
                """;
        List<String> lines = Text.splitByLineBreaks(text );
        JavaEnumAnalyser analyser = new JavaEnumAnalyser(lines);
        analyser.analyse();

        List<EnumDefinition> enumDefinitons = analyser.getEnumDefinitons();
        assertEquals(4, enumDefinitons.size());

        EnumDefinition enumDefinitons01 = enumDefinitons.get(0);
        EnumDefinition enumDefinitons02 = enumDefinitons.get(1);
        EnumDefinition enumDefinitons03 = enumDefinitons.get(2);
        EnumDefinition enumDefinitons04 = enumDefinitons.get(3);

        assertEquals("FIRST_NOT_FOUND", enumDefinitons01.getDefinition());
        assertEquals("", enumDefinitons01.getBraceContent());

        assertEquals("DEFINITION_STARTED_BUT_NOT_CLOSED", enumDefinitons02.getDefinition());
        assertEquals("", enumDefinitons02.getBraceContent());

        assertEquals("DEFINITION_CLOSED", enumDefinitons03.getDefinition());
        assertEquals("", enumDefinitons03.getBraceContent());

        assertEquals("ALL_DEFINITIONS_CLOSED", enumDefinitons04.getDefinition());
        assertEquals("", enumDefinitons04.getBraceContent());
    }

    @Test
    public void definitonsWithoutBraceExtraSemikolon() {
        String text = """
                public enum EnumAnalyseState {

                    FIRST_NOT_FOUND,
                    DEFINITION_STARTED_BUT_NOT_CLOSED,
                    DEFINITION_CLOSED,
                    ALL_DEFINITIONS_CLOSED,
                    ;

                }
                """;
        List<String> lines = Text.splitByLineBreaks(text );
        JavaEnumAnalyser analyser = new JavaEnumAnalyser(lines);
        analyser.analyse();

        List<EnumDefinition> enumDefinitons = analyser.getEnumDefinitons();
        assertEquals(4, enumDefinitons.size());

        EnumDefinition enumDefinitons01 = enumDefinitons.get(0);
        EnumDefinition enumDefinitons02 = enumDefinitons.get(1);
        EnumDefinition enumDefinitons03 = enumDefinitons.get(2);
        EnumDefinition enumDefinitons04 = enumDefinitons.get(3);

        assertEquals("FIRST_NOT_FOUND", enumDefinitons01.getDefinition());
        assertEquals("", enumDefinitons01.getBraceContent());

        assertEquals("DEFINITION_STARTED_BUT_NOT_CLOSED", enumDefinitons02.getDefinition());
        assertEquals("", enumDefinitons02.getBraceContent());

        assertEquals("DEFINITION_CLOSED", enumDefinitons03.getDefinition());
        assertEquals("", enumDefinitons03.getBraceContent());

        assertEquals("ALL_DEFINITIONS_CLOSED", enumDefinitons04.getDefinition());
        assertEquals("", enumDefinitons04.getBraceContent());
    }

    @Test
    public void definitonsOnSingleLinesTestWithBraces() {
        String text = """
                public enum Hiragana {

                    A("あ", "a", KanaSubType.STANDARD),
                    I("い", "i", KanaSubType.STANDARD),
                    U("う", "u", KanaSubType.STANDARD),
                    E("え", "e", KanaSubType.STANDARD),
                    O("お", "o", KanaSubType.STANDARD),

                    KA("か", "ka", KanaSubType.STANDARD),
                    KI("き", "ki", KanaSubType.STANDARD),
                    KU("く", "ku", KanaSubType.STANDARD),
                    KE("け", "ke", KanaSubType.STANDARD),
                    KO("こ", "ko", KanaSubType.STANDARD),
                    ;

                    // und so weiter ...
                }
                """;
        List<String> lines = Text.splitByLineBreaks(text );
        JavaEnumAnalyser analyser = new JavaEnumAnalyser(lines);
        analyser.analyse();
        assertEquals(10, analyser.getNumberOfDefinitions());

        List<EnumDefinition> enumDefinitons = analyser.getEnumDefinitons();
        assertEquals(10, enumDefinitons.size());

        EnumDefinition enumDefinitons01 = enumDefinitons.get(0);
        EnumDefinition enumDefinitons02 = enumDefinitons.get(1);
        EnumDefinition enumDefinitons03 = enumDefinitons.get(2);
        EnumDefinition enumDefinitons04 = enumDefinitons.get(3);
        EnumDefinition enumDefinitons05 = enumDefinitons.get(4);

        EnumDefinition enumDefinitons06 = enumDefinitons.get(5);
        EnumDefinition enumDefinitons07 = enumDefinitons.get(6);
        EnumDefinition enumDefinitons08 = enumDefinitons.get(7);
        EnumDefinition enumDefinitons09 = enumDefinitons.get(8);
        EnumDefinition enumDefinitons10 = enumDefinitons.get(9);

        assertEquals("A", enumDefinitons01.getDefinition());
        assertEquals("\"あ\", \"a\", KanaSubType.STANDARD", enumDefinitons01.getBraceContent());

        assertEquals("I", enumDefinitons02.getDefinition());
        assertEquals("\"い\", \"i\", KanaSubType.STANDARD", enumDefinitons02.getBraceContent());

        assertEquals("U", enumDefinitons03.getDefinition());
        assertEquals("\"う\", \"u\", KanaSubType.STANDARD", enumDefinitons03.getBraceContent());

        assertEquals("E", enumDefinitons04.getDefinition());
        assertEquals("\"え\", \"e\", KanaSubType.STANDARD", enumDefinitons04.getBraceContent());

        assertEquals("O", enumDefinitons05.getDefinition());
        assertEquals("\"お\", \"o\", KanaSubType.STANDARD", enumDefinitons05.getBraceContent());


        assertEquals("KA", enumDefinitons06.getDefinition());
        assertEquals("\"か\", \"ka\", KanaSubType.STANDARD", enumDefinitons06.getBraceContent());

        assertEquals("KI", enumDefinitons07.getDefinition());
        assertEquals("\"き\", \"ki\", KanaSubType.STANDARD", enumDefinitons07.getBraceContent());

        assertEquals("KU", enumDefinitons08.getDefinition());
        assertEquals("\"く\", \"ku\", KanaSubType.STANDARD", enumDefinitons08.getBraceContent());

        assertEquals("KE", enumDefinitons09.getDefinition());
        assertEquals("\"け\", \"ke\", KanaSubType.STANDARD", enumDefinitons09.getBraceContent());

        assertEquals("KO", enumDefinitons10.getDefinition());
        assertEquals("\"こ\", \"ko\", KanaSubType.STANDARD", enumDefinitons10.getBraceContent());
    }

    @Test
    public void definitonsOnSingleLinesTestWithSpecialTextInBrace() {
        String text = """
                public enum Hiragana {

                    A("あ", "a", KanaSubType.STANDARD),
                    I("い", "i", KanaSubType.STANDARD),
                    U("う", "u", KanaSubType.STANDARD),
                    E("え", "e", KanaSubType.STANDARD),
                    O("お", "o", KanaSubType.STANDARD),

                    KA("か", "ka", KanaSubType.FOO_BAR_BAZ),
                    KI("き", "ki", KanaSubType.FOO_BAR_BAZ),
                    KU("く", "ku", KanaSubType.FOO_BAR_BAZ),
                    KE("け", "ke", KanaSubType.FOO_BAR_BAZ),
                    KO("こ", "ko", KanaSubType.FOO_BAR_BAZ),
                    ;

                    // und so weiter ...
                }
                """;
        List<String> lines = Text.splitByLineBreaks(text );
        JavaEnumAnalyser analyser = new JavaEnumAnalyser(lines);
        analyser.analyse();

        int actual = analyser.countDefinitionsWithPartInBrace("KanaSubType.STANDARD");
        int expected = 5;
        assertEquals(expected, actual);

        List<EnumDefinition> enumDefinitons = analyser.getEnumDefinitons();
        assertEquals(10, enumDefinitons.size());

        EnumDefinition enumDefinitons01 = enumDefinitons.get(0);
        EnumDefinition enumDefinitons02 = enumDefinitons.get(1);
        EnumDefinition enumDefinitons03 = enumDefinitons.get(2);
        EnumDefinition enumDefinitons04 = enumDefinitons.get(3);
        EnumDefinition enumDefinitons05 = enumDefinitons.get(4);

        EnumDefinition enumDefinitons06 = enumDefinitons.get(5);
        EnumDefinition enumDefinitons07 = enumDefinitons.get(6);
        EnumDefinition enumDefinitons08 = enumDefinitons.get(7);
        EnumDefinition enumDefinitons09 = enumDefinitons.get(8);
        EnumDefinition enumDefinitons10 = enumDefinitons.get(9);

        assertEquals("A", enumDefinitons01.getDefinition());
        assertEquals("\"あ\", \"a\", KanaSubType.STANDARD", enumDefinitons01.getBraceContent());

        assertEquals("I", enumDefinitons02.getDefinition());
        assertEquals("\"い\", \"i\", KanaSubType.STANDARD", enumDefinitons02.getBraceContent());

        assertEquals("U", enumDefinitons03.getDefinition());
        assertEquals("\"う\", \"u\", KanaSubType.STANDARD", enumDefinitons03.getBraceContent());

        assertEquals("E", enumDefinitons04.getDefinition());
        assertEquals("\"え\", \"e\", KanaSubType.STANDARD", enumDefinitons04.getBraceContent());

        assertEquals("O", enumDefinitons05.getDefinition());
        assertEquals("\"お\", \"o\", KanaSubType.STANDARD", enumDefinitons05.getBraceContent());


        assertEquals("KA", enumDefinitons06.getDefinition());
        assertEquals("\"か\", \"ka\", KanaSubType.FOO_BAR_BAZ", enumDefinitons06.getBraceContent());

        assertEquals("KI", enumDefinitons07.getDefinition());
        assertEquals("\"き\", \"ki\", KanaSubType.FOO_BAR_BAZ", enumDefinitons07.getBraceContent());

        assertEquals("KU", enumDefinitons08.getDefinition());
        assertEquals("\"く\", \"ku\", KanaSubType.FOO_BAR_BAZ", enumDefinitons08.getBraceContent());

        assertEquals("KE", enumDefinitons09.getDefinition());
        assertEquals("\"け\", \"ke\", KanaSubType.FOO_BAR_BAZ", enumDefinitons09.getBraceContent());

        assertEquals("KO", enumDefinitons10.getDefinition());
        assertEquals("\"こ\", \"ko\", KanaSubType.FOO_BAR_BAZ", enumDefinitons10.getBraceContent());
    }

    @Test
    public void definitonsOnMultipleLinesTest() {
        String text = """
                public enum Kanji {

                    FISCH("魚", "Fisch", "魚", "さかな", 290, 112,
                            CollectionsHelper.buildListFrom("GYO"),
                            CollectionsHelper.buildListFrom("sakana", "uo")
                            ),
                    FLEISCH("肉", "Fleisch", "肉", "にく", 223, 102,
                            CollectionsHelper.buildListFrom("NIKU"),
                            CollectionsHelper.buildListFrom()
                            ),
                    EI("卵", "Ei", "卵", "たまご", 1103, 228,
                            CollectionsHelper.buildListFrom("RAN"),
                            CollectionsHelper.buildListFrom("tamago")
                            ),
                    WASSER("水", "Wasser", "水", "みず", 21, 73,
                            CollectionsHelper.buildListFrom("SUI"),
                            CollectionsHelper.buildListFrom("mizu")
                            ),
                    ;

                    // und so weiter ...
                }
                """;
        List<String> lines = Text.splitByLineBreaks(text );
        JavaEnumAnalyser analyser = new JavaEnumAnalyser(lines);
        analyser.analyse();
        assertEquals(4, analyser.getNumberOfDefinitions());

        List<EnumDefinition> enumDefinitons = analyser.getEnumDefinitons();
        assertEquals(4, enumDefinitons.size());

        EnumDefinition enumDefinitons01 = enumDefinitons.get(0);
        EnumDefinition enumDefinitons02 = enumDefinitons.get(1);
        EnumDefinition enumDefinitons03 = enumDefinitons.get(2);
        EnumDefinition enumDefinitons04 = enumDefinitons.get(3);

        assertEquals("FISCH", enumDefinitons01.getDefinition());
        assertEquals("\"魚\", \"Fisch\", \"魚\", \"さかな\", 290, 112, "
                + "CollectionsHelper.buildListFrom(\"GYO\"), "
                + "CollectionsHelper.buildListFrom(\"sakana\", \"uo\")",
                enumDefinitons01.getBraceContent());

        assertEquals("FLEISCH", enumDefinitons02.getDefinition());
        assertEquals("\"肉\", \"Fleisch\", \"肉\", \"にく\", 223, 102, "
                + "CollectionsHelper.buildListFrom(\"NIKU\"), "
                + "CollectionsHelper.buildListFrom()",
                enumDefinitons02.getBraceContent());

        assertEquals("EI", enumDefinitons03.getDefinition());
        assertEquals("\"卵\", \"Ei\", \"卵\", \"たまご\", 1103, 228, "
                + "CollectionsHelper.buildListFrom(\"RAN\"), "
                + "CollectionsHelper.buildListFrom(\"tamago\")",
                enumDefinitons03.getBraceContent());

        assertEquals("WASSER", enumDefinitons04.getDefinition());
        assertEquals("\"水\", \"Wasser\", \"水\", \"みず\", 21, 73, "
                + "CollectionsHelper.buildListFrom(\"SUI\"), "
                + "CollectionsHelper.buildListFrom(\"mizu\")",
                enumDefinitons04.getBraceContent());
    }

    @Test
    public void mixedDefinitons() {
        String text = """
                public enum MixedType {

                    FIRST_NOT_FOUND,
                    I("い", "i", KanaSubType.STANDARD),
                    EI("卵", "Ei", "卵", "たまご", 1103, 228,
                            CollectionsHelper.buildListFrom("RAN"),
                            CollectionsHelper.buildListFrom("tamago")
                            ),
                    ALL_DEFINITIONS_CLOSED;

                }
                """;
        List<String> lines = Text.splitByLineBreaks(text );
        JavaEnumAnalyser analyser = new JavaEnumAnalyser(lines);
        analyser.analyse();

        List<EnumDefinition> enumDefinitons = analyser.getEnumDefinitons();
        assertEquals(4, enumDefinitons.size());

        EnumDefinition enumDefinitons01 = enumDefinitons.get(0);
        EnumDefinition enumDefinitons02 = enumDefinitons.get(1);
        EnumDefinition enumDefinitons03 = enumDefinitons.get(2);
        EnumDefinition enumDefinitons04 = enumDefinitons.get(3);

        assertEquals("FIRST_NOT_FOUND", enumDefinitons01.getDefinition());
        assertEquals("", enumDefinitons01.getBraceContent());

        assertEquals("I", enumDefinitons02.getDefinition());
        assertEquals("\"い\", \"i\", KanaSubType.STANDARD", enumDefinitons02.getBraceContent());

        assertEquals("EI", enumDefinitons03.getDefinition());
        assertEquals("\"卵\", \"Ei\", \"卵\", \"たまご\", 1103, 228, "
                + "CollectionsHelper.buildListFrom(\"RAN\"), "
                + "CollectionsHelper.buildListFrom(\"tamago\")",
                enumDefinitons03.getBraceContent());

        assertEquals("ALL_DEFINITIONS_CLOSED", enumDefinitons04.getDefinition());
        assertEquals("", enumDefinitons04.getBraceContent());
    }

    @Test
    public void definitonsOnMultipleLinesTestWithBreakInBraceInBrace() {
        String text = """
                public enum Kanji {

                    FISCH("魚", "Fisch", "魚", "さかな", 290, 112,
                            CollectionsHelper.buildListFrom("GYO"),
                            CollectionsHelper.buildListFrom("sakana", "uo")
                            ),
                    FLEISCH("肉", "Fleisch", "肉", "にく", 223, 102,
                            CollectionsHelper.buildListFrom("NIKU"),
                            CollectionsHelper.buildListFrom()
                            ),
                    EI("卵", "Ei", "卵", "たまご", 1103, 228,
                            CollectionsHelper.buildListFrom("RAN"),
                            CollectionsHelper.buildListFrom("tamago")
                            ),
                    LICHT_HELL("明", "Licht, hell, Helligkeit", "明かり", "あかり", 18, 73,
                            CollectionsHelper.buildListFrom("MEI", "MYOU"),
                            CollectionsHelper.buildListFrom("a(kari)", "aka(rui)", "aki(raka)", "a(keru)",
                                    "aka(rumu)", "aka(ramu)", "a(ku)", "a(kasu)", "a(kuru)")
                            ),
                    WASSER("水", "Wasser", "水", "みず", 21, 73,
                            CollectionsHelper.buildListFrom("SUI"),
                            CollectionsHelper.buildListFrom("mizu")
                            ),
                    ;

                    // und so weiter ...
                }
                """;
        List<String> lines = Text.splitByLineBreaks(text );
        JavaEnumAnalyser analyser = new JavaEnumAnalyser(lines);
        analyser.analyse();
        assertEquals(5, analyser.getNumberOfDefinitions());

        List<EnumDefinition> enumDefinitons = analyser.getEnumDefinitons();
        assertEquals(5, enumDefinitons.size());

        EnumDefinition enumDefinitons01 = enumDefinitons.get(0);
        EnumDefinition enumDefinitons02 = enumDefinitons.get(1);
        EnumDefinition enumDefinitons03 = enumDefinitons.get(2);
        EnumDefinition enumDefinitons04 = enumDefinitons.get(3);
        EnumDefinition enumDefinitons05 = enumDefinitons.get(4);

        assertEquals("FISCH", enumDefinitons01.getDefinition());
        assertEquals("\"魚\", \"Fisch\", \"魚\", \"さかな\", 290, 112, "
                + "CollectionsHelper.buildListFrom(\"GYO\"), "
                + "CollectionsHelper.buildListFrom(\"sakana\", \"uo\")",
                enumDefinitons01.getBraceContent());

        assertEquals("FLEISCH", enumDefinitons02.getDefinition());
        assertEquals("\"肉\", \"Fleisch\", \"肉\", \"にく\", 223, 102, "
                + "CollectionsHelper.buildListFrom(\"NIKU\"), "
                + "CollectionsHelper.buildListFrom()",
                enumDefinitons02.getBraceContent());

        assertEquals("EI", enumDefinitons03.getDefinition());
        assertEquals("\"卵\", \"Ei\", \"卵\", \"たまご\", 1103, 228, "
                + "CollectionsHelper.buildListFrom(\"RAN\"), "
                + "CollectionsHelper.buildListFrom(\"tamago\")",
                enumDefinitons03.getBraceContent());

        assertEquals("LICHT_HELL", enumDefinitons04.getDefinition());
        assertEquals("\"明\", \"Licht, hell, Helligkeit\", \"明かり\", \"あかり\", 18, 73, "
                + "CollectionsHelper.buildListFrom(\"MEI\", \"MYOU\"), "
                + "CollectionsHelper.buildListFrom(\"a(kari)\", \"aka(rui)\", \"aki(raka)\", "
                + "\"a(keru)\", \"aka(rumu)\", \"aka(ramu)\", \"a(ku)\", \"a(kasu)\", \"a(kuru)\")",
                enumDefinitons04.getBraceContent());

        assertEquals("WASSER", enumDefinitons05.getDefinition());
        assertEquals("\"水\", \"Wasser\", \"水\", \"みず\", 21, 73, "
                + "CollectionsHelper.buildListFrom(\"SUI\"), "
                + "CollectionsHelper.buildListFrom(\"mizu\")",
                enumDefinitons05.getBraceContent());
    }

    private static final String WORKSPACE_DIR = "c:\\Users\\usr207\\Daten\\java\\workspace\\";
    private static final String SYMBOl_DIR = WORKSPACE_DIR
            + "de.duehl.vocabulary.japanese\\src\\de\\duehl\\vocabulary\\japanese\\data\\symbol\\";

    @Test
    public void kanjiTest() {
        String filename = SYMBOl_DIR + "Kanji.java";
        List<String> lines = FileHelper.readFileToList(filename, Charset.UTF_8);
        JavaEnumAnalyser analyser = new JavaEnumAnalyser(lines);
        analyser.analyse();
        assertTrue(224 <= analyser.getNumberOfDefinitions());
        /*
        System.out.println(analyser.getNumberOfDefinitions());
        CollectionsHelper.printListNice(analyser.getEnumDefinitons());
        */
    }

    @Test
    public void hiraganaTest() {
        String filename = SYMBOl_DIR + "Hiragana.java";
        JavaEnumAnalyser analyser = new JavaEnumAnalyser(filename);
        analyser.analyse();
        assertEquals(118, analyser.getNumberOfDefinitions());

        int actual = analyser.countDefinitionsWithPartInBrace("KanaSubType.STANDARD");
        int expected = 46;
        assertEquals(expected, actual);
        /*
        System.out.println(analyser.getNumberOfDefinitions());
        CollectionsHelper.printListNice(analyser.getEnumDefinitons());
        */
    }

    @Test
    public void katakanaTest() {
        String filename = SYMBOl_DIR + "Katakana.java";
        JavaEnumAnalyser analyser = new JavaEnumAnalyser(filename);
        analyser.analyse();
        assertEquals(128, analyser.getNumberOfDefinitions());

        int actual = analyser.countDefinitionsWithPartInBrace("KanaSubType.STANDARD");
        int expected = 46;
        assertEquals(expected, actual);
        /*
        System.out.println(analyser.getNumberOfDefinitions());
        CollectionsHelper.printListNice(analyser.getEnumDefinitons());
        */
    }

}
