package ar.rulosoft.mimanganu.services;
import android.app.Activity;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.os.PowerManager;
import android.preference.PreferenceManager;
import android.util.Log;
import android.widget.Toast;
import java.io.File;
import java.util.ArrayList;
import ar.rulosoft.mimanganu.R;
import ar.rulosoft.mimanganu.componentes.Chapter;
import ar.rulosoft.mimanganu.componentes.Database;
import ar.rulosoft.mimanganu.componentes.Manga;
import ar.rulosoft.mimanganu.servers.ServerBase;
import ar.rulosoft.mimanganu.services.ChapterDownload.DownloadStatus;
import ar.rulosoft.mimanganu.services.SingleDownload.Status;
import ar.rulosoft.mimanganu.utils.NetworkUtilsAndReceiver;
import ar.rulosoft.mimanganu.utils.Util;
import static ar.rulosoft.mimanganu.utils.Paths.generateBasePath;
public class DownloadPoolService extends Service implements StateChangeListener {
public static int SLOTS = 2;
public static DownloadPoolService actual = null;
public static ArrayList<ChapterDownload> chapterDownloads = new ArrayList<>();
public static DownloadsChangesListener mDownloadsChangesListener;
public static StateChangeListener mChapterStateChangeListener;
public static int errors = 0;
private static boolean intentPending = false;
private static DownloadListener downloadListener = null;
private static boolean resetN;
private static boolean resetE;
public int slots = SLOTS;
private int mNotifyID = (int) System.currentTimeMillis();
public static void addChapterDownloadPool(Activity activity, Chapter chapter, boolean reading) throws Exception {
if (activity == null) {
Log.d("DPS", "null");
} else {
if (!chapter.isDownloaded() && NetworkUtilsAndReceiver.isConnected(activity)) {
if (isNewDownload(chapter.getId())) {
ChapterDownload dc = new ChapterDownload(chapter);
if (mDownloadsChangesListener != null) {
mDownloadsChangesListener.onChapterAdded(reading, dc);
}
if (reading) {
chapterDownloads.add(0, dc);
} else {
chapterDownloads.add(dc);
}
} else {
for (int i = 0; i < chapterDownloads.size(); i++) {
ChapterDownload dc = chapterDownloads.get(i);
if (dc.chapter.getId() == chapter.getId()) {
if (dc.status == DownloadStatus.ERROR) {
dc.chapter.deleteImages(activity);
chapterDownloads.remove(dc);
if (mDownloadsChangesListener != null) {
mDownloadsChangesListener.onChapterRemoved(i);
mDownloadsChangesListener.onChapterAdded(reading, dc);
}
dc = null;
ChapterDownload ndc = new ChapterDownload(chapter);
if (reading) {
chapterDownloads.add(0, ndc);
} else {
chapterDownloads.add(ndc);
}
} else {
if (reading) {
chapterDownloads.remove(dc);
if (mDownloadsChangesListener != null) {
mDownloadsChangesListener.onChapterRemoved(i);
mDownloadsChangesListener.onChapterAdded(true, dc);
}
chapterDownloads.add(0, dc);
}
}
break;
}
}
}
initValues(activity);
}
}
}
private static void initValues(Context context) {
if (context != null) {
SharedPreferences pm = PreferenceManager.getDefaultSharedPreferences(context);
int download_threads = Integer.parseInt(pm.getString("download_threads", "2"));
int tolerance = Integer.parseInt(pm.getString("error_tolerancia", "5"));
int retry = Integer.parseInt(pm.getString("reintentos", "4"));
ChapterDownload.MAX_ERRORS = tolerance;
SingleDownload.RETRY = retry;
DownloadPoolService.SLOTS = download_threads;
startService(context);
}
}
public static void startService(Context context) {
if (!intentPending && actual == null) {
intentPending = true;
context.startService(new Intent(context, DownloadPoolService.class));
}
}
public static boolean isNewDownload(int cid) {
boolean result = true;
for (ChapterDownload dc : chapterDownloads) {
if (dc.chapter.getId() == cid) {
if (dc.status == DownloadStatus.DOWNLOADED) {
chapterDownloads.remove(dc);
return true;
}
result = false;
break;
}
}
return result;
}
public static boolean removeDownload(int cid, Context c) {
boolean result = true;
for (int i = 0; i < chapterDownloads.size(); i++) {
if (chapterDownloads.get(i).chapter.getId() == cid) {
if (chapterDownloads.get(i).status.ordinal() != DownloadStatus.DOWNLOADING.ordinal()) {
chapterDownloads.remove(i);
if (mDownloadsChangesListener != null) {
mDownloadsChangesListener.onChapterRemoved(i);
}
} else {
Toast.makeText(c, R.string.quitar_descarga, Toast.LENGTH_LONG).show();
result = false;
}
break;
}
}
return result;
}
public static void attachListener(ChapterDownload.OnErrorListener lector, int cid) {
if (chapterDownloads != null && !chapterDownloads.isEmpty()) {
ChapterDownload cd;
for (int j = 0; j < chapterDownloads.size(); j++) {
cd = chapterDownloads.get(j);
if (cd.chapter.getId() == cid) {
cd.setErrorListener(lector);
break;
}
}
}
}
public static void detachListener(int cid) {
attachListener(null, cid);
}
public static void setDownloadListener(DownloadListener nDownloadListener) {
downloadListener = nDownloadListener;
}
public static void forceStop(int mangaId) {
for (ChapterDownload cd : chapterDownloads) {
if (cd.getChapter().getMangaID() == mangaId) {
cd.status = DownloadStatus.ERROR;
}
}
}
public static void pauseDownload() {
if (mDownloadsChangesListener != null)
for (int i = 0; i < chapterDownloads.size(); i++) {
ChapterDownload cd = chapterDownloads.get(i);
if (cd.status != DownloadStatus.ERROR && cd.status != DownloadStatus.DOWNLOADED) {
cd.status = DownloadStatus.PAUSED;
mDownloadsChangesListener.onStatusChanged(i, cd);
}
}
else {
for (int i = 0; i < chapterDownloads.size(); i++) {
ChapterDownload cd = chapterDownloads.get(i);
if (cd.status != DownloadStatus.ERROR && cd.status != DownloadStatus.DOWNLOADED) {
cd.status = DownloadStatus.PAUSED;
}
}
}
}
public static void retryError(Context context) {
resetE = true;
if (mDownloadsChangesListener != null) {
for (int i = 0; i < chapterDownloads.size(); i++) {
ChapterDownload cd = chapterDownloads.get(i);
if (cd.status == DownloadStatus.ERROR) {
chapterDownloads.set(i, new ChapterDownload(chapterDownloads.get(i).chapter));
mDownloadsChangesListener.onStatusChanged(i, chapterDownloads.get(i));
}
}
} else {
for (int i = 0; i < chapterDownloads.size(); i++) {
ChapterDownload cd = chapterDownloads.get(i);
if (cd.status == DownloadStatus.ERROR) {
chapterDownloads.set(i, new ChapterDownload(chapterDownloads.get(i).chapter));
}
}
}
startService(context);
}
public static void retryError(Context context, Chapter cid, ChapterDownload.OnErrorListener errorListener) {
resetE = true;
for (int i = 0; i < chapterDownloads.size(); i++) {
ChapterDownload cd = chapterDownloads.get(i);
if (cd.status == DownloadStatus.ERROR && cd.getChapter().getId() == cid.getId()) {
ChapterDownload ncd = new ChapterDownload(cid);
ncd.setErrorListener(errorListener);
chapterDownloads.set(i, ncd);
}
}
startService(context);
}
public static void resumeDownloads(Context context) {
if (mDownloadsChangesListener != null) {
for (int i = 0; i < chapterDownloads.size(); i++) {
if (chapterDownloads.get(i).status == DownloadStatus.PAUSED) {
chapterDownloads.get(i).status = DownloadStatus.QUEUED;
mDownloadsChangesListener.onStatusChanged(i, chapterDownloads.get(i));
}
}
} else {
for (int i = 0; i < chapterDownloads.size(); i++) {
if (chapterDownloads.get(i).status == DownloadStatus.PAUSED) {
chapterDownloads.get(i).status = DownloadStatus.QUEUED;
}
}
}
startService(context);
}
public static void removeDownloaded() {
resetN = true;
ArrayList<ChapterDownload> toRemove = new ArrayList<>();
for (int i = 0; i < chapterDownloads.size(); i++) {
if (chapterDownloads.get(i).status == DownloadStatus.DOWNLOADED) {
toRemove.add(chapterDownloads.get(i));
}
}
chapterDownloads.removeAll(toRemove);
if (mDownloadsChangesListener != null) {
mDownloadsChangesListener.onChaptersRemoved(toRemove);
}
}
public static void removeAll() {
resetN = true;
resetE = true;
ArrayList<ChapterDownload> toRemove = new ArrayList<>();
for (int i = 0; i < chapterDownloads.size(); i++) {
if (chapterDownloads.get(i).status != DownloadStatus.DOWNLOADING) {
toRemove.add(chapterDownloads.get(i));
}
}
chapterDownloads.removeAll(toRemove);
if (mDownloadsChangesListener != null) {
mDownloadsChangesListener.onChaptersRemoved(toRemove);
}
}
public static void setDownloadsChangesListener(DownloadsChangesListener mDownloadsChangesListener) {
DownloadPoolService.mDownloadsChangesListener = mDownloadsChangesListener;
}
public static void setStateChangeListener(StateChangeListener mChapterStateChangeListener) {
DownloadPoolService.mChapterStateChangeListener = mChapterStateChangeListener;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
@Override
public void onCreate() {
super.onCreate();
actual = this;
intentPending = false;
new Thread(new Runnable() {
@Override
public void run() {
initPool();
}
}).start();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onChange(SingleDownload singleDownload) {
if (singleDownload.status.ordinal() > Status.POSTPONED.ordinal()) {
slots++;
}
if (downloadListener != null) {
downloadListener.onImageDownloaded(singleDownload.cid, singleDownload.index);
}
if (mDownloadsChangesListener != null) {
mDownloadsChangesListener.onStatusChanged(chapterDownloads.indexOf(singleDownload.cd), singleDownload.cd);
}
}
@Override
public void onStatusChanged(ChapterDownload chapterDownload) {
if (mChapterStateChangeListener != null) {
mChapterStateChangeListener.onStatusChanged(chapterDownload);
}
}
private void initPool() {
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPS_wakelock");
try {
wakeLock.acquire();
} catch (Exception e) {
e.printStackTrace();
}
Util.getInstance().createNotificationWithProgressbar(getApplicationContext(), mNotifyID, getResources().getString(R.string.downloading), "");
Manga manga = null;
ServerBase s = null;
String path = "";
int lcId = -1;
int n = -1;
errors = 0;
while (hasDownloadsPending()) {
if (slots > 0) {
slots--;
ChapterDownload dc = null;
int sig = 1;
int idx = 0;
while (idx < chapterDownloads.size()) {
ChapterDownload d = chapterDownloads.get(idx);
idx++;
// start notification code
if (n > chapterDownloads.size())
n = idx;
if (n < idx)
n = idx;
if (resetN) {
n = 0;
resetN = false;
}
if (resetE) {
errors = 0;
resetE = false;
}
// end notification code
if (d.chapter.getPages() == 0) {
if (d.status != DownloadStatus.ERROR && d.status != DownloadStatus.PAUSED)
try {
ServerBase server;
Manga m = Database.getManga(getApplicationContext(), d.chapter.getMangaID());
server = ServerBase.getServer(m.getServerId(), getApplicationContext());
server.chapterInit(d.chapter);
d.reset();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (d.chapter.getPages() == 0)
d.status = DownloadStatus.ERROR;
}
Database.updateChapter(getApplicationContext(), d.chapter);
}
if (d.getPagesStatusLength() == 0) {
d.reset();
}
if (d.status != DownloadStatus.ERROR && d.status != DownloadStatus.PAUSED) {
sig = d.getNext();
if (sig > -1) {
dc = d;
break;
}
}
}
if (dc != null) {
if (manga == null || manga.getId() != dc.chapter.getMangaID()) {
try {
manga = Database.getManga(actual.getApplicationContext(), dc.chapter.getMangaID());
s = ServerBase.getServer(manga.getServerId(), getApplicationContext());
} catch (Exception e) {
dc.status = DownloadStatus.ERROR;
}
}
if (lcId != dc.chapter.getId()) {
try {
lcId = dc.chapter.getId();
path = generateBasePath(s, manga, dc.chapter, getApplicationContext());
new File(path).mkdirs();
} catch (Exception e) {
dc.status = DownloadStatus.ERROR;
}
}
try {
if (errors < 1)
Util.getInstance().changeNotificationWithProgressbar(dc.getChapter().getPages(), sig, mNotifyID, getResources().getString(R.string.x_of_y_chapters_downloaded, (n - 1), chapterDownloads.size()), getResources().getString(R.string.downloading) + " " + dc.getChapter().getTitle(), true);
else {
Util.getInstance().changeNotificationWithProgressbar(dc.getChapter().getPages(), sig, mNotifyID, getResources().getString(R.string.x_of_y_chapters_downloaded, (n - 1), chapterDownloads.size()), "(" + getResources().getString(R.string.chapter_download_errors) + " " + errors + ")\n" + getResources().getString(R.string.downloading) + " " + dc.getChapter().getTitle(), true);
}
String source_file = s.getImageFrom(dc.chapter, sig);
String save_file = path + "/" + sig + ".jpg";
SingleDownload des;
des = new SingleDownload(source_file, save_file, sig - 1, dc.chapter.getId(), dc, s.needRefererForImages());
des.setChangeListener(dc);
dc.setChangeListener(this);
new Thread(des).start();
} catch (Exception e) {
dc.setErrorIdx(sig - 1);
slots++;
}
} else if (slots == 1) {
break;
} else {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
slots++;
}
} else {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Util.getInstance().cancelNotification(mNotifyID);
actual = null;
stopSelf();
try {
if (wakeLock.isHeld())
wakeLock.release();
} catch (Exception e) {
e.printStackTrace();
}
}
public boolean hasDownloadsPending() {
for (int i = 0; i < chapterDownloads.size(); i++) {
if (chapterDownloads.get(i).status == DownloadStatus.DOWNLOADING || chapterDownloads.get(i).status == DownloadStatus.QUEUED) {
return true;
}
}
return false;
}
}