package org.geogebra.web.web.gui.inputfield;
import java.util.ArrayList;
import java.util.List;
import org.geogebra.common.gui.inputfield.InputHelper;
import org.geogebra.common.kernel.Macro;
import org.geogebra.common.main.App;
import org.geogebra.common.main.Localization;
import org.geogebra.common.util.AutoCompleteDictionary;
import org.geogebra.common.util.debug.Log;
import org.geogebra.web.html5.gui.inputfield.AutoCompleteW;
import org.geogebra.web.html5.gui.view.autocompletion.CompletionsPopup;
import org.geogebra.web.html5.gui.view.autocompletion.GSuggestBox;
import org.geogebra.web.html5.main.AppW;
import com.google.gwt.user.client.ui.SuggestOracle;
import com.google.gwt.user.client.ui.SuggestOracle.Response;
import com.google.gwt.user.client.ui.SuggestOracle.Suggestion;
public class InputSuggestions implements HasSuggestions {
protected AutoCompleteDictionary dict;
private ScrollableSuggestionDisplay sug;
public static final int querylimit = 5000;
private List<String> completions;
StringBuilder curWord;
protected CompletionsPopup popup;
private App app;
private AutoCompleteW component;
public InputSuggestions(AppW app, AutoCompleteW component) {
this.app = app;
this.component = component;
curWord = new StringBuilder();
popup = new CompletionsPopup();
popup.addTextField(component);
sug = new ScrollableSuggestionDisplay(this, app.getPanel());
}
protected SuggestOracle.Callback popupCallback = new SuggestOracle.Callback() {
@Override
public void onSuggestionsReady(SuggestOracle.Request req,
SuggestOracle.Response res) {
updateSuggestions(res);
}
};
protected GSuggestBox.SuggestionCallback sugCallback = new GSuggestBox.SuggestionCallback() {
@Override
public void onSuggestionSelected(Suggestion s) {
String sugg = s.getReplacementString();
autocomplete(sugg, true);
}
};
public void updateCurrentWord(boolean searchRight) {
// TODO
curWord = new StringBuilder(component.getCommand());
// int next = InputHelper.updateCurrentWord(searchRight, this.curWord,
// component.getText(), getCaretPosition(), false);
// if (next > -1) {
// this.curWordStart = next;
// }
}
public int getCaretPosition() {
return 0;
}
public void autocomplete(String sugg, boolean replace) {
component.insertString(sugg);
sug.hideSuggestions();
}
public boolean popupSuggestions() {
// sub, or query is the same as the current word,
// so moved from method parameter to automatism
// updateCurrentWord(true);// although true would be nicer here
updateCurrentWord(false);// compatibility should be preserved
if (curWord != null && curWord.length() > 0
&& !"sqrt".equals(curWord.toString())) {
// for length check we also need flattenKorean
if (!InputHelper.needsAutocomplete(this.curWord, app.getKernel())) {
// if there is only one letter typed,
// for any reason, this method should
// hide the suggestions instead!
hideSuggestions();
} else {
Log.debug("requestingSug" + curWord);
popup.requestSuggestions(
new SuggestOracle.Request(this.curWord.toString(),
querylimit), popupCallback);
}
} else {
hideSuggestions();
}
return true;
}
public boolean hideSuggestions() {
if (sug.isSuggestionListShowing()) {
sug.hideSuggestions();
}
return true;
}
protected void updateSuggestions(Response res) {
sug.updateHeight();
component.updatePosition(sug);
sug.accessShowSuggestions(res, popup, sugCallback);
}
@Override
public double getMaxSuggestionsHeight() {
double ret = (app.getHeight() / 2);
if (component != null) {
ret = Math.max(29, Math.min(ret, app.getHeight()
+ ((AppW) app).getAbsTop() - component.getAbsoluteTop()
- component.toWidget().getOffsetHeight()
- ((AppW) app).getAppletFrame().getKeyboardHeight()));
}
return ret;
}
public List<String> resetCompletions() {
updateCurrentWord(false);
completions = null;
// if (isEqualsRequired && !text.startsWith("="))
// return null;
boolean korean = false;
if (app.getLocalization() != null) {
korean = "ko".equals(app.getLocalization().getLanguage());
}
// start autocompletion only for words with at least two characters
if (!InputHelper.needsAutocomplete(curWord, app.getKernel())) {
completions = null;
return null;
}
String cmdPrefix = curWord.toString();
if (korean) {
completions = getDictionary().getCompletionsKorean(cmdPrefix);
} else {
completions = getDictionary().getCompletions(cmdPrefix);
}
Log.debug(cmdPrefix + ":"
+ (completions == null ? "-1" : completions.size()));
List<String> commandCompletions = getSyntaxes(completions);
// Start with the built-in function completions
completions = app.getParserFunctions().getCompletions(cmdPrefix);
// Then add the command completions
if (completions.isEmpty()) {
completions = commandCompletions;
} else if (commandCompletions != null) {
completions.addAll(commandCompletions);
}
return completions;
}
/*
* Take a list of commands and return all possible syntaxes for these
* commands
*/
private List<String> getSyntaxes(List<String> commands) {
if (commands == null) {
return null;
}
ArrayList<String> syntaxes = new ArrayList<String>();
for (String cmd : commands) {
String cmdInt = app.getInternalCommand(cmd);
Localization loc = app.getLocalization();
String syntaxString;
if (component.isForCAS()) {
syntaxString = app.getLocalization()
.getCommandSyntaxCAS(cmdInt);
} else {
syntaxString = app.getExam() == null
? loc.getCommandSyntax(cmdInt)
: app.getExam().getSyntax(cmdInt, loc,
app.getSettings());
}
if (syntaxString.endsWith(component.isForCAS()
? Localization.syntaxCAS : Localization.syntaxStr)) {
// command not found, check for macros
Macro macro = component.isForCAS() ? null
: app.getKernel().getMacro(cmd);
if (macro != null) {
syntaxes.add(macro.toString());
} else {
// syntaxes.add(cmdInt + "[]");
Log.debug("Can't find syntax for: " + cmd);
}
continue;
}
for (String syntax : syntaxString.split("\\n")) {
syntaxes.add(syntax);
}
}
return syntaxes;
}
public AutoCompleteDictionary getDictionary() {
if (this.dict == null) {
this.dict = component.isForCAS() ? app.getCommandDictionaryCAS()
: app.getCommandDictionary();
}
return dict;
}
public List<String> getCompletions() {
return completions;
}
public void setFocus() {
sug.setFocus(true);
}
public boolean isSuggesting() {
return sug.isSuggestionListShowing();
}
public boolean needsEnterForSuggestion() {
if (sug.isSuggestionListShowing()) {
sugCallback.onSuggestionSelected(sug.accessCurrentSelection());
return true;
}
return false;
}
public void onKeyDown() {
sug.moveSelectionDown();
}
public void onKeyUp() {
sug.moveSelectionUp();
}
}