/* FichothequeLib_Tools - Copyright (c) 2006-2017 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.parsers;

import net.fichotheque.corpus.fiche.TextContentBuilder;
import net.fichotheque.tools.parsers.span.SpanParseResult;
import net.fichotheque.tools.parsers.span.SpanParser;
import net.mapeadores.util.text.TypoOptions;


/**
 *
 * @author Vincent Calame
 */
public class TextContentParser {

    private final SpanParser bracketsParser;
    private final SpanParser emphasisParser;
    private final SpanParser httpParser = SpanParser.getHttpParser();
    private final SpanParser wwwParser = SpanParser.getWwwParser();
    private final TypoOptions typoOptions;

    public TextContentParser() {
        this.bracketsParser = null;
        this.emphasisParser = null;
        this.typoOptions = null;
    }

    public TextContentParser(TypoOptions typoOptions) {
        this.bracketsParser = SpanParser.getBracketsParser(typoOptions);
        this.emphasisParser = SpanParser.getEmphasisParser(typoOptions);
        this.typoOptions = typoOptions;
    }

    public void parse(TextContentBuilder textContentBuilder, String token) {
        int length = token.length();
        if (length == 0) {
            return;
        }
        boolean onQuote = false;
        char quoteChar = 0;
        StringBuilder buf = new StringBuilder(token.length());
        for (int i = 0; i < length; i++) {
            char carac = token.charAt(i);
            if (onQuote) {
                buf.append(carac);
                if (carac == quoteChar) {
                    flushBuffer(textContentBuilder, buf, false);
                    onQuote = false;

                } else if ((carac == '\\') && (i < (length - 1))) {
                    char next = token.charAt(i + 1);
                    if (next == quoteChar) {
                        buf.append(quoteChar);
                        i = i + 1;
                    }
                }
            } else {
                SpanParseResult spanParseResult = null;
                if ((carac == '"') && (isInformaticQuote(token, i))) {
                    flushBuffer(textContentBuilder, buf, true);
                    quoteChar = carac;
                    onQuote = true;
                } else if ((carac == '\'') && (isInformaticQuote(token, i))) {
                    flushBuffer(textContentBuilder, buf, true);
                    quoteChar = carac;
                    onQuote = true;
                } else if ((carac == '[') && (bracketsParser != null)) {
                    spanParseResult = bracketsParser.parse(token, i);
                } else if ((carac == '{') && (emphasisParser != null)) {
                    spanParseResult = emphasisParser.parse(token, i);
                } else if (carac == 'h') {
                    spanParseResult = httpParser.parse(token, i);
                } else if (carac == 'w') {
                    spanParseResult = wwwParser.parse(token, i);
                }
                if (spanParseResult != null) {
                    short state = spanParseResult.getState();
                    switch (state) {
                        case SpanParseResult.SUCCESS:
                            flushBuffer(textContentBuilder, buf, true);
                            textContentBuilder.addS(spanParseResult.getSpan());
                            i = spanParseResult.getEndIndex();
                            break;
                        case SpanParseResult.SYNTAX_ERROR:
                            flushBuffer(textContentBuilder, buf, true);
                            textContentBuilder.addText(token.substring(i));
                            return;
                        default:
                            int ignoreCharCount = spanParseResult.getIgnoreCharCount();
                            if (ignoreCharCount > 0) {
                                for (int j = i; j < i + ignoreCharCount; j++) {
                                    buf.append(token.charAt(j));
                                }
                                i = i + ignoreCharCount - 1;
                            }
                            break;
                    }
                } else {
                    buf.append(carac);
                }
            }
        }
        flushBuffer(textContentBuilder, buf, !onQuote);
    }

    private void flushBuffer(TextContentBuilder textContentBuilder, StringBuilder buf, boolean withTypo) {
        int bufLength = buf.length();
        if (bufLength > 0) {
            String text;
            if ((withTypo) && (typoOptions != null)) {
                text = TypoParser.parseTypo(buf, 0, bufLength, typoOptions);
            } else {
                text = buf.toString();
            }
            textContentBuilder.addText(text);
            buf.delete(0, bufLength);
        }
    }

    private static boolean isInformaticQuote(String token, int currentIndex) {
        if (currentIndex == 0) {
            return false;
        }
        for (int i = (currentIndex - 1); i >= 0; i--) {
            char carac = token.charAt(i);
            if (carac == ' ') {
                continue;
            }
            switch (carac) {
                case '(':
                case '{':
                case '[':
                case '=':
                    return true;
                default:
                    return false;
            }
        }
        return false;
    }

}
