/* UtilLib - Copyright (c) 2010-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.mapeadores.util.regex;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import net.mapeadores.util.instruction.Argument;
import net.mapeadores.util.instruction.Instruction;
import net.mapeadores.util.instruction.InstructionParser;


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

    private final List<Couple> list = new ArrayList<Couple>();

    public RegexList() {
    }

    public int getRegexCount() {
        return list.size();
    }

    public static RegexList parse(String s) {
        BufferedReader bufReader = new BufferedReader(new StringReader(s));
        RegexList regexList = new RegexList();
        String ligne = null;
        int p = 0;
        try {
            while ((ligne = bufReader.readLine()) != null) {
                p++;
                ligne = ligne.trim();
                int length = ligne.length();
                if (length == 0) {
                    continue;
                }
                int idx = -1;
                for (int i = 0; i < length; i++) {
                    char c = ligne.charAt(i);
                    if (Character.isWhitespace(c)) {
                        idx = i;
                        break;
                    }
                }
                if (idx == -1) {
                    continue;
                }
                String patternString = ligne.substring(0, idx);
                String result = ligne.substring(idx + 1).trim();
                Pattern pattern = null;
                try {
                    pattern = Pattern.compile(patternString);
                } catch (PatternSyntaxException pse) {
                    continue;
                }
                Instruction instruction = InstructionParser.parse(result, null);
                regexList.add(pattern, instruction);
            }
        } catch (IOException ioe) {
        }
        return regexList;
    }

    private void add(Pattern pattern, Instruction instruction) {
        Map<Integer, String> groupMap = new HashMap<Integer, String>();
        Map<String, String> constantsMap = new HashMap<String, String>();
        for (Argument argument : instruction) {
            String key = argument.getKey();
            String value = argument.getValue();
            if (value == null) {
                constantsMap.put(key, "");
                continue;
            }
            int sl = value.length();
            if ((sl > 1) && (value.charAt(0) == '$')) {
                try {
                    int id = Integer.parseInt(value.substring(1));
                    if (id > 0) {
                        groupMap.put(id, key);
                        continue;
                    }
                } catch (NumberFormatException nfe) {
                }
            }
            constantsMap.put(key, value);
        }
        add(pattern, groupMap, constantsMap);
    }

    private void add(Pattern pattern, Map<Integer, String> groupMap, Map<String, String> constantsMap) {
        list.add(new Couple(pattern, groupMap, constantsMap));
    }

    public Map<String, String> getMap(String s) {
        for (Couple couple : list) {
            Map<String, String> map = couple.getResultMap(s);
            if (map != null) {
                return map;
            }
        }
        return null;
    }


    private class Couple {

        private final Pattern pattern;
        private final Map<String, String> constantsMap;
        private final Map<Integer, String> groupMap;

        Couple(Pattern pattern, Map<Integer, String> groupMap, Map<String, String> constantsMap) {
            this.pattern = pattern;
            this.groupMap = groupMap;
            this.constantsMap = constantsMap;
        }

        public Map<String, String> getResultMap(String s) {
            Matcher matcher = pattern.matcher(s);
            if (!matcher.matches()) {
                return null;
            }
            Map<String, String> map = new HashMap<String, String>(constantsMap);
            int groupCount = matcher.groupCount();
            for (int i = 1; i <= groupCount; i++) {
                String key = groupMap.get(i);
                if (key != null) {
                    map.put(key, matcher.group(i));
                }
            }
            return map;
        }

    }

}
