/* FichothequeLib_Tools - Copyright (c) 2007-2014 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.span;

import net.mapeadores.util.text.TypoOptions;


/**
 *
 * @author Vincent Calame
 */
public abstract class SpanParser {

    SpanParser() {
    }

    public static SpanParser getEmphasisParser(TypoOptions typoOptions) {
        return new EmphasisParser(typoOptions);
    }

    public static SpanParser getBracketsParser(TypoOptions typoOptions) {
        return new BracketsParser(typoOptions);
    }

    public static SpanParser getHttpParser() {
        return new HttpParser();
    }

    public static SpanParser getWwwParser() {
        return new WwwParser();
    }

    public abstract SpanParseResult parse(String sourceString, int startIndex);

    public abstract char getStartChar();


    /*
     *Valide si un caractère peut-être dans un url ou non lorsqu'on fait une reconnaissance avec http. La règle est assez restrictive.
     * Il est à noter que rentrer un url avec [[][]] n'impose, lui aucune restriction.
     */
    static boolean checkCharInUrl(char c) {
        if (c < '!' || c > '~') {
            return false;
        }
        switch (c) {
            case '"':
            case '>':
            case '<':
            case '\\':
            case '^':
            case '`':
            case '{':
            case '}':
                return false;
        }
        return true;
    }

    static int appendUrl(String source, StringBuilder buftexte, int beginIndex) {
        int length = source.length();
        int stopIndex = beginIndex - 1;
        UrlTester urlTester = new UrlTester(source);
        for (int i = beginIndex; i < length; i++) {
            boolean valid = urlTester.testChar(i);
            if (valid) {
                buftexte.append(source.charAt(i));
                stopIndex = i;
            } else {
                break;
            }
        }
        return stopIndex;
    }

    static String getValue(String source, int beginIndex, int stopIndex, char stopChar) {
        StringBuilder buf = new StringBuilder();
        for (int i = beginIndex; i < stopIndex; i++) {
            char carac = source.charAt(i);
            if ((i == beginIndex) && (carac == ' ')) {
                continue;
            }
            if ((carac == '\\') && (i < (stopIndex - 1))) {
                char next = source.charAt(i + 1);
                if ((next == stopChar) || (next == '\\')) {
                    buf.append(next);
                    i++;
                    continue;
                }
            }
            buf.append(carac);
        }
        return buf.toString();
    }

    static int getStopIndex(String source, int beginIndex, char stopChar) {
        int length = source.length();
        for (int i = beginIndex; i < length; i++) {
            char carac = source.charAt(i);
            if (carac == stopChar) {
                return i;
            }
            if (carac == '\\') {
                i++;
            }
        }
        return -1;
    }


    private static class UrlTester {

        private final String source;
        private int parenthesisOpened;

        private UrlTester(String source) {
            this.source = source;
            this.parenthesisOpened = 0;
        }

        private boolean testChar(int index) {
            char c = source.charAt(index);
            if (!checkCharInUrl(c)) {
                return false;
            }
            boolean testNext = false;
            switch (c) {
                case '?':
                case '.':
                case ',':
                case ';':
                    testNext = true;
                    break;
                case '(':
                    parenthesisOpened++;
                    break;
                case ')':
                    parenthesisOpened--;
                    if (parenthesisOpened < 0) {
                        return false;
                    } else {
                        break;
                    }
            }
            if (testNext) {
                if (index == (source.length() - 1)) {
                    return false;
                }
                char nextChar = source.charAt(index + 1);
                if (!checkCharInUrl(nextChar)) {
                    return false;
                }
            }
            return true;
        }

    }

}
