package com.jparkie.aizoban.controllers;
import android.content.ContentValues;
import android.database.Cursor;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.FutureTarget;
import com.bumptech.glide.request.target.Target;
import com.jparkie.aizoban.AizobanApplication;
import com.jparkie.aizoban.controllers.caches.CacheProvider;
import com.jparkie.aizoban.controllers.databases.ApplicationContract;
import com.jparkie.aizoban.controllers.events.DownloadChapterQueryEvent;
import com.jparkie.aizoban.controllers.factories.SourceFactory;
import com.jparkie.aizoban.controllers.networks.MangaService;
import com.jparkie.aizoban.controllers.sources.UpdatePageMarker;
import com.jparkie.aizoban.models.Chapter;
import com.jparkie.aizoban.models.Manga;
import com.jparkie.aizoban.models.downloads.DownloadChapter;
import com.jparkie.aizoban.models.downloads.DownloadPage;
import com.jparkie.aizoban.utils.DiskUtils;
import com.jparkie.aizoban.utils.DownloadUtils;
import com.jparkie.aizoban.utils.wrappers.RequestWrapper;
import com.squareup.okhttp.Response;
import java.io.File;
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import de.greenrobot.event.EventBus;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
public class AizobanManager {
private AizobanManager() {
throw new AssertionError();
}
public static Observable<String> getNameFromPreferenceSource() {
return SourceFactory.constructSourceFromPreferences().getName();
}
public static Observable<String> getBaseUrlFromPreferenceSource() {
return SourceFactory.constructSourceFromPreferences().getBaseUrl();
}
public static Observable<String> getInitialUpdateUrlFromPreferenceSource() {
return SourceFactory.constructSourceFromPreferences().getInitialUpdateUrl();
}
public static Observable<List<String>> getGenresFromPreferenceSource() {
return SourceFactory.constructSourceFromPreferences().getGenres();
}
public static Observable<UpdatePageMarker> pullLatestUpdatesFromNetwork(final UpdatePageMarker newUpdate) {
return SourceFactory.constructSourceFromPreferences().pullLatestUpdatesFromNetwork(newUpdate);
}
public static Observable<Manga> pullMangaFromNetwork(final RequestWrapper request) {
return SourceFactory.constructSourceFromName(request.getSource()).pullMangaFromNetwork(request);
}
public static Observable<List<Chapter>> pullChaptersFromNetwork(final RequestWrapper request) {
return SourceFactory.constructSourceFromName(request.getSource()).pullChaptersFromNetwork(request);
}
public static Observable<String> pullImageUrlsFromNetwork(final RequestWrapper request) {
return AizobanManager.getImageUrlsFromDiskCache(request.getUrl())
.onBackpressureBuffer()
.onErrorResumeNext(new Func1<Throwable, Observable<? extends String>>() {
@Override
public Observable<? extends String> call(Throwable throwable) {
return SourceFactory.constructSourceFromName(request.getSource()).pullImageUrlsFromNetwork(request);
}
});
}
public static Observable<File> downloadChapterFromNetwork(final DownloadChapter downloadChapter) {
final RequestWrapper downloadRequest = new RequestWrapper(downloadChapter.getSource(), downloadChapter.getUrl());
final MangaService mangaService = MangaService.getTemporaryInstance();
final AtomicBoolean isUnsubscribed = new AtomicBoolean(false);
return QueryManager
.queryDownloadPagesOfDownloadChapter(downloadRequest)
.flatMap(new Func1<Cursor, Observable<List<DownloadPage>>>() {
@Override
public Observable<List<DownloadPage>> call(Cursor downloadPagesCursor) {
return Observable.just(QueryManager.toList(downloadPagesCursor, DownloadPage.class));
}
})
.onErrorResumeNext(new Func1<Throwable, Observable<? extends List<DownloadPage>>>() {
@Override
public Observable<? extends List<DownloadPage>> call(Throwable throwable) {
return AizobanManager
.pullImageUrlsFromNetwork(downloadRequest)
.subscribeOn(Schedulers.io())
.toList()
.flatMap(new Func1<List<String>, Observable<List<DownloadPage>>>() {
@Override
public Observable<List<DownloadPage>> call(List<String> imageUrls) {
return QueryManager.addDownloadPagesForDownloadChapter(downloadChapter, imageUrls);
}
});
}
})
.doOnNext(new Action1<List<DownloadPage>>() {
@Override
public void call(List<DownloadPage> downloadPages) {
ContentValues updateValues = new ContentValues(1);
updateValues.put(ApplicationContract.DownloadChapter.COLUMN_TOTAL_PAGES, downloadPages.size());
QueryManager.updateDownloadChapter(downloadChapter.getId(), updateValues)
.toBlocking()
.single();
EventBus.getDefault().post(new DownloadChapterQueryEvent());
}
})
.flatMap(new Func1<List<DownloadPage>, Observable<File>>() {
@Override
public Observable<File> call(final List<DownloadPage> downloadPages) {
return Observable.from(downloadPages.toArray(new DownloadPage[downloadPages.size()]))
.filter(new Func1<DownloadPage, Boolean>() {
@Override
public Boolean call(DownloadPage downloadPage) {
return downloadPage.getFlag() != DownloadUtils.FLAG_COMPLETED;
}
})
.flatMap(new Func1<DownloadPage, Observable<File>>() {
@Override
public Observable<File> call(final DownloadPage downloadPage) {
return mangaService
.getResponse(downloadPage.getUrl())
.flatMap(new Func1<Response, Observable<File>>() {
@Override
public Observable<File> call(Response response) {
String fileDirectory = downloadPage.getDirectory();
String fileName = downloadPage.getName();
String fileType = response.body().contentType().subtype();
InputStream fileData = response.body().byteStream();
return AizobanManager.saveInputStreamToDirectory(fileData, fileDirectory, fileName + "." + fileType);
}
})
.doOnCompleted(new Action0() {
@Override
public void call() {
ContentValues pageValues = new ContentValues(1);
pageValues.put(ApplicationContract.DownloadPage.COLUMN_FLAG, DownloadUtils.FLAG_COMPLETED);
QueryManager.updateDownloadPage(downloadPage.getId(), pageValues)
.toBlocking()
.single();
ContentValues chapterValues = new ContentValues(1);
chapterValues.put(ApplicationContract.DownloadChapter.COLUMN_CURRENT_PAGE, downloadPages.indexOf(downloadPage) + 1);
QueryManager.updateDownloadChapter(downloadChapter.getId(), chapterValues)
.toBlocking()
.single();
EventBus.getDefault().post(new DownloadChapterQueryEvent());
}
});
}
});
}
})
.doOnUnsubscribe(new Action0() {
@Override
public void call() {
isUnsubscribed.set(true);
}
})
.doOnError(new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
if (!isUnsubscribed.get()) {
ContentValues updateValues = new ContentValues(1);
updateValues.put(ApplicationContract.DownloadChapter.COLUMN_FLAG, DownloadUtils.FLAG_FAILED);
QueryManager.updateDownloadChapter(downloadChapter.getId(), updateValues)
.toBlocking()
.single();
EventBus.getDefault().post(new DownloadChapterQueryEvent());
}
}
})
.doOnCompleted(new Action0() {
@Override
public void call() {
Cursor downloadChapterCursor = QueryManager.queryDownloadChapterFromRequest(downloadRequest)
.toBlocking()
.single();
if (downloadChapterCursor != null) {
DownloadChapter updatedDownloadChapter = QueryManager.toObject(downloadChapterCursor, DownloadChapter.class);
if (updatedDownloadChapter != null) {
if (updatedDownloadChapter.getCurrentPage() != 0 && updatedDownloadChapter.getTotalPages() != 0) {
if (updatedDownloadChapter.getCurrentPage() == updatedDownloadChapter.getTotalPages()) {
QueryManager.deleteDownloadPagesOfDownloadChapter(downloadRequest)
.toBlocking()
.single();
ContentValues updateValues = new ContentValues(1);
updateValues.put(ApplicationContract.DownloadChapter.COLUMN_FLAG, DownloadUtils.FLAG_COMPLETED);
QueryManager.updateDownloadChapter(downloadChapter.getId(), updateValues)
.toBlocking()
.single();
QueryManager.addDownloadMangaIfNone(new RequestWrapper(downloadChapter.getSource(), downloadChapter.getParentUrl()))
.toBlocking()
.single();
}
}
}
}
EventBus.getDefault().post(new DownloadChapterQueryEvent());
}
});
}
public static Observable<GlideDrawable> cacheFromImagesOfSize(final List<String> imageUrls) {
return Observable.create(new Observable.OnSubscribe<GlideDrawable>() {
@Override
public void call(Subscriber<? super GlideDrawable> subscriber) {
try {
for (String imageUrl : imageUrls) {
if (!subscriber.isUnsubscribed()) {
FutureTarget<GlideDrawable> cacheFuture = Glide.with(AizobanApplication.getInstance())
.load(imageUrl)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.into(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL);
subscriber.onNext(cacheFuture.get(MangaService.READ_TIMEOUT, TimeUnit.SECONDS));
}
}
subscriber.onCompleted();
} catch (Throwable e) {
subscriber.onError(e);
}
}
}).subscribeOn(Schedulers.newThread());
}
public static Observable<Boolean> clearImageCache() {
return Observable.create(new Observable.OnSubscribe<Boolean>() {
@Override
public void call(Subscriber<? super Boolean> subscriber) {
try {
boolean isSuccessful = true;
File imageCacheDirectory = Glide.getPhotoCacheDir(AizobanApplication.getInstance());
if (imageCacheDirectory.isDirectory()) {
for (File cachedFile : imageCacheDirectory.listFiles()) {
if (!cachedFile.delete()) {
isSuccessful = false;
}
}
} else {
isSuccessful = false;
}
File urlCacheDirectory = CacheProvider.getInstance().getCacheDir();
if (urlCacheDirectory.isDirectory()) {
for (File cachedFile : urlCacheDirectory.listFiles()) {
if (!cachedFile.delete()) {
isSuccessful = false;
}
}
} else {
isSuccessful = false;
}
subscriber.onNext(isSuccessful);
subscriber.onCompleted();
} catch (Throwable e) {
subscriber.onError(e);
}
}
});
}
private static Observable<String> getImageUrlsFromDiskCache(final String chapterUrl) {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
try {
String[] imageUrls = CacheProvider.getInstance().getImageUrlsFromDiskCache(chapterUrl);
for (String imageUrl : imageUrls) {
if (!subscriber.isUnsubscribed()) {
subscriber.onNext(imageUrl);
}
}
subscriber.onCompleted();
} catch (Throwable e) {
subscriber.onError(e);
}
}
});
}
private static Observable<File> saveInputStreamToDirectory(final InputStream inputStream, final String directory, final String name) {
return Observable.create(new Observable.OnSubscribe<File>() {
@Override
public void call(Subscriber<? super File> subscriber) {
try {
subscriber.onNext(DiskUtils.saveInputStreamToDirectory(inputStream, directory, name));
subscriber.onCompleted();
} catch (Throwable e) {
subscriber.onError(e);
}
}
});
}
}