/* FichothequeLib_Tools - Copyright (c) 2020-2022 Vincent Calame - Exemole
 * Logiciel libre donné sous triple licence :
 * 1) selon les termes de la CeCILL V2
 * 2) selon les termes de l’EUPL V.1.1
 * 3) selon les termes de la GNU GPLv3
 * Voir le fichier licences.txt
 */


package net.fichotheque.tools.extraction.syntaxes;

import java.io.IOException;
import java.util.Locale;
import net.fichotheque.corpus.fiche.FicheBlock;
import net.fichotheque.corpus.fiche.P;
import net.fichotheque.corpus.fiche.ParagraphBlock;
import net.fichotheque.syntax.FicheblockCodemirror;
import net.fichotheque.tools.parsers.LineInfo;
import net.fichotheque.tools.parsers.TextContentParser;
import net.fichotheque.tools.parsers.ficheblock.FicheBlockParser;
import net.fichotheque.utils.SyntaxUtils;
import net.mapeadores.util.exceptions.ShouldNotOccurException;
import net.mapeadores.util.text.TypoOptions;


/**
 *
 * @author Vincent Calame
 */
public final class FicheblockResolver {

    private final static TypoOptions TYPO_OPTIONS = TypoOptions.getTypoOptions(Locale.ENGLISH);

    private FicheblockResolver() {

    }

    public static String resolve(String value) {
        if (value.isEmpty()) {
            return "";
        }
        try {
            String zoneElement = resolveZoneElement(value);
            if (zoneElement != null) {
                return zoneElement;
            }
            String threeChars = resolveThreeChars(value);
            if (threeChars != null) {
                return threeChars;
            }
            return resolveLine(value);
        } catch (IOException ioe) {
            throw new ShouldNotOccurException();
        }
    }

    private static String resolveLine(String value) throws IOException {
        LineInfo lineInfo = LineInfo.parse(value, -1);
        if (lineInfo.hasAttsError()) {
            StringBuilder buf = new StringBuilder();
            SyntaxUtils.appendSpan(buf, "cm-error", value);
            return buf.toString();
        }
        StringBuilder buf = new StringBuilder();
        FicheblockCodemirror.appendAttsList(buf, lineInfo.getAttsList());
        if (lineInfo.isCleanedLineEmpty()) {
            return buf.toString();
        }
        String line = lineInfo.getCleanedLine();
        char firstChar = line.charAt(0);
        if ((firstChar == '-') || (firstChar == '_')) {
            return resolveList(firstChar, buf, line);
        }
        TextContentParser textContentParser = new TextContentParser(TYPO_OPTIONS);
        FicheBlock paragraph = FicheBlockParser.parseLine(lineInfo.deriveWithoutAttsList(), textContentParser);
        FicheblockCodemirror.appendFicheBlock(buf, paragraph);
        return buf.toString();
    }

    private static String resolveList(char firstChar, StringBuilder buf, String line) throws IOException {
        int index = 1;
        int lineLength = line.length();
        StringBuilder listBuffer = new StringBuilder();
        listBuffer.append(firstChar);
        for (int i = 1; i < lineLength; i++) {
            if (line.charAt(i) == firstChar) {
                listBuffer.append(firstChar);
                index++;
            }
        }
        SyntaxUtils.appendSpan(buf, "cm-ficheblock-firstchars", listBuffer.toString());
        if (index < (lineLength - 1)) {
            buf.append(' ');
            P p = new P();
            TextContentParser textContentParser = new TextContentParser(TYPO_OPTIONS);
            textContentParser.parse(p, line.substring(index));
            FicheblockCodemirror.appendTextContent(buf, p, "");
        }
        return buf.toString();
    }


    private static String resolveThreeChars(String value) throws IOException {
        String threeCharsClass = testTreeChars(value);
        if (threeCharsClass != null) {
            StringBuilder buf = new StringBuilder();
            SyntaxUtils.appendSpan(buf, threeCharsClass, value.substring(0, 3));
            if (value.length() > 3) {
                SyntaxUtils.appendSpan(buf, "cm-ficheblock-zone-parameters", value.substring(3));
            }
            return buf.toString();
        } else {
            return null;
        }
    }

    private static String resolveZoneElement(String value) throws IOException {
        int length = value.length();
        if (length < 2) {
            return null;
        }
        if (value.charAt(1) != '=') {
            return null;
        }
        char firstChar = value.charAt(0);
        if ((firstChar < 'a') || (firstChar > 'z')) {
            return null;
        }
        StringBuilder buf = new StringBuilder();
        SyntaxUtils.appendSpan(buf, "cm-ficheblock-zone-elementname", value.substring(0, 2));
        if (length > 2) {
            if (isText(firstChar)) {
                TextContentParser textContentParser = new TextContentParser(TYPO_OPTIONS);
                ParagraphBlock paragraphBlock = new ParagraphBlock();
                textContentParser.parse(paragraphBlock, value.substring(2));
                FicheblockCodemirror.appendTextContent(buf, paragraphBlock, " cm-ficheblock-zone-elementcontent");
            } else {
                SyntaxUtils.appendSpan(buf, "cm-ficheblock-zone-elementvalue", value.substring(2));
            }
        }
        return buf.toString();
    }

    private static String testTreeChars(String value) {
        if (value.startsWith("???")) {
            return "cm-ficheblock-cdata cm-ficheblock-zone-firstchars";
        }
        if (value.startsWith("+++")) {
            return "cm-ficheblock-code cm-ficheblock-zone-firstchars";
        }
        if (value.startsWith("!!!")) {
            return "cm-ficheblock-div cm-ficheblock-zone-firstchars";
        }
        if (value.startsWith("===")) {
            return "cm-ficheblock-table cm-ficheblock-zone-firstchars";
        }
        if (value.startsWith(":::")) {
            return "cm-ficheblock-insert cm-ficheblock-zone-firstchars";
        }
        return null;
    }

    private static boolean isText(char firstChar) {
        switch (firstChar) {
            case 'l':
            case 'n':
            case 'a':
            case 'c':
                return true;
            default:
                return false;
        }
    }

}
