package org.unicode.cldr.draft;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.unicode.cldr.draft.PatternFixer.Target;

import com.ibm.icu.impl.Utility;
import com.ibm.icu.text.Normalizer;
import com.ibm.icu.text.StringTransform;
import com.ibm.icu.text.Transliterator;
import com.ibm.icu.text.UnicodeSet;

public class RegexTransformBuilder {
    static final boolean DEBUG = false;
    private static final boolean SKIP_BAD = true;

    // initially just very rough rule parser, for proof-of-concept
    public static StringTransform createFromRules(String string) {
        List<StringTransform> compound = new ArrayList<>();

        List<Rule> rules = new ArrayList<>();
        String[] ruleSet = string.split(";");
        Matcher m = RULE_PATTERN.matcher("");
        List<String> results = new ArrayList<>();
        Matcher variable = VARIABLE.matcher("");
        UnicodeSet filter = null;

        if (DEBUG) System.out.println();

        for (String ruleString : ruleSet) {
            ruleString = ruleString.trim();
            if (DEBUG) System.out.print(ruleString + "\t=>\t");

            if (ruleString.startsWith("::")) {
                if (rules.size() != 0) {
                    compound.add(new RegexTransform(rules));
                    rules.clear();
                }
                final String body = ruleString.substring(2).trim();
                if (body.equalsIgnoreCase("NULL")) {
                    // nothing
                    if (DEBUG) System.out.println();
                } else if (UnicodeSet.resemblesPattern(body, 0)) {
                    filter = new UnicodeSet(body);
                    if (DEBUG) System.out.println(":: " + filter + " ;");
                } else {
                    // if we didn't find a filter, it is a Transliterator
                    final Transliterator translit = Transliterator.getInstance(body.trim());
                    compound.add(translit);
                    if (DEBUG) System.out.println(":: " + translit + " ;");
                }
                continue;
            }
            if (!m.reset(ruleString).matches()) {
                if (SKIP_BAD) {
                    System.out.println("BAD RULE");
                    continue;
                } else {
                    throw new IllegalArgumentException("Bad rule: {" + Utility.escape(ruleString) + "} ;");
                }
            }

            String pre = m.group(1);
            if (pre == null) {
                pre = "";
            } else {
                pre = fix(pre);
            }

            String main = fix(m.group(2));
            if (m.group(3) != null) {
                main += "(?=" + fix(m.group(3)) + ")";
            }

            results.clear();
            String result = m.group(4).trim();
            variable.reset(result);
            int last = 0;
            while (true) {
                if (!variable.find()) {
                    results.add(result.substring(last));
                    break;
                } else {
                    results.add(result.substring(last, variable.start()));
                    results.add(variable.group());
                    last = variable.end();
                }
            }
            try {
                Rule rule = new Rule(pre, main, results);
                if (DEBUG) System.out.println(rule);
                rules.add(rule);
            } catch (Exception e) {
                System.out.println("BAD:\t" + e.getMessage());
            }
        }

        // add any trailing rules
        if (rules.size() != 0) {
            compound.add(new RegexTransform(rules));
            rules.clear();
        }

        // generate final result
        StringTransform result = compound.size() == 1 ? compound.get(0) : new CompoundTransform(compound);
        if (filter != null) {
            return new UnicodeSetFilteredTransform(filter, result);
        }
        return result;
    }

    private static String fix(String pattern) {
        pattern = pattern.trim();
        // TODO fix pattern to not have anything but NFD in patterns
        PATTERN_FIXER.fix(pattern);
        pattern = Normalizer.decompose(pattern, false);
        // pre = pre.replace("[:", "\\p{");
        // pre = pre.replace(":]", "}");
        return pattern;
    }

    private static final PatternFixer PATTERN_FIXER = new PatternFixer(Target.JAVA);

    static Pattern RULE_PATTERN = Pattern.compile(
        "(?:([^{}>]*) \\{)?" +
            "([^}<>]*)" +
            "(?:\\} ([^<>]*))?" +
            "<?> (.*)",
        Pattern.COMMENTS);
    static Pattern VARIABLE = Pattern.compile(
        "\\$[0-9]",
        Pattern.COMMENTS);
}
