package com.quran.labs.androidquran.ui.util;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.support.annotation.NonNull;
import android.util.SparseArray;
import android.widget.ImageView;
import com.quran.labs.androidquran.common.AyahBounds;
import com.quran.labs.androidquran.data.SuraAyah;
import com.quran.labs.androidquran.widgets.AyahToolBar;
import com.quran.labs.androidquran.widgets.HighlightingImageView;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import timber.log.Timber;
public class ImageAyahUtils {
private static SuraAyah getAyahFromKey(String key){
String[] parts = key.split(":");
SuraAyah result = null;
if (parts.length == 2){
try {
int sura = Integer.parseInt(parts[0]);
int ayah = Integer.parseInt(parts[1]);
result = new SuraAyah(sura, ayah);
}
catch (Exception e){
// no op
}
}
return result;
}
public static SuraAyah getAyahFromCoordinates(
Map<String, List<AyahBounds>> coords,
HighlightingImageView imageView, float xc, float yc) {
if (coords == null || imageView == null){ return null; }
float[] pageXY = getPageXY(xc, yc, imageView);
if (pageXY == null){ return null; }
float x = pageXY[0];
float y = pageXY[1];
int closestLine = -1;
int closestDelta = -1;
final SparseArray<List<String>> lineAyahs = new SparseArray<>();
final Set<String> keys = coords.keySet();
for (String key : keys){
List<AyahBounds> bounds = coords.get(key);
if (bounds == null){ continue; }
for (AyahBounds b : bounds){
// only one AyahBound will exist for an ayah on a particular line
int line = b.getLine();
List<String> items = lineAyahs.get(line);
if (items == null){
items = new ArrayList<>();
}
items.add(key);
lineAyahs.put(line, items);
final RectF boundsRect = b.getBounds();
if (boundsRect.contains(x, y)) {
return getAyahFromKey(key);
}
int delta = Math.min((int) Math.abs(boundsRect.bottom - y),
(int) Math.abs(boundsRect.top - y));
if (closestDelta == -1 || delta < closestDelta){
closestLine = b.getLine();
closestDelta = delta;
}
}
}
if (closestLine > -1){
int leastDeltaX = -1;
String closestAyah = null;
List<String> ayat = lineAyahs.get(closestLine);
if (ayat != null){
Timber.d("no exact match, %d candidates.", ayat.size());
for (String ayah : ayat){
List<AyahBounds> bounds = coords.get(ayah);
if (bounds == null){ continue; }
for (AyahBounds b : bounds){
if (b.getLine() > closestLine){
// this is the last ayah in ayat list
break;
}
final RectF boundsRect = b.getBounds();
if (b.getLine() == closestLine){
// if x is within the x of this ayah, that's our answer
if (boundsRect.right >= x && boundsRect.left <= x){
return getAyahFromKey(ayah);
}
// otherwise, keep track of the least delta and return it
int delta = Math.min((int) Math.abs(boundsRect.right - x),
(int) Math.abs(boundsRect.left - x));
if (leastDeltaX == -1 || delta < leastDeltaX){
closestAyah = ayah;
leastDeltaX = delta;
}
}
}
}
}
if (closestAyah != null){
Timber.d("fell back to closest ayah of %s", closestAyah);
return getAyahFromKey(closestAyah);
}
}
return null;
}
public static AyahToolBar.AyahToolBarPosition getToolBarPosition(
@NonNull List<AyahBounds> bounds, @NonNull Matrix matrix,
int screenWidth, int screenHeight, int toolBarWidth, int toolBarHeight) {
boolean isToolBarUnderAyah = false;
AyahToolBar.AyahToolBarPosition result = null;
final int size = bounds.size();
RectF chosenRect;
if (size > 0) {
RectF firstRect = new RectF();
AyahBounds chosen = bounds.get(0);
matrix.mapRect(firstRect, chosen.getBounds());
chosenRect = new RectF(firstRect);
float y = firstRect.top - toolBarHeight;
if (y < toolBarHeight) {
// too close to the top, let's move to the bottom
chosen = bounds.get(size - 1);
matrix.mapRect(chosenRect, chosen.getBounds());
y = chosenRect.bottom;
if (y > (screenHeight - toolBarHeight)) {
y = firstRect.bottom;
chosenRect = firstRect;
}
isToolBarUnderAyah = true;
}
final float midpoint = chosenRect.centerX();
float x = midpoint - (toolBarWidth / 2);
if (x < 0 || x + toolBarWidth > screenWidth) {
x = chosenRect.left;
if (x + toolBarWidth > screenWidth) {
x = screenWidth - toolBarWidth;
}
}
result = new AyahToolBar.AyahToolBarPosition();
result.x = x;
result.y = y;
result.pipOffset = midpoint - x;
result.pipPosition = isToolBarUnderAyah ?
AyahToolBar.PipPosition.UP : AyahToolBar.PipPosition.DOWN;
}
return result;
}
private static float[] getPageXY(
float screenX, float screenY, ImageView imageView) {
if (imageView.getDrawable() == null) {
return null;
}
float[] results = null;
Matrix inverse = new Matrix();
if (imageView.getImageMatrix().invert(inverse)) {
results = new float[2];
inverse.mapPoints(results, new float[]{screenX, screenY});
}
return results;
}
public static RectF getYBoundsForHighlight(
Map<String, List<AyahBounds>> coordinateData, int sura, int ayah) {
final List<AyahBounds> ayahBounds = coordinateData.get(sura + ":" + ayah);
if (ayahBounds == null) {
return null;
}
RectF ayahBoundsRect = null;
for (AyahBounds bounds : ayahBounds) {
if (ayahBoundsRect == null) {
ayahBoundsRect = bounds.getBounds();
} else {
ayahBoundsRect.union(bounds.getBounds());
}
}
return ayahBoundsRect;
}
}