001/*
002 *     Copyright 2021 Siroshun09
003 *
004 *     Licensed under the Apache License, Version 2.0 (the "License");
005 *     you may not use this file except in compliance with the License.
006 *     You may obtain a copy of the License at
007 *
008 *         http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *     Unless required by applicable law or agreed to in writing, software
011 *     distributed under the License is distributed on an "AS IS" BASIS,
012 *     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *     See the License for the specific language governing permissions and
014 *     limitations under the License.
015 */
016
017package com.github.siroshun09.mcmessage.util;
018
019import org.jetbrains.annotations.NotNull;
020
021import java.util.regex.Pattern;
022
023public final class Colorizer {
024
025    private static final String EMPTY = "";
026    private static final char COLOR_MARK = '&';
027    private static final String COLOR_MARK_STRING = String.valueOf(COLOR_MARK);
028    private static final char COLOR_SECTION = '§';
029    private static final String COLOR_SECTION_STRING = String.valueOf(COLOR_SECTION);
030    private static final char HEX_MARK = '#';
031    private static final char X = 'x';
032    private static final String COLOR_CODES = "0123456789AaBbCcDdEeFfKkLlMmNnOoRr";
033    private static final Pattern COLOR_SECTION_PATTERN = Pattern.compile("(?i)" + COLOR_SECTION + "[0-9A-FK-ORX]");
034    private static final Pattern COLOR_MARK_PATTERN =
035            Pattern.compile(COLOR_MARK + "((" + HEX_MARK + "[0-9a-fA-F]{6})|([0-9a-fk-orxA-FK-ORX]))");
036
037    private Colorizer() {
038        throw new UnsupportedOperationException();
039    }
040
041    @NotNull
042    public static String colorize(String str) {
043        if (str == null || str.isEmpty()) {
044            return EMPTY;
045        }
046
047        if (str.contains(COLOR_MARK_STRING)) {
048            StringBuilder builder = new StringBuilder(str);
049            return colorize(builder).toString();
050        } else {
051            return str;
052        }
053    }
054
055    public static @NotNull StringBuilder colorize(StringBuilder builder) {
056        if (builder == null) {
057            return new StringBuilder();
058        }
059
060        int i = builder.indexOf(COLOR_MARK_STRING);
061
062        if (i == -1) {
063            return builder;
064        }
065
066        int l = builder.length();
067
068        while (i != -1 && i + 1 < l) {
069            if (builder.charAt(i + 1) == HEX_MARK) {
070                if (i + 7 < l) {
071                    String hex = builder.substring(i + 2, i + 8);
072
073                    try {
074                        Integer.parseInt(hex, 16);
075                    } catch (NumberFormatException e) {
076                        i = builder.indexOf(COLOR_MARK_STRING, i + 1);
077                        continue;
078                    }
079
080                    builder.setCharAt(i, COLOR_SECTION);
081                    builder.setCharAt(i + 1, X);
082
083                    for (int j = i + 7; j != i + 1; j--) {
084                        builder.insert(j, COLOR_SECTION_STRING);
085                    }
086
087                    l = builder.length();
088                }
089
090                i = builder.indexOf(COLOR_MARK_STRING, i + 1);
091                continue;
092            }
093
094            if (-1 < COLOR_CODES.indexOf(builder.charAt(i + 1))) {
095                builder.setCharAt(i, COLOR_SECTION);
096            }
097
098            i = builder.indexOf(COLOR_MARK_STRING, i + 1);
099        }
100
101        return builder;
102    }
103
104    /**
105     * Strips the given string of color.
106     * <p>
107     * Example: {@code §aHello, §bWorld!} {@literal ->} {@code Hello, World!}
108     *
109     * @param str the string to strip
110     * @return stripped string
111     */
112    @NotNull
113    public static String stripColorCode(String str) {
114        return stripColorCode(str, COLOR_SECTION_PATTERN);
115    }
116
117    @NotNull
118    public static String stripMarkedColorCode(String str) {
119        return stripColorCode(str, COLOR_MARK_PATTERN);
120    }
121
122    @NotNull
123    public static String stripColorCode(String str, @NotNull Pattern pattern) {
124        if (str == null || str.isEmpty()) {
125            return EMPTY;
126        }
127
128        return pattern.matcher(str).replaceAll("");
129    }
130}