package zlc.season.rxdownload2.entity;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.processors.FlowableProcessor;
import zlc.season.rxdownload2.RxDownload;
import zlc.season.rxdownload2.db.DataBaseHelper;
import zlc.season.rxdownload2.function.Constant;
import static zlc.season.rxdownload2.function.DownloadEventFactory.completed;
import static zlc.season.rxdownload2.function.DownloadEventFactory.failed;
import static zlc.season.rxdownload2.function.DownloadEventFactory.normal;
import static zlc.season.rxdownload2.function.DownloadEventFactory.paused;
import static zlc.season.rxdownload2.function.DownloadEventFactory.started;
import static zlc.season.rxdownload2.function.DownloadEventFactory.waiting;
import static zlc.season.rxdownload2.function.Utils.createProcessor;
import static zlc.season.rxdownload2.function.Utils.formatStr;
import static zlc.season.rxdownload2.function.Utils.log;
/**
* Author: Season(ssseasonnn@gmail.com)
* Date: 2017/2/24
* <p>
* MultiMission, many urls.
*/
public class MultiMission extends DownloadMission {
private AtomicInteger completeNumber;
private AtomicInteger failedNumber;
private List<SingleMission> missions;
private String missionId;
private Observer<DownloadStatus> observer;
public MultiMission(MultiMission other) {
super(other.rxdownload);
this.missionId = other.getUrl();
this.missions = new ArrayList<>();
this.completeNumber = new AtomicInteger(0);
this.failedNumber = new AtomicInteger(0);
this.observer = new SingleMissionObserver(this);
for (SingleMission each : other.getMissions()) {
this.missions.add(new SingleMission(each, observer));
}
}
public MultiMission(RxDownload rxDownload, String missionId, List<DownloadBean> missions) {
super(rxDownload);
this.missionId = missionId;
this.missions = new ArrayList<>();
this.completeNumber = new AtomicInteger(0);
this.failedNumber = new AtomicInteger(0);
this.observer = new SingleMissionObserver(this);
for (DownloadBean each : missions) {
this.missions.add(new SingleMission(rxDownload, each, missionId, observer));
}
}
public String getUrl() {
return missionId;
}
@Override
public void init(Map<String, DownloadMission> missionMap,
Map<String, FlowableProcessor<DownloadEvent>> processorMap) {
DownloadMission mission = missionMap.get(getUrl());
if (mission == null) {
missionMap.put(getUrl(), this);
} else {
if (mission.isCanceled()) {
missionMap.put(getUrl(), this);
} else {
throw new IllegalArgumentException(formatStr(Constant.DOWNLOAD_URL_EXISTS, getUrl()));
}
}
this.processor = createProcessor(getUrl(), processorMap);
for (SingleMission each : missions) {
each.init(missionMap, processorMap);
}
}
@Override
public void insertOrUpdate(DataBaseHelper dataBaseHelper) {
for (SingleMission each : missions) {
each.insertOrUpdate(dataBaseHelper);
}
}
@Override
public void sendWaitingEvent(DataBaseHelper dataBaseHelper) {
for (SingleMission each : missions) {
each.sendWaitingEvent(dataBaseHelper);
}
processor.onNext(waiting(null));
}
@Override
public void start(Semaphore semaphore) throws InterruptedException {
for (SingleMission each : missions) {
each.start(semaphore);
}
}
@Override
public void pause(DataBaseHelper dataBaseHelper) {
for (SingleMission each : missions) {
each.pause(dataBaseHelper);
}
setCanceled(true);
completeNumber.set(0);
failedNumber.set(0);
processor.onNext(paused(null));
}
@Override
public void delete(DataBaseHelper dataBaseHelper, boolean deleteFile) {
for (SingleMission each : missions) {
each.delete(dataBaseHelper, deleteFile);
}
setCanceled(true);
completeNumber.set(0);
failedNumber.set(0);
processor.onNext(normal(null));
}
private List<SingleMission> getMissions() {
return missions;
}
private class SingleMissionObserver implements Observer<DownloadStatus> {
MultiMission real;
public SingleMissionObserver(MultiMission multiMission) {
this.real = multiMission;
}
@Override
public void onSubscribe(Disposable d) {
real.processor.onNext(started(null));
}
@Override
public void onNext(DownloadStatus value) {
}
@Override
public void onError(Throwable e) {
log("onerror");
int temp = real.failedNumber.incrementAndGet();
log("temp: " + temp);
log("size: " + real.missions.size());
if ((temp + real.completeNumber.intValue()) == real.missions.size()) {
real.processor.onNext(failed(null, new Throwable("download failed")));
real.setCanceled(true);
log("set error cancel");
}
}
@Override
public void onComplete() {
int temp = real.completeNumber.incrementAndGet();
if (temp == real.missions.size()) {
real.processor.onNext(completed(null));
real.setCompleted(true);
real.setCanceled(true);
} else if ((temp + real.failedNumber.intValue()) == real.missions.size()) {
real.processor.onNext(failed(null, new Throwable("download failed")));
real.setCanceled(true);
}
}
}
}