package de.duehl.vocabulary.japanese.logic.symbol.kanji.strokes.extract;

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

import de.duehl.basics.io.Charset;
import de.duehl.basics.io.FileHelper;
import de.duehl.basics.text.Text;
import de.duehl.vocabulary.japanese.logic.symbol.kanji.strokes.extract.data.PathWithStrokeNumber;

/**
 * Diese Klasse extrahiert aus einer SVG-Datei aus dem Kanji-VG Projekt die Pfade.
 *
 * Zu Kanji-VG siehe:
 *
 * https://github.com/KanjiVG/kanjivg
 *
 * KanjiVG is copyright Ulrich Apel and released under the Creative Commons Attribution-Share
 * Alike 3.0 licence: http://creativecommons.org/licenses/by-sa/3.0/
 *
 * The project's documentation is at https://kanjivg.tagaini.net/.
 *
 * @version 1.01     2026-08-18
 * @author Christian Dühl
 */

public class KanjiVgSvgPathesExtractor {

    /** Der Name der SVG-Datei zu einem Kanji, aus welcher hier die Pfade extrahiert werden. */
    private final String filename;

    /** Der Inhalt der SVG-Datei. */
    private String text;

    /**
     * Der Unicode-Codepoint des Kanji als UTF8-Zeichen. Hier ist das der zum Kanji passende Teil
     * der ID im ID-Teil des Pfad-Element, welche z.B. so aussieht: id="kvg:06f22-s1".
     */
    private String codePoint;

    /** Die Liste der extrahierten Pfade mit den Strichnummern. */
    private List<PathWithStrokeNumber> extractedPathes;

    /**
     * Konstruktor.
     *
     * @param filename
     *            Der Name der SVG-Datei zu einem Kanji, aus welcher hier die Pfade extrahiert
     *            werden.
     */
    public KanjiVgSvgPathesExtractor(String filename) {
        this.filename = filename;
    }

    /** Führt die Extraktion durch. */
    public void extract() {
        init();
        readLinesOfFile();
        determinePathIdPart();
        extractWantedPathes();
    }

    private void init() {
        extractedPathes = new ArrayList<>();
    }

    private void readLinesOfFile() {
        text = FileHelper.readFileToString(filename, Charset.UTF_8);
    }

    private void determinePathIdPart() {
        String bareFilename = FileHelper.getBareName(filename);
        codePoint = FileHelper.removeExtension(bareFilename);
    }

    private static final String PATH_ELEMENT_START_PHRASE = "<path id=\"kvg:";
    private static final String PATH_ELEMENT_END_PHRASE = "/>";

    private void extractWantedPathes() {
        for (int startPosition : Text.findAllPositions(PATH_ELEMENT_START_PHRASE, text)) {
            extractAtPosition(startPosition);
        }
    }

    /**
     * Der gesuchte Pfad sieht z.B. so aus:
     *
     *     <path id="kvg:06f22-s1" kvg:type="㇔" d="M20,19.5c3.62,1.47,8.62,5.38,10.25,8.34"/>
     *
     * @param startPosition
     *            Der Index im text, an dem "<path id=" gefunden wurde.
     */
    private void extractAtPosition(int startPosition) {
        String pathWithRest = text.substring(startPosition);
        int endIndex = pathWithRest.indexOf(PATH_ELEMENT_END_PHRASE);
        if (endIndex == -1) {
            throw new RuntimeException("Zu einem öffnenden Pfad-Element wurde das schließende "
                    + "Gegenstück nicht gefunden.\n"
                    + "\t" + "filename      : " + filename + "\n"
                    + "\t" + "startPosition : " + startPosition + "\n"
                    + "\t" + "pathWithRest  : " + pathWithRest + "\n"
                    );
        }
        String pathElement = pathWithRest.substring(0, endIndex + PATH_ELEMENT_END_PHRASE.length());
        String strokeNumber = extractStrokeNumber(pathElement);
        String path = extractPath(pathElement);
        PathWithStrokeNumber pathWithStrokeNumber = new PathWithStrokeNumber(strokeNumber, path);
        extractedPathes.add(pathWithStrokeNumber);
    }

    private static final String STROKE_START_PHRASE = "id=\"kvg:";
    private static final String STROKE_END_PHRASE = "\" ";

    private String extractStrokeNumber(String pathElement) {
        int startIndex = pathElement.indexOf(STROKE_START_PHRASE);
        if (startIndex == -1) {
            throw new RuntimeException("In einem Pfad-Element wurd keine id mit der Stroke-Number "
                    + "gefunden.\n"
                    + "\t" + "filename      : " + filename + "\n"
                    + "\t" + "pathElement   : " + pathElement + "\n"
                    );
        }
        String strokeWithRest = pathElement.substring(startIndex);
        int endIndex = strokeWithRest.indexOf(STROKE_END_PHRASE);
        if (endIndex == -1) {
            throw new RuntimeException("Zu einem öffnenden Stroke in einem Pfad-Element wurde das "
                    + "schließende Gegenstück nicht gefunden.\n"
                    + "\t" + "filename      : " + filename + "\n"
                    + "\t" + "pathElement   : " + pathElement + "\n"
                    + "\t" + "strokeWithRest: " + strokeWithRest + "\n"
                    );
        }
        String strokeElement = strokeWithRest.substring(0, endIndex + STROKE_END_PHRASE.length());
        String fullStrokeName = strokeElement.substring(STROKE_START_PHRASE.length(),
                strokeElement.length() - STROKE_END_PHRASE.length());
        String expectedStart = codePoint + "-";
        if (!fullStrokeName.startsWith(expectedStart)) {
            throw new RuntimeException("Der Name eines Strokes beginnt nicht mit dem "
                    + "Unicode-Codepoint des Kanji und einem Bindestrich.\n"
                    + "\t" + "filename      : " + filename + "\n"
                    + "\t" + "pathElement   : " + pathElement + "\n"
                    + "\t" + "strokeElement : " + strokeElement + "\n"
                    + "\t" + "fullStrokeName: " + fullStrokeName + "\n"
                    + "\t" + "pathIdPart    : " + codePoint + "\n"
                    );
        }
        return fullStrokeName.substring(expectedStart.length());
    }

    private static final String PATH_D_START_PHRASE = " d=\"";
    private static final String PATH_D_END_PHRASE = "\"";

    private String extractPath(String pathElement) {
        int startIndex = pathElement.indexOf(PATH_D_START_PHRASE);
        if (startIndex == -1) {
            throw new RuntimeException("In einem Pfad-Element wurd keine Pfad gefunden.\n"
                    + "\t" + "filename      : " + filename + "\n"
                    + "\t" + "pathElement   : " + pathElement + "\n"
                    );
        }
        String pathDElement = pathElement.substring(startIndex,
                pathElement.length() - PATH_ELEMENT_END_PHRASE.length());
        if (!pathDElement.endsWith(PATH_D_END_PHRASE)) {
            throw new RuntimeException("Zu einem öffnenden Pfad in einem Pfad-Element wurde das "
                    + "schließende Gegenstück nicht gefunden.\n"
                    + "\t" + "filename    : " + filename + "\n"
                    + "\t" + "pathElement : " + pathElement + "\n"
                    + "\t" + "pathWithRest: " + pathDElement + "\n"
                    );
        }
        return pathDElement.substring(PATH_D_START_PHRASE.length(),
                pathDElement.length() - PATH_D_END_PHRASE.length());
    }

    /**
     * Getter für den Unicode-Codepoint des Kanji als UTF8-Zeichen. Hier ist das der zum Kanji
     * passende Teil der ID im ID-Teil des Pfad-Element, welche z.B. so aussieht:
     * id="kvg:06f22-s1".
     */
    public String getCodePoint() {
        return codePoint;
    }

    /** Getter für die Liste der extrahierten Pfade mit den Strichnummern. */
    public List<PathWithStrokeNumber> getExtractedPathes() {
        return extractedPathes;
    }

    public static void main(String[] args) {
        String filename = "c:\\TEMP\\kanjivg\\06f22.svg";
        KanjiVgSvgPathesExtractor extrator = new KanjiVgSvgPathesExtractor(filename);
        extrator.extract();
        List<PathWithStrokeNumber> pathes = extrator.getExtractedPathes();

        for (PathWithStrokeNumber path : pathes) {
            System.out.println(path);
        }
    }

}
