1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.inputmethod.latin;
18
19import android.util.Log;
20
21import com.android.inputmethod.latin.SuggestedWords.SuggestedWordInfo;
22import com.android.inputmethod.latin.common.ComposedData;
23import com.android.inputmethod.latin.settings.SettingsValuesForSuggestion;
24
25import java.util.ArrayList;
26import java.util.Collection;
27import java.util.Collections;
28import java.util.Locale;
29import java.util.concurrent.CopyOnWriteArrayList;
30
31/**
32 * Class for a collection of dictionaries that behave like one dictionary.
33 */
34public final class DictionaryCollection extends Dictionary {
35    private final String TAG = DictionaryCollection.class.getSimpleName();
36    protected final CopyOnWriteArrayList<Dictionary> mDictionaries;
37
38    public DictionaryCollection(final String dictType, final Locale locale) {
39        super(dictType, locale);
40        mDictionaries = new CopyOnWriteArrayList<>();
41    }
42
43    public DictionaryCollection(final String dictType, final Locale locale,
44            final Dictionary... dictionaries) {
45        super(dictType, locale);
46        if (null == dictionaries) {
47            mDictionaries = new CopyOnWriteArrayList<>();
48        } else {
49            mDictionaries = new CopyOnWriteArrayList<>(dictionaries);
50            mDictionaries.removeAll(Collections.singleton(null));
51        }
52    }
53
54    public DictionaryCollection(final String dictType, final Locale locale,
55            final Collection<Dictionary> dictionaries) {
56        super(dictType, locale);
57        mDictionaries = new CopyOnWriteArrayList<>(dictionaries);
58        mDictionaries.removeAll(Collections.singleton(null));
59    }
60
61    @Override
62    public ArrayList<SuggestedWordInfo> getSuggestions(final ComposedData composedData,
63            final NgramContext ngramContext, final long proximityInfoHandle,
64            final SettingsValuesForSuggestion settingsValuesForSuggestion,
65            final int sessionId, final float weightForLocale,
66            final float[] inOutWeightOfLangModelVsSpatialModel) {
67        final CopyOnWriteArrayList<Dictionary> dictionaries = mDictionaries;
68        if (dictionaries.isEmpty()) return null;
69        // To avoid creating unnecessary objects, we get the list out of the first
70        // dictionary and add the rest to it if not null, hence the get(0)
71        ArrayList<SuggestedWordInfo> suggestions = dictionaries.get(0).getSuggestions(composedData,
72                ngramContext, proximityInfoHandle, settingsValuesForSuggestion, sessionId,
73                weightForLocale, inOutWeightOfLangModelVsSpatialModel);
74        if (null == suggestions) suggestions = new ArrayList<>();
75        final int length = dictionaries.size();
76        for (int i = 1; i < length; ++ i) {
77            final ArrayList<SuggestedWordInfo> sugg = dictionaries.get(i).getSuggestions(
78                    composedData, ngramContext, proximityInfoHandle, settingsValuesForSuggestion,
79                    sessionId, weightForLocale, inOutWeightOfLangModelVsSpatialModel);
80            if (null != sugg) suggestions.addAll(sugg);
81        }
82        return suggestions;
83    }
84
85    @Override
86    public boolean isInDictionary(final String word) {
87        for (int i = mDictionaries.size() - 1; i >= 0; --i)
88            if (mDictionaries.get(i).isInDictionary(word)) return true;
89        return false;
90    }
91
92    @Override
93    public int getFrequency(final String word) {
94        int maxFreq = -1;
95        for (int i = mDictionaries.size() - 1; i >= 0; --i) {
96            final int tempFreq = mDictionaries.get(i).getFrequency(word);
97            maxFreq = Math.max(tempFreq, maxFreq);
98        }
99        return maxFreq;
100    }
101
102    @Override
103    public int getMaxFrequencyOfExactMatches(final String word) {
104        int maxFreq = -1;
105        for (int i = mDictionaries.size() - 1; i >= 0; --i) {
106            final int tempFreq = mDictionaries.get(i).getMaxFrequencyOfExactMatches(word);
107            maxFreq = Math.max(tempFreq, maxFreq);
108        }
109        return maxFreq;
110    }
111
112    @Override
113    public boolean isInitialized() {
114        return !mDictionaries.isEmpty();
115    }
116
117    @Override
118    public void close() {
119        for (final Dictionary dict : mDictionaries)
120            dict.close();
121    }
122
123    // Warning: this is not thread-safe. Take necessary precaution when calling.
124    public void addDictionary(final Dictionary newDict) {
125        if (null == newDict) return;
126        if (mDictionaries.contains(newDict)) {
127            Log.w(TAG, "This collection already contains this dictionary: " + newDict);
128        }
129        mDictionaries.add(newDict);
130    }
131
132    // Warning: this is not thread-safe. Take necessary precaution when calling.
133    public void removeDictionary(final Dictionary dict) {
134        if (mDictionaries.contains(dict)) {
135            mDictionaries.remove(dict);
136        } else {
137            Log.w(TAG, "This collection does not contain this dictionary: " + dict);
138        }
139    }
140}
141