001package ball.game.scrabble;
002/*-
003 * ##########################################################################
004 * Game Applications and Utilities
005 * %%
006 * Copyright (C) 2010 - 2022 Allen D. Ball
007 * %%
008 * Licensed under the Apache License, Version 2.0 (the "License");
009 * you may not use this file except in compliance with the License.
010 * You may obtain a copy of the License at
011 *
012 *      http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing, software
015 * distributed under the License is distributed on an "AS IS" BASIS,
016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017 * See the License for the specific language governing permissions and
018 * limitations under the License.
019 * ##########################################################################
020 */
021import ball.annotation.CompileTimeCheck;
022import java.text.Collator;
023import java.util.LinkedHashSet;
024import java.util.Locale;
025import java.util.ResourceBundle;
026import java.util.Set;
027import java.util.TreeMap;
028import java.util.regex.Pattern;
029
030/**
031 * Abstract Word List base class.
032 *
033 * @author {@link.uri mailto:ball@hcf.dev Allen D. Ball}
034 */
035public abstract class WordList extends TreeMap<CharSequence,Set<String>> {
036    private static final long serialVersionUID = -2777411476474325653L;
037
038    @CompileTimeCheck
039    private static final Pattern BRACKETED = Pattern.compile("\\[[^]]+\\]");
040    @CompileTimeCheck
041    private static final Pattern ALTERNATIVES = Pattern.compile("-?[\\p{Upper}]+");
042
043    /**
044     * Sole constructor.
045     *
046     * @param   locale          The {@link Locale}.
047     */
048    protected WordList(Locale locale) {
049        super(Collator.getInstance(locale));
050
051        var bundle = ResourceBundle.getBundle(getClass().getName(), locale);
052
053        for (var key : bundle.keySet()) {
054            var value = bundle.getString(key);
055            var root = key.toUpperCase();
056            var line = String.join(" ", root, value).trim();
057
058            add(root, line);
059
060            var bracketed = BRACKETED.matcher(value);
061
062            while (bracketed.find()) {
063                var alternatives = ALTERNATIVES.matcher(bracketed.group());
064
065                while (alternatives.find()) {
066                    var word = alternatives.group();
067
068                    if (word.startsWith("-")) {
069                        word = root + word.replace("-", "");
070                    }
071
072                    add(word, line);
073                }
074            }
075        }
076    }
077
078    private void add(String word, String source) {
079        computeIfAbsent(word, k -> new LinkedHashSet<>()).add(source);
080    }
081}