package yuku.alkitab.base.fr;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AutoCompleteTextView;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.TextView;
import com.afollestad.materialdialogs.MaterialDialog;
import gnu.trove.map.TIntObjectMap;
import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.set.TIntSet;
import gnu.trove.set.hash.TIntHashSet;
import yuku.afw.V;
import yuku.afw.widget.EasyAdapter;
import yuku.alkitab.base.S;
import yuku.alkitab.base.fr.base.BaseGotoFragment;
import yuku.alkitab.base.util.Jumper;
import yuku.alkitab.base.util.Levenshtein;
import yuku.alkitab.debug.R;
import yuku.alkitab.model.Book;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class GotoDirectFragment extends BaseGotoFragment {
public static final String TAG = GotoDirectFragment.class.getSimpleName();
private static final String EXTRA_verse = "verse";
private static final String EXTRA_chapter = "chapter";
private static final String EXTRA_bookId = "bookId";
TextView lDirectSample;
AutoCompleteTextView tDirectReference;
View bOk;
AutoCompleteAdapter adapter;
int bookId;
int chapter_1;
int verse_1;
GotoFinishListener listener;
static class Candidate {
String title;
int score;
boolean bookOnly;
}
public static Bundle createArgs(int bookId, int chapter_1, int verse_1) {
Bundle args = new Bundle();
args.putInt(EXTRA_bookId, bookId);
args.putInt(EXTRA_chapter, chapter_1);
args.putInt(EXTRA_verse, verse_1);
return args;
}
@Override
public void onAttach(final Context context) {
super.onAttach(context);
this.listener = (GotoFinishListener) context;
}
@Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
bookId = args.getInt(EXTRA_bookId, -1);
chapter_1 = args.getInt(EXTRA_chapter);
verse_1 = args.getInt(EXTRA_verse);
}
}
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View res = inflater.inflate(R.layout.fragment_goto_direct, container, false);
lDirectSample = V.get(res, R.id.lDirectSample);
tDirectReference = V.get(res, R.id.tDirectReference);
tDirectReference.setAdapter(adapter = new AutoCompleteAdapter());
tDirectReference.setOnItemClickListener((parent, view, position, id) -> {
if (!adapter.getItem(position).bookOnly) {
bOk.performClick();
}
});
bOk = V.get(res, R.id.bOk);
bOk.setOnClickListener(bOk_click);
tDirectReference.setOnEditorActionListener((v, actionId, event) -> {
bOk_click.onClick(bOk);
return true;
});
return res;
}
@Override public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final String example = S.activeVersion.reference(bookId, chapter_1, verse_1);
final CharSequence text = getText(R.string.jump_to_prompt);
SpannableStringBuilder sb = new SpannableStringBuilder();
sb.append(text);
final CharSequence text2 = TextUtils.expandTemplate(text, example);
lDirectSample.setText(text2);
}
View.OnClickListener bOk_click = new View.OnClickListener() {
public Pattern nobookPattern;
@Override public void onClick(View v) {
String reference = tDirectReference.getText().toString();
if (reference.trim().length() == 0) {
return; // do nothing
}
// typing chapter or chapter:verse was broken sometime. Let us make a special case to handle this.
if (nobookPattern == null) {
nobookPattern = Pattern.compile("(\\d+)(?:[ :.]+(\\d+))?");
}
final Matcher m = nobookPattern.matcher(reference.trim());
if (m.matches()) {
try {
final String chapter_s = m.group(1);
final int chapter_1 = Integer.parseInt(chapter_s);
final String verse_s = m.group(2);
final int verse_1;
if (verse_s != null) {
verse_1 = Integer.parseInt(verse_s);
} else {
verse_1 = 0;
}
listener.onGotoFinished(GotoFinishListener.GOTO_TAB_direct, bookId, chapter_1, verse_1);
return;
} catch (NumberFormatException ignored) {}
}
final Jumper jumper = new Jumper(reference);
if (! jumper.getParseSucceeded()) {
new MaterialDialog.Builder(getActivity())
.content(getString(R.string.alamat_tidak_sah_alamat, reference))
.positiveText(R.string.ok)
.show();
return;
}
final int bookId = jumper.getBookId(S.activeVersion.getConsecutiveBooks());
final int chapter = jumper.getChapter();
final int verse = jumper.getVerse();
listener.onGotoFinished(GotoFinishListener.GOTO_TAB_direct, bookId, chapter, verse);
}
};
class AutoCompleteAdapter extends EasyAdapter implements Filterable {
final List<Candidate> candidates = new ArrayList<>();
@Override
public View newView(final int position, final ViewGroup parent) {
return getActivity().getLayoutInflater().inflate(R.layout.support_simple_spinner_dropdown_item, parent, false);
}
@Override
public void bindView(final View view, final int position, final ViewGroup parent) {
final TextView tv = (TextView) view;
final Candidate candidate = getItem(position);
tv.setText(candidate.title);
}
@Override
public int getCount() {
return candidates.size();
}
/**
* This may not be removed, or the {@link android.widget.AutoCompleteTextView#setOnItemClickListener(android.widget.AdapterView.OnItemClickListener)} won't work!
*/
@Override
public Candidate getItem(final int position) {
return candidates.get(position);
}
@Override
public Filter getFilter() {
return new Filter() {
final Book[] books = S.activeVersion.getConsecutiveBooks();
final TIntObjectMap<Book> bookIndex = new TIntObjectHashMap<>();
{
for (final Book book : books) {
bookIndex.put(book.bookId, book);
}
}
List<Jumper.BookRef> bookRefs;
@Override
protected FilterResults performFiltering(@Nullable final CharSequence constraint) {
final FilterResults res = new FilterResults();
if (constraint == null) {
res.values = null;
res.count = 0;
return res;
}
final Jumper jumper = new Jumper(constraint.toString());
String bookName = jumper.getUnparsedBook();
final ArrayList<Candidate> candidates = new ArrayList<>();
if (bookName != null) {
bookName = bookName.trim().toLowerCase();
if (bookName.length() >= 1) {
final TIntSet addedBookIds = new TIntHashSet();
for (final Book book : books) {
String title = null;
int score = 0;
final String n = book.shortName.toLowerCase();
if (n.startsWith(bookName)) {
title = book.shortName;
score = 20;
} else if (n.contains(bookName)) {
title = book.shortName;
score = 10;
}
if (score != 0) {
addCandidate(jumper, candidates, title, score, book);
addedBookIds.add(book.bookId);
}
}
// now try the levenstein
if (candidates.size() < 5) {
List<Jumper.BookRef> _bookRefs = this.bookRefs;
if (_bookRefs == null) {
this.bookRefs = _bookRefs = Jumper.createBookCandidates(books);
}
for (final Jumper.BookRef bookRef : _bookRefs) {
if (addedBookIds.contains(bookRef.bookId)) continue;
final int distance = Levenshtein.distance(bookName, bookRef.condensed);
final Book book = bookIndex.get(bookRef.bookId);
addCandidate(jumper, candidates, book.shortName, -distance, book);
addedBookIds.add(bookRef.bookId);
}
}
}
}
Collections.sort(candidates, (lhs, rhs) -> rhs.score - lhs.score);
res.count = candidates.size();
res.values = candidates;
return res;
}
private void addCandidate(final Jumper jumper, final ArrayList<Candidate> values, String title, final int score, final Book book) {
boolean bookOnly = true;
// try to add chapter and verse
final int chapter_1 = jumper.getChapter();
if (chapter_1 != 0) {
bookOnly = false;
title += " " + chapter_1;
final int verse_1 = jumper.getVerse();
if (verse_1 != 0) {
title += ":" + verse_1;
}
// do not add if the chapter is unavailable
if (chapter_1 < 1 || chapter_1 > book.chapter_count) {
return;
} else {
if (verse_1 != 0 && (verse_1 < 1 || verse_1 > book.verse_counts[chapter_1 - 1])) {
return;
}
}
}
final Candidate c = new Candidate();
c.title = title;
c.score = score;
c.bookOnly = bookOnly;
values.add(c);
}
@Override
protected void publishResults(final CharSequence constraint, final FilterResults results) {
candidates.clear();
if (results.values != null) {
//noinspection unchecked
candidates.addAll((List<Candidate>) results.values);
}
notifyDataSetChanged();
}
@Override
public CharSequence convertResultToString(final Object resultValue) {
final Candidate c = (Candidate) resultValue;
if (c.bookOnly) {
return c.title + " "; // for user to start typing the chapter number
}
return c.title;
}
};
}
}
}