package zlc.season.rxdownload2.entity;
import org.reactivestreams.Publisher;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableEmitter;
import io.reactivex.FlowableOnSubscribe;
import io.reactivex.functions.Function;
import okhttp3.ResponseBody;
import retrofit2.Response;
import zlc.season.rxdownload2.db.DataBaseHelper;
import zlc.season.rxdownload2.function.DownloadApi;
import zlc.season.rxdownload2.function.FileHelper;
import static android.text.TextUtils.concat;
import static java.io.File.separator;
import static zlc.season.rxdownload2.entity.DownloadFlag.COMPLETED;
import static zlc.season.rxdownload2.entity.DownloadFlag.FAILED;
import static zlc.season.rxdownload2.entity.DownloadFlag.PAUSED;
import static zlc.season.rxdownload2.entity.DownloadFlag.STARTED;
import static zlc.season.rxdownload2.function.Constant.CACHE;
import static zlc.season.rxdownload2.function.Constant.RANGE_DOWNLOAD_STARTED;
import static zlc.season.rxdownload2.function.Utils.empty;
import static zlc.season.rxdownload2.function.Utils.getPaths;
import static zlc.season.rxdownload2.function.Utils.log;
import static zlc.season.rxdownload2.function.Utils.mkdirs;
/**
* Author: Season(ssseasonnn@gmail.com)
* Date: 2017/2/4
* FIXME
*/
public class TemporaryRecord {
private DownloadBean bean;
private String filePath;
private String tempPath;
private String lmfPath;
private int maxRetryCount;
private int maxThreads;
private long contentLength;
private String lastModify;
private boolean rangeSupport = false;
private boolean serverFileChanged = false;
private DataBaseHelper dataBaseHelper;
private FileHelper fileHelper;
private DownloadApi downloadApi;
public TemporaryRecord(DownloadBean bean) {
this.bean = bean;
}
/**
* init needs info
*
* @param maxThreads Max download threads
* @param maxRetryCount Max retry times
* @param defaultSavePath Default save path;
* @param downloadApi API
* @param dataBaseHelper DataBaseHelper
*/
public void init(int maxThreads, int maxRetryCount, String defaultSavePath,
DownloadApi downloadApi, DataBaseHelper dataBaseHelper) {
this.maxThreads = maxThreads;
this.maxRetryCount = maxRetryCount;
this.downloadApi = downloadApi;
this.dataBaseHelper = dataBaseHelper;
this.fileHelper = new FileHelper(maxThreads);
String realSavePath;
if (empty(bean.getSavePath())) {
realSavePath = defaultSavePath;
bean.setSavePath(defaultSavePath);
} else {
realSavePath = bean.getSavePath();
}
String cachePath = concat(realSavePath, separator, CACHE).toString();
mkdirs(realSavePath, cachePath);
String[] paths = getPaths(bean.getSaveName(), realSavePath);
filePath = paths[0];
tempPath = paths[1];
lmfPath = paths[2];
}
/**
* prepare normal download, create files and save last-modify.
*
* @throws IOException
* @throws ParseException
*/
public void prepareNormalDownload() throws IOException, ParseException {
fileHelper.prepareDownload(lastModifyFile(), file(), contentLength, lastModify);
}
/**
* prepare range download, create necessary files and save last-modify.
*
* @throws IOException
* @throws ParseException
*/
public void prepareRangeDownload() throws IOException, ParseException {
fileHelper.prepareDownload(lastModifyFile(), tempFile(), file(), contentLength, lastModify);
}
/**
* Read download range from record file.
*
* @param index index
* @return
* @throws IOException
*/
public DownloadRange readDownloadRange(int index) throws IOException {
return fileHelper.readDownloadRange(tempFile(), index);
}
/**
* Normal download save.
*
* @param e emitter
* @param response response
*/
public void save(FlowableEmitter<DownloadStatus> e, Response<ResponseBody> response) {
fileHelper.saveFile(e, file(), response);
}
/**
* Range download save
*
* @param emitter emitter
* @param index download index
* @param response response
* @throws IOException
*/
public void save(FlowableEmitter<DownloadStatus> emitter, int index, ResponseBody response)
throws IOException {
fileHelper.saveFile(emitter, index, tempFile(), file(), response);
}
/**
* Normal download request.
*
* @return response
*/
public Flowable<Response<ResponseBody>> download() {
return downloadApi.download(null, bean.getUrl());
}
/**
* Range download request
*
* @param index download index
* @return response
*/
public Flowable<Response<ResponseBody>> rangeDownload(final int index) {
return Flowable
.create(new FlowableOnSubscribe<DownloadRange>() {
@Override
public void subscribe(FlowableEmitter<DownloadRange> e) throws Exception {
DownloadRange range = readDownloadRange(index);
if (range.legal()) {
e.onNext(range);
}
e.onComplete();
}
}, BackpressureStrategy.ERROR)
.flatMap(new Function<DownloadRange, Publisher<Response<ResponseBody>>>() {
@Override
public Publisher<Response<ResponseBody>> apply(DownloadRange range)
throws Exception {
log(RANGE_DOWNLOAD_STARTED, index, range.start, range.end);
String rangeStr = "bytes=" + range.start + "-" + range.end;
return downloadApi.download(rangeStr, bean.getUrl());
}
});
}
public int getMaxRetryCount() {
return maxRetryCount;
}
public int getMaxThreads() {
return maxThreads;
}
public boolean isSupportRange() {
return rangeSupport;
}
public void setRangeSupport(boolean rangeSupport) {
this.rangeSupport = rangeSupport;
}
public boolean isFileChanged() {
return serverFileChanged;
}
public void setFileChanged(boolean serverFileChanged) {
this.serverFileChanged = serverFileChanged;
}
public long getContentLength() {
return contentLength;
}
public void setContentLength(long contentLength) {
this.contentLength = contentLength;
}
public void setLastModify(String lastModify) {
this.lastModify = lastModify;
}
public String getSaveName() {
return bean.getSaveName();
}
public void setSaveName(String saveName) {
bean.setSaveName(saveName);
}
public File file() {
return new File(filePath);
}
public File tempFile() {
return new File(tempPath);
}
public File lastModifyFile() {
return new File(lmfPath);
}
public boolean fileComplete() {
return file().length() == contentLength;
}
public boolean tempFileDamaged() throws IOException {
return fileHelper.tempFileDamaged(tempFile(), contentLength);
}
public String readLastModify() throws IOException {
return fileHelper.readLastModify(lastModifyFile());
}
public boolean fileNotComplete() throws IOException {
return fileHelper.fileNotComplete(tempFile());
}
public File[] getFiles() {
return new File[]{file(), tempFile(), lastModifyFile()};
}
public void start() {
if (dataBaseHelper.recordNotExists(bean.getUrl())) {
dataBaseHelper.insertRecord(bean, STARTED);
} else {
dataBaseHelper.updateRecord(bean.getUrl(), bean.getSaveName(), bean.getSavePath(), STARTED);
}
}
public void update(DownloadStatus status) {
dataBaseHelper.updateStatus(bean.getUrl(), status);
}
public void error() {
dataBaseHelper.updateRecord(bean.getUrl(), FAILED);
}
public void complete() {
dataBaseHelper.updateRecord(bean.getUrl(), COMPLETED);
}
public void cancel() {
dataBaseHelper.updateRecord(bean.getUrl(), PAUSED);
}
public void finish() {
// dataBaseHelper.closeDataBase();
}
}