1/*
2 * Copyright (C) 2012 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
17#ifndef LATINIME_DIC_TRAVERSE_SESSION_H
18#define LATINIME_DIC_TRAVERSE_SESSION_H
19
20#include <stdint.h>
21#include <vector>
22
23#include "defines.h"
24#include "jni.h"
25#include "multi_bigram_map.h"
26#include "proximity_info_state.h"
27#include "suggest/core/dicnode/dic_nodes_cache.h"
28
29namespace latinime {
30
31class Dictionary;
32class ProximityInfo;
33
34class DicTraverseSession {
35 public:
36    AK_FORCE_INLINE DicTraverseSession(JNIEnv *env, jstring localeStr)
37            : mPrevWordPos(NOT_VALID_WORD), mProximityInfo(0),
38              mDictionary(0), mDicNodesCache(), mMultiBigramMap(),
39              mInputSize(0), mPartiallyCommited(false), mMaxPointerCount(1),
40              mMultiWordCostMultiplier(1.0f) {
41        // NOTE: mProximityInfoStates is an array of instances.
42        // No need to initialize it explicitly here.
43    }
44
45    // Non virtual inline destructor -- never inherit this class
46    AK_FORCE_INLINE ~DicTraverseSession() {}
47
48    void init(const Dictionary *dictionary, const int *prevWord, int prevWordLength);
49    // TODO: Remove and merge into init
50    void setupForGetSuggestions(const ProximityInfo *pInfo, const int *inputCodePoints,
51            const int inputSize, const int *const inputXs, const int *const inputYs,
52            const int *const times, const int *const pointerIds, const float maxSpatialDistance,
53            const int maxPointerCount);
54    void resetCache(const int nextActiveCacheSize, const int maxWords);
55
56    // TODO: Remove
57    const uint8_t *getOffsetDict() const;
58    int getDictFlags() const;
59
60    //--------------------
61    // getters and setters
62    //--------------------
63    const ProximityInfo *getProximityInfo() const { return mProximityInfo; }
64    int getPrevWordPos() const { return mPrevWordPos; }
65    // TODO: REMOVE
66    void setPrevWordPos(int pos) { mPrevWordPos = pos; }
67    // TODO: Use proper parameter when changed
68    int getDicRootPos() const { return 0; }
69    DicNodesCache *getDicTraverseCache() { return &mDicNodesCache; }
70    MultiBigramMap *getMultiBigramMap() { return &mMultiBigramMap; }
71    const ProximityInfoState *getProximityInfoState(int id) const {
72        return &mProximityInfoStates[id];
73    }
74    int getInputSize() const { return mInputSize; }
75    void setPartiallyCommited() { mPartiallyCommited = true; }
76    bool isPartiallyCommited() const { return mPartiallyCommited; }
77
78    bool isOnlyOnePointerUsed(int *pointerId) const {
79        // Not in the dictionary word
80        int usedPointerCount = 0;
81        int usedPointerId = 0;
82        for (int i = 0; i < mMaxPointerCount; ++i) {
83            if (mProximityInfoStates[i].isUsed()) {
84                ++usedPointerCount;
85                usedPointerId = i;
86            }
87        }
88        if (usedPointerCount != 1) {
89            return false;
90        }
91        *pointerId = usedPointerId;
92        return true;
93    }
94
95    void getSearchKeys(const DicNode *node, std::vector<int> *const outputSearchKeyVector) const {
96        for (int i = 0; i < MAX_POINTER_COUNT_G; ++i) {
97            if (!mProximityInfoStates[i].isUsed()) {
98                continue;
99            }
100            const int pointerId = node->getInputIndex(i);
101            const std::vector<int> *const searchKeyVector =
102                    mProximityInfoStates[i].getSearchKeyVector(pointerId);
103            outputSearchKeyVector->insert(outputSearchKeyVector->end(), searchKeyVector->begin(),
104                    searchKeyVector->end());
105        }
106    }
107
108    ProximityType getProximityTypeG(const DicNode *const node, const int childCodePoint) const {
109        ProximityType proximityType = UNRELATED_CHAR;
110        for (int i = 0; i < MAX_POINTER_COUNT_G; ++i) {
111            if (!mProximityInfoStates[i].isUsed()) {
112                continue;
113            }
114            const int pointerId = node->getInputIndex(i);
115            proximityType = mProximityInfoStates[i].getProximityTypeG(pointerId, childCodePoint);
116            ASSERT(proximityType == UNRELATED_CHAR || proximityType == MATCH_CHAR);
117            // TODO: Make this more generic
118            // Currently we assume there are only two types here -- UNRELATED_CHAR
119            // and MATCH_CHAR
120            if (proximityType != UNRELATED_CHAR) {
121                return proximityType;
122            }
123        }
124        return proximityType;
125    }
126
127    AK_FORCE_INLINE bool isCacheBorderForTyping(const int inputSize) const {
128        return mDicNodesCache.isCacheBorderForTyping(inputSize);
129    }
130
131    /**
132     * Returns whether or not it is possible to continue suggestion from the previous search.
133     */
134    // TODO: Remove. No need to check once the session is fully implemented.
135    bool isContinuousSuggestionPossible() const {
136        if (!mDicNodesCache.hasCachedDicNodesForContinuousSuggestion()) {
137            return false;
138        }
139        ASSERT(mMaxPointerCount <= MAX_POINTER_COUNT_G);
140        for (int i = 0; i < mMaxPointerCount; ++i) {
141            const ProximityInfoState *const pInfoState = getProximityInfoState(i);
142            // If a proximity info state is not continuous suggestion possible,
143            // do not continue searching.
144            if (pInfoState->isUsed() && !pInfoState->isContinuousSuggestionPossible()) {
145                return false;
146            }
147        }
148        return true;
149    }
150
151    bool isTouchPositionCorrectionEnabled() const {
152        return mProximityInfoStates[0].touchPositionCorrectionEnabled();
153    }
154
155    float getMultiWordCostMultiplier() const {
156        return mMultiWordCostMultiplier;
157    }
158
159 private:
160    DISALLOW_IMPLICIT_CONSTRUCTORS(DicTraverseSession);
161    // threshold to start caching
162    static const int CACHE_START_INPUT_LENGTH_THRESHOLD;
163    void initializeProximityInfoStates(const int *const inputCodePoints, const int *const inputXs,
164            const int *const inputYs, const int *const times, const int *const pointerIds,
165            const int inputSize, const float maxSpatialDistance, const int maxPointerCount);
166
167    int mPrevWordPos;
168    const ProximityInfo *mProximityInfo;
169    const Dictionary *mDictionary;
170
171    DicNodesCache mDicNodesCache;
172    // Temporary cache for bigram frequencies
173    MultiBigramMap mMultiBigramMap;
174    ProximityInfoState mProximityInfoStates[MAX_POINTER_COUNT_G];
175
176    int mInputSize;
177    bool mPartiallyCommited;
178    int mMaxPointerCount;
179
180    /////////////////////////////////
181    // Configuration per dictionary
182    float mMultiWordCostMultiplier;
183
184};
185} // namespace latinime
186#endif // LATINIME_DIC_TRAVERSE_SESSION_H
187