package com.quran.labs.androidquran.util;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import com.quran.labs.androidquran.R;
import com.quran.labs.androidquran.common.QariItem;
import com.quran.labs.androidquran.data.QuranInfo;
import com.quran.labs.androidquran.data.SuraAyah;
import com.quran.labs.androidquran.service.AudioService;
import com.quran.labs.androidquran.service.util.AudioRequest;
import com.quran.labs.androidquran.service.util.DownloadAudioRequest;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import timber.log.Timber;
import static com.quran.labs.androidquran.data.Constants.PAGES_LAST;
public class AudioUtils {
public static final String AUDIO_EXTENSION = ".mp3";
private static final String DB_EXTENSION = ".db";
private static final String ZIP_EXTENSION = ".zip";
final static class LookAheadAmount {
static final int PAGE = 1;
static final int SURA = 2;
static final int JUZ = 3;
// make sure to update these when a lookup type is added
static final int MIN = 1;
static final int MAX = 3;
}
/**
* Get a list of QariItem representing the qaris to show
*
* This method takes into account qaris that exist both in gapped and gapless, and, in those
* cases, hides the gapped version if it contains no files.
*
* @param context the current context
* @return a list of QariItem representing the qaris to show.
*/
public static List<QariItem> getQariList(@NonNull Context context) {
final Resources resources = context.getResources();
final String[] shuyookh = resources.getStringArray(R.array.quran_readers_name);
final String[] paths = resources.getStringArray(R.array.quran_readers_path);
final String[] urls = resources.getStringArray(R.array.quran_readers_urls);
final String[] databases = resources.getStringArray(R.array.quran_readers_db_name);
final int[] hasGaplessEquivalent =
resources.getIntArray(R.array.quran_readers_have_gapless_equivalents);
List<QariItem> items = new ArrayList<>(shuyookh.length);
for (int i=0; i < shuyookh.length; i++) {
if (hasGaplessEquivalent[i] == 0 || haveAnyFiles(context, paths[i])) {
items.add(new QariItem(i, shuyookh[i], urls[i], paths[i], databases[i]));
}
}
Collections.sort(items, new Comparator<QariItem>() {
@Override
public int compare(QariItem lhs, QariItem rhs) {
boolean lhsGapless = lhs.isGapless();
boolean rhsGapless = rhs.isGapless();
if (lhsGapless != rhsGapless) {
return lhsGapless ? -1 : 1;
}
return lhs.getName().compareTo(rhs.getName());
}
});
return items;
}
public static String getQariUrl(@NonNull QariItem item) {
String url = item.getUrl();
if (item.isGapless()) {
url += "%03d" + AudioUtils.AUDIO_EXTENSION;
} else {
url += "%03d%03d" + AudioUtils.AUDIO_EXTENSION;
}
return url;
}
public static String getLocalQariUrl(@NonNull Context context, @NonNull QariItem item) {
String rootDirectory = QuranFileUtils.getQuranAudioDirectory(context);
return rootDirectory == null ? null : rootDirectory + item.getPath();
}
public static String getQariDatabasePathIfGapless(
@NonNull Context context, @NonNull QariItem item) {
String databaseName = item.getDatabaseName();
if (databaseName != null) {
String path = getLocalQariUrl(context, item);
if (path != null) {
databaseName = path + File.separator + databaseName + DB_EXTENSION;
}
}
return databaseName;
}
public static boolean shouldDownloadGaplessDatabase(DownloadAudioRequest request) {
if (!request.isGapless()) {
return false;
}
String dbPath = request.getGaplessDatabaseFilePath();
if (TextUtils.isEmpty(dbPath)) {
return false;
}
File f = new File(dbPath);
return !f.exists();
}
public static String getGaplessDatabaseUrl(DownloadAudioRequest request) {
if (!request.isGapless()) {
return null;
}
QariItem item = request.getQariItem();
String dbname = item.getDatabaseName() + ZIP_EXTENSION;
return QuranFileUtils.getGaplessDatabaseRootUrl() + "/" + dbname;
}
public static SuraAyah getLastAyahToPlay(SuraAyah startAyah,
int page, int mode, boolean isDualPages) {
if (isDualPages && mode == LookAheadAmount.PAGE && (page % 2 == 1)) {
// if we download page by page and we are currently in tablet mode
// and playing from the right page, get the left page as well.
page++;
}
int pageLastSura = 114;
int pageLastAyah = 6;
// page < 0 - intentional, because nextPageAyah looks up the ayah on the next page
if (page > PAGES_LAST || page < 0) {
return null;
}
if (page < PAGES_LAST) {
int nextPageSura = QuranInfo.safelyGetSuraOnPage(page);
// not using [page-1] as an index because we literally want the next page
int nextPageAyah = QuranInfo.PAGE_AYAH_START[page];
pageLastSura = nextPageSura;
pageLastAyah = nextPageAyah - 1;
if (pageLastAyah < 1) {
pageLastSura--;
if (pageLastSura < 1) {
pageLastSura = 1;
}
pageLastAyah = QuranInfo.getNumAyahs(pageLastSura);
}
}
if (mode == LookAheadAmount.SURA) {
int sura = startAyah.sura;
int lastAyah = QuranInfo.getNumAyahs(sura);
if (lastAyah == -1) {
return null;
}
// if we start playback between two suras, download both suras
if (pageLastSura > sura) {
sura = pageLastSura;
lastAyah = QuranInfo.getNumAyahs(sura);
}
return new SuraAyah(sura, lastAyah);
} else if (mode == LookAheadAmount.JUZ) {
int juz = QuranInfo.getJuzFromPage(page);
if (juz == 30) {
return new SuraAyah(114, 6);
} else if (juz >= 1 && juz < 30) {
int[] endJuz = QuranInfo.QUARTERS[juz * 8];
if (pageLastSura > endJuz[0]) {
// ex between jathiya and a7qaf
endJuz = QuranInfo.QUARTERS[(juz + 1) * 8];
} else if (pageLastSura == endJuz[0] &&
pageLastAyah > endJuz[1]) {
// ex surat al anfal
endJuz = QuranInfo.QUARTERS[(juz + 1) * 8];
}
return new SuraAyah(endJuz[0], endJuz[1]);
}
}
// page mode (fallback also from errors above)
return new SuraAyah(pageLastSura, pageLastAyah);
}
public static boolean shouldDownloadBasmallah(DownloadAudioRequest request) {
if (request.isGapless()) {
return false;
}
String baseDirectory = request.getLocalPath();
if (!TextUtils.isEmpty(baseDirectory)) {
File f = new File(baseDirectory);
if (f.exists()) {
String filename = 1 + File.separator + 1 + AUDIO_EXTENSION;
f = new File(baseDirectory + File.separator + filename);
if (f.exists()) {
Timber.d("already have basmalla...");
return false;
}
} else {
f.mkdirs();
}
}
return doesRequireBasmallah(request);
}
public static boolean haveSuraAyahForQari(String baseDir, int sura, int ayah) {
String filename = baseDir + File.separator + sura +
File.separator + ayah + AUDIO_EXTENSION;
File f = new File(filename);
return f.exists();
}
private static boolean doesRequireBasmallah(AudioRequest request) {
SuraAyah minAyah = request.getMinAyah();
int startSura = minAyah.sura;
int startAyah = minAyah.ayah;
SuraAyah maxAyah = request.getMaxAyah();
int endSura = maxAyah.sura;
int endAyah = maxAyah.ayah;
Timber.d("seeing if need basmalla...");
for (int i = startSura; i <= endSura; i++) {
int lastAyah = QuranInfo.getNumAyahs(i);
if (i == endSura) {
lastAyah = endAyah;
}
int firstAyah = 1;
if (i == startSura) {
firstAyah = startAyah;
}
for (int j = firstAyah; j < lastAyah; j++) {
if (j == 1 && i != 1 && i != 9) {
Timber.d("need basmalla for %d:%d", i, j);
return true;
}
}
}
return false;
}
private static boolean haveAnyFiles(Context context, String path) {
final String basePath = QuranFileUtils.getQuranAudioDirectory(context);
final File file = new File(basePath, path);
return file.isDirectory() && file.list().length > 0;
}
public static boolean haveAllFiles(DownloadAudioRequest request) {
String baseDirectory = request.getLocalPath();
if (TextUtils.isEmpty(baseDirectory)) {
return false;
}
boolean isGapless = request.isGapless();
File f = new File(baseDirectory);
if (!f.exists()) {
f.mkdirs();
return false;
}
SuraAyah minAyah = request.getMinAyah();
int startSura = minAyah.sura;
int startAyah = minAyah.ayah;
SuraAyah maxAyah = request.getMaxAyah();
int endSura = maxAyah.sura;
int endAyah = maxAyah.ayah;
for (int i = startSura; i <= endSura; i++) {
int lastAyah = QuranInfo.getNumAyahs(i);
if (i == endSura) {
lastAyah = endAyah;
}
int firstAyah = 1;
if (i == startSura) {
firstAyah = startAyah;
}
if (isGapless) {
if (i == endSura && endAyah == 0) {
continue;
}
String p = request.getBaseUrl();
String fileName = String.format(Locale.US, p, i);
Timber.d("gapless, checking if we have %s", fileName);
f = new File(fileName);
if (!f.exists()) {
return false;
}
continue;
}
Timber.d("not gapless, checking each ayah...");
for (int j = firstAyah; j <= lastAyah; j++) {
String filename = i + File.separator + j + AUDIO_EXTENSION;
f = new File(baseDirectory + File.separator + filename);
if (!f.exists()) {
return false;
}
}
}
return true;
}
public static Intent getAudioIntent(Context context, String action) {
final Intent intent = new Intent(context, AudioService.class);
intent.setAction(action);
return intent;
}
}