/**
 * Copyright 2017 Pivotal Software, Inc.
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package io.micrometer.statsd.internal;

import io.micrometer.core.instrument.Meter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Statistic;
import io.micrometer.core.instrument.config.NamingConvention;
import io.micrometer.core.lang.Nullable;
import org.pcollections.HashTreePMap;
import org.pcollections.PMap;

import java.util.stream.Collectors;

public class SysdigStatsdLineBuilder extends FlavorStatsdLineBuilder {
    private final Object tagsLock = new Object();
    @SuppressWarnings({"NullableProblems", "unused"})
    private volatile NamingConvention namingConvention;
    @SuppressWarnings("NullableProblems")
    private volatile String name;
    @Nullable
    private volatile String conventionTags;
    @SuppressWarnings("NullableProblems")
    private volatile String tagsNoStat;
    private volatile PMap<Statistic, String> tags = HashTreePMap.empty();

    public SysdigStatsdLineBuilder(Meter.Id id, MeterRegistry.Config config) {
        super(id, config);
    }

    @Override
    String line(String amount, @Nullable Statistic stat, String type) {
        updateIfNamingConventionChanged();
        return name + tagsByStatistic(stat) + ":" + amount + "|" + type;
    }

    private void updateIfNamingConventionChanged() {
        NamingConvention next = config.namingConvention();
        if (this.namingConvention != next) {
            this.namingConvention = next;
            this.name = sanitizeCharacters(next.name(id.getName(), id.getType(), id.getBaseUnit()));
            this.tags = HashTreePMap.empty();
            this.conventionTags = id.getTagsAsIterable().iterator().hasNext() ?
                    id.getConventionTags(this.namingConvention).stream()
                            .map(t -> sanitizeCharacters(t.getKey()) + "=" + sanitizeCharacters(t.getValue()))
                            .collect(Collectors.joining(","))
                    : null;
            this.tagsNoStat = tags(null, conventionTags, "=", "#");
        }
    }

    private String sanitizeCharacters(String toSanitize) {
        if (toSanitize == null || toSanitize.isEmpty()) {
            return toSanitize;
        }
        char[] strArr = toSanitize.toCharArray();
        char[] newArr = new char[strArr.length];
        for (int x = 0; x < strArr.length; x++) {
            Character c = strArr[x];
            if (!Character.isAlphabetic(c) && !Character.isDigit(c) && c != '_' && c != '.') {
                newArr[x] = '_';
            } else {
                newArr[x] = c;
            }

        }
        String sanitized = String.valueOf(newArr);
        return sanitized;
    }

    private String tagsByStatistic(@Nullable Statistic stat) {
        if (stat == null) {
            return tagsNoStat;
        }

        String tagString = tags.get(stat);
        if (tagString != null)
            return tagString;

        synchronized (tagsLock) {
            tagString = tags.get(stat);
            if (tagString != null) {
                return tagString;
            }

            tagString = tags(stat, conventionTags, "=", "#");
            tags = tags.plus(stat, tagString);
            return tagString;
        }
    }
}
@@ -964,16 +964,48 @@
 .PMap;%0A%0A
+import java.util.regex.Pattern;%0A
 import j
@@ -1032,16 +1032,16 @@
 ectors;%0A
-
 %0Apublic 
@@ -1555,16 +1555,96 @@
 pty();%0A%0A
+    private static final Pattern NAME_WHITELIST = Pattern.compile(%22%5B%5E%5C%5Cw._%5D%22);%0A%0A
     publ
@@ -2188,26 +2188,16 @@
 sanitize
-Characters
 (next.na
@@ -2488,34 +2488,24 @@
  -%3E sanitize
-Characters
 (t.getKey())
@@ -2521,26 +2521,16 @@
 sanitize
-Characters
 (t.getVa
@@ -2728,109 +2728,42 @@
 ate 
-String sanitizeCharacters(
+static 
 String 
-toS
+s
 anitize
-) %7B%0A        if (toSanitize == null %7C%7C toSanitize.isEmpty()
+(String name
 ) %7B%0A
@@ -2774,507 +2774,59 @@
     
-    
 return 
-toSanitize;%0A        %7D%0A        char%5B%5D strArr = toSanitize.toCharArray();%0A        char%5B%5D newArr = new char%5BstrArr.length%5D;%0A        for (int x = 0; x %3C strArr.length; x++) %7B%0A            Character c = strArr%5Bx%5D;%0A            if (!Character.isAlphabetic(c) && !Character.isDigit(c) && c != '_' && c != '.') %7B%0A                newArr%5Bx%5D = '_';%0A            %7D else %7B%0A                newArr%5Bx%5D = c;%0A            %7D%0A%0A        %7D%0A        String sanitized = String.valueOf(newArr);%0A        return sanitized
+NAME_WHITELIST.matcher(name).replaceAll(%22_%22)
 ;%0A  

Simplify sysdig sanitization