JazzySpellChecker.java :  » IntelliJ » idea-spellchecker » org » intellij » spellChecker » engine » Java Open Source

Java Open Source » IntelliJ » idea spellchecker 
idea spellchecker » org » intellij » spellChecker » engine » JazzySpellChecker.java
/*
 * Copyright 2007 Sergiy Dubovik, Alexey Efimov
 *
 * 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
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * 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 org.intellij.spellChecker.engine;

import com.swabunga.spell.engine.SpellDictionaryHashMap;
import com.swabunga.spell.engine.Word;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.*;

/**
 * Jazzy implementation of Spell Checker.
 *
 * @author Alexey Efimov
 */
final class JazzySpellChecker implements SpellChecker {
    private final SpellCheckerWrapper delegate = new SpellCheckerWrapper();
    private final Map<SpellDictionaryImpl, Set<Character>> dictionaries = new HashMap<SpellDictionaryImpl, Set<Character>>();
    private final Set<Character> allowed = new HashSet<Character>();
    private SpellDictionaryImpl userDictionary;

    JazzySpellChecker() {
        setUserDictionary();
    }

    public void addDictionary(@NotNull InputStream is, @NonNls String encoding, @NotNull Locale locale) throws IOException {
        SpellDictionaryImpl spellDictionary = new SpellDictionaryImpl(new InputStreamReader(is, encoding), locale);
        Set<Character> indexedChars = spellDictionary.getIndexedChars();
        dictionaries.put(spellDictionary, indexedChars);
        allowed.addAll(indexedChars);
        delegate.addDictionary(spellDictionary);
    }

    public void addToDictionary(@NotNull String word) {
        delegate.addToDictionary(word);
        indexWord(word);
    }

    private void indexWord(CharSequence word) {
        indexWord(word, allowed);
    }

    private static void indexWord(CharSequence word, Set<Character> index) {
        for (int i = 0; i < word.length(); i++) {
            index.add(word.charAt(i));
        }
    }

    public void ignoreAll(@NotNull String word) {
        delegate.ignoreAll(word);
    }

    public boolean isIgnored(@NotNull String word) {
        return !isEntireWordAllowed(word, allowed) || delegate.isIgnored(word);
    }

    public boolean isCorrect(@NotNull String word) {
        return !isEntireWordAllowed(word, allowed) || delegate.isCorrect(word);
    }

    private static boolean isEntireWordAllowed(CharSequence word, Set<Character> index) {
        for (int i = 0; i < word.length(); i++) {
            if (!index.contains(word.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    private Set<Character> findDictionaryIndex(String word) {
        Set<Character> commonIndex = null;
        Set<Character> lastIndex = null;
        Collection<Set<Character>> indexes = dictionaries.values();
        for (Set<Character> index : indexes) {
            if (isEntireWordAllowed(word, index)) {
                if (lastIndex != null && commonIndex == null) {
                    commonIndex = new HashSet<Character>(lastIndex.size() + index.size());
                    commonIndex.addAll(lastIndex);
                    lastIndex = commonIndex;
                }
                if (commonIndex != null) {
                    commonIndex.addAll(index);
                } else {
                    lastIndex = index;
                }
            }
        }
        return lastIndex;
    }

    @NotNull
    @SuppressWarnings({"unchecked"})
    public List<String> getSuggestions(@NotNull String word, int threshold) {
        List<Word> words = delegate.getSuggestions(word, threshold);
        Set<Character> index = findDictionaryIndex(word);
        List<String> strings = new ArrayList<String>(words.size());
        for (Word w : words) {
            String suggestion = w.getWord();
            if (index == null || isEntireWordAllowed(suggestion, index)) {
                strings.add(suggestion);
            }
        }
        return strings;
    }

    @NotNull
    public List<String> getVariants(@NotNull String prefix) {
        if (prefix.length() > 0) {
            List<String> variants = new ArrayList<String>();
            userDictionary.appendWordsStartsWith(prefix, variants);
            Set<Character> index = new HashSet<Character>();
            indexWord(prefix, index);
            for (SpellDictionaryImpl dictionary : dictionaries.keySet()) {
                Set<Character> dictionaryIndex = dictionaries.get(dictionary);
                if (isSame(index, dictionaryIndex)) {
                    dictionary.appendWordsStartsWith(prefix, variants);
                }
            }
            Collections.sort(variants);
            return variants;
        }
        return Collections.emptyList();
    }

    private static boolean isSame(@NotNull Set<Character> i1, @NotNull Set<Character> i2) {
        if (i1.equals(i2)) {
            return true;
        }
        for (Character c : i1) {
            if (!i2.contains(c)) {
                return false;
            }
        }
        return true;
    }

    public void reset() {
        delegate.reset();
        allowed.clear();
        Collection<Set<Character>> sets = dictionaries.values();
        for (Set<Character> set : sets) {
            allowed.addAll(set);
        }
        setUserDictionary();
    }

    private void setUserDictionary() {
        try {
            userDictionary = new SpellDictionaryImpl(Locale.getDefault());
            delegate.setUserDictionary(userDictionary);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private static class SpellDictionaryImpl extends SpellDictionaryHashMap {
        private final Locale locale;

        public SpellDictionaryImpl(Locale locale) throws IOException {
            this.locale = locale;
        }

        private SpellDictionaryImpl(Reader wordList, Locale locale) throws IOException {
            super(wordList);
            this.locale = locale;
        }

        @SuppressWarnings({"unchecked"})
        public Set<Character> getIndexedChars() {
            Set<Character> index = new HashSet<Character>(64);
            Collection<List<String>> values = mainDictionary.values();
            for (List<String> wordList : values) {
                if (wordList != null) {
                    for (String word : wordList) {
                        if (word != null) {
                            indexWord(word, index);
                        }
                    }
                }
            }
            return Collections.unmodifiableSet(index);
        }

        @SuppressWarnings({"unchecked"})
        public void appendWordsStartsWith(@NotNull String prefix, @NotNull Collection<String> buffer) {
            String prefixLowerCase = prefix.toLowerCase(locale);
            Collection<List<String>> values = mainDictionary.values();
            int prefixLength = prefix.length();
            StringBuilder builder = new StringBuilder();
            for (List<String> wordList : values) {
                if (wordList != null) {
                    for (String word : wordList) {
                        if (word != null) {
                            String lowerCased = word.toLowerCase(locale);
                            int length = lowerCased.length();
                            if (lowerCased.startsWith(prefixLowerCase) && length > prefixLength) {
                                builder.setLength(0);
                                builder.append(prefix);
                                builder.append(lowerCased, prefixLength, length);
                                String value = builder.toString();
                                if (!buffer.contains(value)) {
                                    buffer.add(value);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private static final class SpellCheckerWrapper extends com.swabunga.spell.event.SpellChecker {
        private SpellCheckerWrapper() {
            // Disable cashing
            setCache(0);
        }

        public List getSuggestions(String word, int threshold) {
            return super.getSuggestions(word, threshold);
        }
    }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.