package mnm.mods.tabbychat.extra.filters;

import mnm.mods.tabbychat.api.Channel;
import mnm.mods.tabbychat.api.TabbyAPI;
import mnm.mods.tabbychat.api.filters.Filter;
import mnm.mods.tabbychat.api.filters.FilterEvent;
import mnm.mods.tabbychat.api.filters.FilterSettings;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.text.ITextComponent;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.annotation.RegEx;

public class UserFilter implements Filter {

    private String name = "New Filter";
    private FilterSettings settings = new FilterSettings();
    private String pattern = ".*";

    private transient Pattern expression;

    public void setPattern(@RegEx String pattern) throws PatternSyntaxException {
        testPatternUnsafe(pattern);
        this.pattern = pattern;
        this.expression = null;
    }

    public void testPattern(String pattern) throws UserPatternException {
        try {
            testPatternUnsafe(pattern);
        } catch (PatternSyntaxException e) {
            throw new UserPatternException(e);
        }
    }

    private void testPatternUnsafe(String pattern) throws PatternSyntaxException {
        Pattern.compile(resolvePattern(pattern));
    }

    @Override
    public Pattern getPattern() {
        if (expression == null) {
            this.expression = Pattern.compile(resolvePattern(pattern), settings.getFlags());
        }
        return expression;
    }

    private String resolvePattern(String pattern) {
        String resolved = resolveVariables(pattern);
        if (!settings.isRegex()) {
            resolved = Pattern.quote(resolved);
        }
        return resolved;
    }

    public String getRawPattern() {
        return this.pattern;
    }

    @RegEx
    private static String resolveVariables(String pattern) {
        Matcher matcher = Pattern.compile("\\$\\{([\\w\\d]+)}").matcher(pattern);
        StringBuffer buffer = new StringBuffer();
        while (matcher.find()) {
            String key = matcher.group(1);
            String var = FilterAddon.getVariable(key);
            matcher.appendReplacement(buffer, var);
        }
        matcher.appendTail(buffer);

        return pattern;
    }

    @Override
    public void action(FilterEvent event) {

        if (settings.isRemove()) {
            // remove
            event.channels.clear();
        } else {
            // add channels
            for (String name : settings.getChannels()) {
                // TODO multiple replacements in a single name
                Matcher matcher = Pattern.compile("^\\$(\\d+)$").matcher(name);
                if (matcher.find()) {
                    // find groups
                    int group = Integer.parseInt(matcher.group(1));
                    if (group > 0 && event.matcher.groupCount() >= group) {
                        name = event.matcher.group(group);
                        if (name == null) {
                            continue;
                        }
                    } else {
                        continue;
                    }
                }

                // PMs start with a '@' character
                boolean pm = name.startsWith("@");
                // remove # or @ from the start of the channel name
                if (name.matches("^[@#]"))
                    name = name.substring(1);
                Channel channel = TabbyAPI.getAPI().getChat().getChannel(name, pm);
                event.channels.add(channel);
            }
        }
        // play sound
        if (settings.isSoundNotification()) {
            settings.getSoundName()
                    .map(ResourceLocation::new)
                    .map(SoundEvent.REGISTRY::getObject)
                    .map(sndEvent -> PositionedSoundRecord.getMasterRecord(sndEvent, 1.0F))
                    .ifPresent(Minecraft.getMinecraft().getSoundHandler()::playSound);

        }
    }

    @Override
    public String prepareText(ITextComponent string) {
        return settings.isRaw() ? string.getFormattedText() : Filter.super.prepareText(string);
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return this.name;
    }

    public FilterSettings getSettings() {
        return settings;
    }

    class UserPatternException extends Exception {
        private UserPatternException(PatternSyntaxException e) {
            super(e);
        }
    }
}

@@ -2688,46 +2688,39 @@
  // 
-TODO multiple replacem
+replace group tok
 en
-t
 s in 
-a single
+channel
  nam
@@ -2772,17 +2772,16 @@
 ompile(%22
-%5E
 %5C%5C$(%5C%5Cd+
@@ -2781,17 +2781,16 @@
 %5C$(%5C%5Cd+)
-$
 %22).match
@@ -2815,18 +2815,21 @@
         
-if
+while
  (matche
@@ -3043,20 +3043,32 @@
         
-name
+String groupText
  = event
@@ -3118,22 +3118,27 @@
     if (
-name =
+groupText !
 = null) 
@@ -3171,128 +3171,335 @@
     
-continue;%0A                        %7D%0A                    %7D else %7B%0A                        continue;%0A                    %7D
+name = name.replace(matcher.group(), groupText);%0A                            continue;%0A                        %7D%0A                    %7D%0A                    name = null;%0A                    break;%0A                %7D%0A                // skip this because there were missing or out of bounds groups.%0A                if (name == null)
 %0A   
@@ -3507,25 +3507,37 @@
             
-%7D
+    continue;
 %0A%0A          
@@ -3724,22 +3724,45 @@
 ame.
-matches(%22%5E%5B@#%5D
+startsWith(%22#%22) %7C%7C name.startsWith(%22@
 %22))%0A
@@ -3803,24 +3803,25 @@
 bstring(1);%0A
+%0A
             

Allow multiple groups to be referenced in a channel. Fixes being unable to use groups in PMs.