1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5package org.chromium.chrome.browser.infobar;
6
7import java.util.Arrays;
8import java.util.Collections;
9import java.util.List;
10
11
12/**
13 * A class that keeps the state of the different translation options and
14 * languages.
15 */
16public class TranslateOptions {
17
18    // This would be an enum but they are not good for mobile.
19    // The checkBoundaries method below needs to be updated if new options are added.
20    private static final int NEVER_LANGUAGE = 0;
21    private static final int NEVER_DOMAIN = 1;
22    private static final int ALWAYS_LANGUAGE = 2;
23
24    private final String[] mAllLanguages;
25
26    // Will reflect the state before the object was ever modified
27    private final boolean[] mOriginalOptions;
28    private final int mOriginalSourceLanguageIndex;
29    private final int mOriginalTargetLanguageIndex;
30
31    private final boolean[] mOptions;
32    private int mSourceLanguageIndex;
33    private int mTargetLanguageIndex;
34    private final boolean mTriggeredFromMenu;
35
36    private TranslateOptions(int sourceLanguageCode, int targetLanguageCode, String[] allLanguages,
37            boolean neverLanguage, boolean neverDomain, boolean alwaysLanguage,
38            boolean triggeredFromMenu, boolean[] originalOptions) {
39        mAllLanguages = allLanguages;
40        mSourceLanguageIndex = sourceLanguageCode;
41        mTargetLanguageIndex = targetLanguageCode;
42        mTriggeredFromMenu = triggeredFromMenu;
43
44        mOptions = new boolean[3];
45        mOptions[NEVER_LANGUAGE] = neverLanguage;
46        mOptions[NEVER_DOMAIN] = neverDomain;
47        mOptions[ALWAYS_LANGUAGE] = alwaysLanguage;
48
49
50        if (originalOptions == null) {
51            mOriginalOptions = mOptions.clone();
52        } else {
53            mOriginalOptions = originalOptions.clone();
54        }
55
56        mOriginalSourceLanguageIndex = mSourceLanguageIndex;
57        mOriginalTargetLanguageIndex = mTargetLanguageIndex;
58    }
59
60    public TranslateOptions(int sourceLanguageCode, int targetLanguageCode, String[] allLanguages,
61           boolean alwaysTranslate, boolean triggeredFromMenu) {
62        this(sourceLanguageCode, targetLanguageCode, allLanguages, false, false, alwaysTranslate,
63                triggeredFromMenu, null);
64    }
65
66    /**
67     * Copy constructor
68     */
69    public TranslateOptions(TranslateOptions other) {
70        this(other.mSourceLanguageIndex, other.mTargetLanguageIndex, other.mAllLanguages,
71                other.mOptions[NEVER_LANGUAGE], other.mOptions[NEVER_DOMAIN],
72                other.mOptions[ALWAYS_LANGUAGE], other.mTriggeredFromMenu,
73                other.mOriginalOptions);
74    }
75
76    public String sourceLanguage() {
77        if (checkLanguageBoundaries(mSourceLanguageIndex))
78            return mAllLanguages[mSourceLanguageIndex];
79        return "";
80    }
81
82    public String targetLanguage() {
83        if (checkLanguageBoundaries(mTargetLanguageIndex))
84            return mAllLanguages[mTargetLanguageIndex];
85        return "";
86    }
87
88    public int sourceLanguageIndex() {
89        return checkLanguageBoundaries(mSourceLanguageIndex) ? mSourceLanguageIndex : 0;
90    }
91
92    public int targetLanguageIndex() {
93        return checkLanguageBoundaries(mTargetLanguageIndex) ? mTargetLanguageIndex : 0;
94    }
95
96    public boolean triggeredFromMenu() {
97        return mTriggeredFromMenu;
98    }
99
100    public boolean optionsChanged() {
101        return (mSourceLanguageIndex != mOriginalSourceLanguageIndex) ||
102                (mTargetLanguageIndex != mOriginalTargetLanguageIndex) ||
103                (mOptions[NEVER_LANGUAGE] != mOriginalOptions[NEVER_LANGUAGE]) ||
104                (mOptions[NEVER_DOMAIN] != mOriginalOptions[NEVER_DOMAIN]) ||
105                (mOptions[ALWAYS_LANGUAGE] != mOriginalOptions[ALWAYS_LANGUAGE]);
106    }
107
108
109    public List<String> allLanguages() {
110        return Collections.unmodifiableList(Arrays.asList(mAllLanguages));
111    }
112
113    public boolean neverTranslateLanguageState() {
114        return mOptions[NEVER_LANGUAGE];
115    }
116
117    public boolean alwaysTranslateLanguageState() {
118        return mOptions[ALWAYS_LANGUAGE];
119    }
120
121    public boolean neverTranslateDomainState() {
122        return mOptions[NEVER_DOMAIN];
123    }
124
125    public boolean setSourceLanguage(int languageIndex) {
126        boolean canSet = canSetLanguage(languageIndex, mTargetLanguageIndex);
127        if (canSet) {
128            mSourceLanguageIndex = languageIndex;
129        }
130        return canSet;
131    }
132
133    public boolean setTargetLanguage(int languageIndex) {
134        boolean canSet = canSetLanguage(mSourceLanguageIndex, languageIndex);
135        if (canSet) {
136            mTargetLanguageIndex = languageIndex;
137        }
138        return canSet;
139    }
140
141    /**
142     * Sets the new state of never translate domain.
143     *
144     * @return true if the toggling was possible
145     */
146    public boolean toggleNeverTranslateDomainState(boolean value) {
147        return toggleState(NEVER_DOMAIN, value);
148    }
149
150    /**
151     * Sets the new state of never translate language.
152     *
153     * @return true if the toggling was possible
154     */
155    public boolean toggleNeverTranslateLanguageState(boolean value) {
156        // Do not toggle if we are activating NeverLanguge but AlwaysTranslate
157        // for a language pair with the same source language is already active.
158        if (mOptions[ALWAYS_LANGUAGE] && value) {
159            return false;
160        }
161        return toggleState(NEVER_LANGUAGE, value);
162    }
163
164    /**
165     * Sets the new state of never translate a language pair.
166     *
167     * @return true if the toggling was possible
168     */
169    public boolean toggleAlwaysTranslateLanguageState(boolean value) {
170        // Do not toggle if we are activating AlwaysLanguge but NeverLanguage is active already.
171        if (mOptions[NEVER_LANGUAGE] && value) {
172            return false;
173        }
174        return toggleState(ALWAYS_LANGUAGE, value);
175    }
176
177    private boolean toggleState(int element, boolean newValue) {
178        if (!checkElementBoundaries(element))
179            return false;
180
181        mOptions[element] = newValue;
182        return true;
183    }
184
185
186    private boolean checkLanguageBoundaries(int index) {
187        return index >= 0 && index < mAllLanguages.length;
188    }
189
190    private boolean canSetLanguage(int sourceIndex, int targetIndex) {
191        if (sourceIndex == targetIndex)
192            return false;
193        return checkLanguageBoundaries(sourceIndex) && checkLanguageBoundaries(targetIndex);
194    }
195
196
197    private static boolean checkElementBoundaries(int element) {
198        return element >= NEVER_LANGUAGE && element <= ALWAYS_LANGUAGE;
199    }
200
201    @Override
202    public String toString() {
203        return new StringBuilder()
204                .append(sourceLanguage())
205                .append(" -> ")
206                .append(targetLanguage())
207                .append(" - ")
208                .append("Never Language:")
209                .append(mOptions[NEVER_LANGUAGE])
210                .append(" Always Language:")
211                .append(mOptions[ALWAYS_LANGUAGE])
212                .append(" Never Domain:")
213                .append(mOptions[NEVER_DOMAIN])
214                .toString();
215    }
216}
217