package yuku.alkitab.base.cp;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.content.pm.ProviderInfo;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.util.Log;
import yuku.alkitab.base.S;
import yuku.alkitab.base.U;
import yuku.alkitab.base.config.AppConfig;
import yuku.alkitab.base.model.MVersionDb;
import yuku.alkitab.base.util.LidToAri;
import yuku.alkitab.model.Book;
import yuku.alkitab.model.SingleChapterVerses;
import yuku.alkitab.util.Ari;
import yuku.alkitab.util.IntArrayList;
import yuku.alkitabintegration.provider.VerseProvider;
import java.util.Arrays;
import java.util.Locale;
public class Provider extends ContentProvider {
public static final String TAG = Provider.class.getSimpleName();
private static final int PATHID_bible_verses_single_by_lid = 1;
private static final int PATHID_bible_verses_single_by_ari = 2;
private static final int PATHID_bible_verses_range_by_lid = 3;
private static final int PATHID_bible_verses_range_by_ari = 4;
private static final int PATHID_bible_versions = 5;
private static UriMatcher uriMatcher;
@Override
public void attachInfo(final Context context, final ProviderInfo info) {
super.attachInfo(context, info);
final String authority = info.authority;
if (uriMatcher == null) {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(authority, VerseProvider.PATH_bible_verses_single_by_lid + "#", PATHID_bible_verses_single_by_lid);
uriMatcher.addURI(authority, VerseProvider.PATH_bible_verses_single_by_ari + "#", PATHID_bible_verses_single_by_ari);
uriMatcher.addURI(authority, VerseProvider.PATH_bible_verses_range_by_lid + "*", PATHID_bible_verses_range_by_lid);
uriMatcher.addURI(authority, VerseProvider.PATH_bible_verses_range_by_ari + "*", PATHID_bible_verses_range_by_ari);
uriMatcher.addURI(authority, "bible/versions", PATHID_bible_versions);
}
}
@Override public boolean onCreate() {
Log.d(TAG, "@@onCreate");
yuku.afw.App.initWithAppContext(getContext().getApplicationContext());
yuku.alkitab.base.App.staticInit();
return true;
}
@Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
Log.d(TAG, "@@query uri=" + uri + " projection=" + Arrays.toString(projection) + " selection=" + selection + " args=" + Arrays.toString(selectionArgs) + " sortOrder=" + sortOrder);
int uriMatch = uriMatcher.match(uri);
Log.d(TAG, "uriMatch=" + uriMatch);
String formatting_s = uri.getQueryParameter("formatting");
boolean formatting = parseBoolean(formatting_s);
Cursor res;
switch (uriMatch) {
case PATHID_bible_verses_single_by_lid: {
res = getCursorForSingleVerseLid(Ari.parseInt(uri.getLastPathSegment(), Integer.MIN_VALUE), formatting);
} break;
case PATHID_bible_verses_single_by_ari: {
res = getCursorForSingleVerseAri(Ari.parseInt(uri.getLastPathSegment(), Integer.MIN_VALUE), formatting);
} break;
case PATHID_bible_verses_range_by_lid: {
String range = uri.getLastPathSegment();
IntArrayList lids = decodeLidRange(range);
res = getCursorForRangeVerseLid(lids, formatting);
} break;
case PATHID_bible_verses_range_by_ari: {
String range = uri.getLastPathSegment();
IntArrayList aris = decodeAriRange(range);
res = getCursorForRangeVerseAri(aris, formatting);
} break;
case PATHID_bible_versions: {
res = getCursorForBibleVersions();
} break;
default: {
res = null;
} break;
}
Log.d(TAG, "returning " + (res == null? "null": "cursor with " + res.getCount() + " rows"));
return res;
}
/**
* @return [start, end, start, end, ...]
*/
private IntArrayList decodeLidRange(String range) {
IntArrayList res = new IntArrayList();
String[] splits = range.split(",");
for (String split: splits) {
int start, end;
if (split.indexOf('-') != -1) {
String[] startEnd = split.split("-", 2);
start = Ari.parseInt(startEnd[0], Integer.MIN_VALUE);
end = Ari.parseInt(startEnd[1], Integer.MIN_VALUE);
} else {
start = end = Ari.parseInt(split, Integer.MIN_VALUE);
}
if (start != Integer.MIN_VALUE && end != Integer.MIN_VALUE) {
res.add(start);
res.add(end);
}
}
return res;
}
/**
* Also supports verse 0 for the whole chapter (0xbbcc00)
*
* @return [start, end, start, end, ...]
*/
private IntArrayList decodeAriRange(String range) {
IntArrayList res = new IntArrayList();
String[] splits = range.split(",");
for (String split: splits) {
int start, end;
if (split.indexOf('-') != -1) {
String[] startEnd = split.split("-", 2);
start = Ari.parseInt(startEnd[0], Integer.MIN_VALUE);
end = Ari.parseInt(startEnd[1], Integer.MIN_VALUE);
} else {
start = end = Ari.parseInt(split, Integer.MIN_VALUE);
}
if (start != Integer.MIN_VALUE && end != Integer.MIN_VALUE) {
start &= 0xffffff;
end &= 0xffffff;
if (start == end && Ari.toVerse(start) == 0) {
// case: 0xXXYY00 - 0xXXYY00 (whole single chapter)
res.add(start | 0x01);
res.add(start | 0xff);
} else if (end >= start) {
if (Ari.toVerse(start) == 0) {
start = start | 0x01;
}
if (Ari.toVerse(end) == 0) {
end = end | 0xff;
}
res.add(start);
res.add(end);
}
}
}
return res;
}
private Cursor getCursorForSingleVerseLid(int lid, boolean formatting) {
int ari = LidToAri.lidToAri(lid);
return getCursorForSingleVerseAri(ari, formatting);
}
private Cursor getCursorForSingleVerseAri(int ari, boolean formatting) {
MatrixCursor res = new MatrixCursor(new String[] {"_id", VerseProvider.COLUMN_ari, VerseProvider.COLUMN_bookName, VerseProvider.COLUMN_text});
Log.d(TAG, "getting ari 0x" + Integer.toHexString(ari));
if (ari != Integer.MIN_VALUE && ari != 0) {
Book book = S.activeVersion.getBook(Ari.toBook(ari));
if (book != null) {
String text = S.activeVersion.loadVerseText(ari);
if (text != null) {
if (!formatting) {
text = U.removeSpecialCodes(text);
}
res.addRow(new Object[]{1, ari, book.shortName, text});
}
}
}
return res;
}
private Cursor getCursorForRangeVerseLid(IntArrayList lids, boolean formatting) {
IntArrayList aris = new IntArrayList(lids.size());
for (int i = 0, len = lids.size(); i < len; i+=2) {
int lid_start = lids.get(i);
int lid_end = lids.get(i + 1);
int ari_start = LidToAri.lidToAri(lid_start);
int ari_end = LidToAri.lidToAri(lid_end);
aris.add(ari_start);
aris.add(ari_end);
}
return getCursorForRangeVerseAri(aris, formatting);
}
private Cursor getCursorForRangeVerseAri(IntArrayList ariRanges, boolean formatting) {
MatrixCursor res = new MatrixCursor(new String[] {"_id", VerseProvider.COLUMN_ari, VerseProvider.COLUMN_bookName, VerseProvider.COLUMN_text});
int c = 0;
for (int i = 0, len = ariRanges.size(); i < len; i+=2) {
int ari_start = ariRanges.get(i);
int ari_end = ariRanges.get(i + 1);
if (ari_start == 0 || ari_end == 0) {
continue;
}
if (ari_start == ari_end) {
// case: single verse
//noinspection UnnecessaryLocalVariable
int ari = ari_start;
Book book = S.activeVersion.getBook(Ari.toBook(ari));
if (book != null) {
String text = S.activeVersion.loadVerseText(ari);
if (!formatting) {
text = U.removeSpecialCodes(text);
}
res.addRow(new Object[] {++c, ari, book.shortName, text});
}
} else {
int ari_start_bc = Ari.toBookChapter(ari_start);
int ari_end_bc = Ari.toBookChapter(ari_end);
if (ari_start_bc == ari_end_bc) {
// case: multiple verses in the same chapter
Book book = S.activeVersion.getBook(Ari.toBook(ari_start));
if (book != null) {
c += resultForOneChapter(res, book, c, ari_start_bc, Ari.toVerse(ari_start), Ari.toVerse(ari_end), formatting);
}
} else {
// case: multiple verses in different chapters
for (int ari_bc = ari_start_bc; ari_bc <= ari_end_bc; ari_bc += 0x0100) {
Book book = S.activeVersion.getBook(Ari.toBook(ari_bc));
int chapter_1 = Ari.toChapter(ari_bc);
if (book == null || chapter_1 <= 0 || chapter_1 > book.chapter_count) {
continue;
}
if (ari_bc == ari_start_bc) { // we're at the first requested chapter
c += resultForOneChapter(res, book, c, ari_bc, Ari.toVerse(ari_start), 0xff, formatting);
} else if (ari_bc == ari_end_bc) { // we're at the last requested chapter
c += resultForOneChapter(res, book, c, ari_bc, 0x01, Ari.toVerse(ari_end), formatting);
} else { // we're at the middle, request all verses!
c += resultForOneChapter(res, book, c, ari_bc, 0x01, 0xff, formatting);
}
}
}
}
}
return res;
}
/**
* @return number of verses put into the cursor
*/
private int resultForOneChapter(MatrixCursor cursor, Book book, int last_c, int ari_bc, int v_1_start, int v_1_end, boolean formatting) {
final SingleChapterVerses verses = S.activeVersion.loadChapterText(book, Ari.toChapter(ari_bc));
if (verses == null) {
return 0;
}
int count = 0;
for (int v_1 = v_1_start; v_1 <= v_1_end; v_1++) {
final int v_0 = v_1 - 1;
if (v_0 < verses.getVerseCount()) {
int ari = ari_bc | v_1;
String text = verses.getVerse(v_0);
if (!formatting) {
text = U.removeSpecialCodes(text);
}
count++;
cursor.addRow(new Object[] {last_c + count, ari, book.shortName, text});
} else {
// we're done with this chapter, no need to loop again
break;
}
}
return count;
}
private Cursor getCursorForBibleVersions() {
MatrixCursor res = new MatrixCursor(new String[] {"_id", "type", "available", "shortName", "longName", "description"});
final AppConfig ac = AppConfig.get();
long _id = 0;
{ // internal
res.addRow(new Object[] {++_id, "internal", 1, ac.internalShortName, ac.internalLongName, ac.internalLongName});
}
{ // database versions
for (MVersionDb mvDb: S.getDb().listAllVersions()) {
res.addRow(new Object[]{++_id, "yes", mvDb.hasDataFile() ? 1 : 0, mvDb.shortName != null ? mvDb.shortName : mvDb.longName, mvDb.longName, mvDb.description});
}
}
return res;
}
private static boolean parseBoolean(String s) {
if (s == null) return false;
if (s.equals("0")) return false;
if (s.equals("1")) return true;
if (s.equals("false")) return false;
if (s.equals("true")) return true;
s = s.toLowerCase(Locale.US);
if (s.equals("false")) return false;
if (s.equals("true")) return true;
if (s.equals("no")) return false;
if (s.equals("yes")) return true;
int n = Ari.parseInt(s, Integer.MIN_VALUE);
if (n == 0) return false;
if (n != Integer.MIN_VALUE) return true;
return false;
}
@Override public String getType(Uri uri) {
return null;
}
@Override public Uri insert(Uri uri, ContentValues values) {
throw new UnsupportedOperationException();
}
@Override public int delete(Uri uri, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException();
}
@Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException();
}
}