package org.monospark.spongematchers.parser.element;

import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.monospark.spongematchers.parser.SpongeMatcherParseException;
import org.monospark.spongematchers.parser.base.BaseMatcherParser;
import org.monospark.spongematchers.parser.element.PatternElement.Type;

import com.google.common.collect.Sets;

public abstract class StringElementParser {

    public static final Pattern REPLACE_PATTERN = Pattern.compile("#+");
    
    private static final Set<StringElementParser> BASE_ELEMENT_PARSERS = createBaseElementParsers();
    
    private static final Set<StringElementParser> OTHER_ELEMENT_PARSERS = createOtherElementParsers();
    
    private static Set<StringElementParser> createBaseElementParsers() {
        Set<StringElementParser> baseParsers = Sets.newLinkedHashSet();
        baseParsers.add(new BaseElementParser<>(BaseMatcherParser.STRING));
        baseParsers.add(new BaseElementParser<>(BaseMatcherParser.BOOLEAN));
        baseParsers.add(new BaseElementParser<>(BaseMatcherParser.FLOATING_POINT));
        baseParsers.add(new BaseElementParser<>(BaseMatcherParser.INTEGER));
        baseParsers.add(new LiteralElementParser(LiteralElement.Type.EMPTY));
        baseParsers.add(new LiteralElementParser(LiteralElement.Type.WILDCARD));
        return baseParsers;
    }
    
    private static Set<StringElementParser> createOtherElementParsers() {
        Set<StringElementParser> otherParsers = Sets.newHashSet();
        otherParsers.add(new PatternElementParser(Type.PARANTHESES));
        otherParsers.add(new PatternElementParser(Type.NOT));
        otherParsers.add(new ConnectedElementParser());
        otherParsers.add(new ListElementParser());
        otherParsers.add(new PatternElementParser(Type.LIST_MATCH_ANY));
        otherParsers.add(new PatternElementParser(Type.LIST_MATCH_ALL));
        otherParsers.add(new MapElementParser());
        return otherParsers;
    }
    
    public static StringElement parseStringElement(String string) throws SpongeMatcherParseException {
        StringElementContext context = new StringElementContext(string.trim());
        for (StringElementParser parser : BASE_ELEMENT_PARSERS) {
            parser.parseElements(context);
        }
        String lastContextString;
        do {
            lastContextString = context.getString();
            for (StringElementParser parser : OTHER_ELEMENT_PARSERS) {
                parser.parseElements(context);
            }
        } while (!lastContextString.equals(context.getString()));
        
        return context.getFinalElement();
    }

    private Pattern pattern;
    
    StringElementParser() {}
    
    abstract Pattern createPattern();
    
    final void parseElements(StringElementContext context) throws SpongeMatcherParseException {
        if (pattern == null) {
            pattern = createPattern();
        }
        
        Matcher matcher = pattern.matcher(context.getString());
        while (matcher.find()) {
            parse(matcher, context);
        }
    }
    
    abstract void parse(Matcher matcher, StringElementContext context) throws SpongeMatcherParseException;
}

@@ -559,19 +559,23 @@
 Parser%3E 
-BAS
+ONE_TIM
 E_ELEMEN
@@ -588,27 +588,30 @@
 ERS = create
-Bas
+OneTim
 eElementPars
@@ -672,21 +672,26 @@
 Parser%3E 
-OTHER
+MANY_TIMES
 _ELEMENT
@@ -703,29 +703,33 @@
 ERS = create
-Other
+ManyTimes
 ElementParse
@@ -789,19 +789,22 @@
 %3E create
-Bas
+OneTim
 eElement
@@ -848,19 +848,22 @@
 Parser%3E 
-bas
+oneTim
 eParsers
@@ -890,35 +890,38 @@
 hSet();%0A        
-bas
+oneTim
 eParsers.add(new
@@ -969,35 +969,38 @@
 RING));%0A        
-bas
+oneTim
 eParsers.add(new
@@ -1049,35 +1049,38 @@
 LEAN));%0A        
-bas
+oneTim
 eParsers.add(new
@@ -1136,35 +1136,38 @@
 OINT));%0A        
-bas
+oneTim
 eParsers.add(new
@@ -1216,35 +1216,38 @@
 EGER));%0A        
-bas
+oneTim
 eParsers.add(new
@@ -1305,19 +1305,22 @@
         
-bas
+oneTim
 eParsers
@@ -1396,19 +1396,22 @@
  return 
-bas
+oneTim
 eParsers
@@ -1477,13 +1477,17 @@
 eate
-Other
+ManyTimes
 Elem
@@ -1534,21 +1534,25 @@
 Parser%3E 
-other
+manyTimes
 Parsers 
@@ -1572,37 +1572,41 @@
 hSet();%0A        
-other
+manyTimes
 Parsers.add(new 
@@ -1646,37 +1646,41 @@
 ESES));%0A        
-other
+manyTimes
 Parsers.add(new 
@@ -1712,37 +1712,41 @@
 .NOT));%0A        
-other
+manyTimes
 Parsers.add(new 
@@ -1772,37 +1772,41 @@
 ser());%0A        
-other
+manyTimes
 Parsers.add(new 
@@ -1827,37 +1827,41 @@
 ser());%0A        
-other
+manyTimes
 Parsers.add(new 
@@ -1904,37 +1904,41 @@
 _ANY));%0A        
-other
+manyTimes
 Parsers.add(new 
@@ -1989,21 +1989,25 @@
         
-other
+manyTimes
 Parsers.
@@ -2054,13 +2054,17 @@
 urn 
-other
+manyTimes
 Pars
@@ -2308,11 +2308,15 @@
 r : 
-BAS
+ONE_TIM
 E_EL
@@ -2535,13 +2535,18 @@
 r : 
-OTHER
+MANY_TIMES
 _ELE

Make differences between StringElementParsers clear