package io.kaif.mobile.view.daemon; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; import android.support.annotation.NonNull; import android.support.v4.util.Pair; import io.kaif.mobile.event.EventPublishSubject; import io.kaif.mobile.event.article.ArticleEvent; import io.kaif.mobile.model.Article; import io.kaif.mobile.model.Vote; import io.kaif.mobile.model.exception.DuplicateArticleUrlException; import io.kaif.mobile.service.ArticleService; import io.kaif.mobile.service.CommaSeparatedParam; import io.kaif.mobile.service.VoteService; import io.kaif.mobile.view.viewmodel.ArticleViewModel; import rx.Observable; @Singleton public class ArticleDaemon { private final EventPublishSubject<ArticleEvent> subject; private final ArticleService articleService; private final VoteService voteService; public Observable<ArticleEvent> getSubject(Class<?>... classes) { return subject.getSubject(classes); } public <T extends ArticleEvent> Observable<T> getSubject(Class<T> clazz) { return subject.getSubject(clazz); } @Inject ArticleDaemon(ArticleService articleService, VoteService voteService) { this.voteService = voteService; this.articleService = articleService; this.subject = new EventPublishSubject<>(); } public Observable<Article> createExternalLink(@NonNull String url, @NonNull String title, @NonNull String zone, boolean forceCreate) { Observable<Void> checkObservable = Observable.just(null); if (!forceCreate) { checkObservable = articleService.exist(zone, url).flatMap(duplicate -> { if (duplicate) { return Observable.error(new DuplicateArticleUrlException()); } return Observable.just(null); }); } return checkObservable.flatMap(aVoid -> articleService.createExternalLink(new ArticleService.ExternalLinkEntry( url, title, zone))); } public Observable<List<ArticleViewModel>> listHotArticles(String startArticleId) { return articleService.listHotArticles(startArticleId).flatMap(articles -> { List<String> ids = mapArticlesToIds(articles); return voteService.listArticleVotes(CommaSeparatedParam.of(ids)) .map(votes -> new Pair<>(articles, votes)) .map(this::mapToViewModel); }); } public Observable<List<ArticleViewModel>> listLatestArticles(String startArticleId) { return articleService.listLatestArticles(startArticleId).flatMap(articles -> { List<String> ids = mapArticlesToIds(articles); return voteService.listArticleVotes(CommaSeparatedParam.of(ids)) .map(votes -> new Pair<>(articles, votes)) .map(this::mapToViewModel); }); } public Observable<ArticleViewModel> loadArticle(String articleId) { return articleService.loadArticle(articleId) .flatMap(article -> voteService.listArticleVotes(CommaSeparatedParam.of(Collections.singletonList( article.getArticleId()))) .map(votes -> new Pair<>(Collections.singletonList(article), votes)) .map(this::mapToViewModel) .map(articleViewModels -> articleViewModels.get(0))); } private Vote loadVote(List<Vote> votes, String targetId) { for (Vote vote : votes) { if (vote.matches(targetId)) { return vote; } } return Vote.abstain(targetId); } private List<String> mapArticlesToIds(List<Article> articles) { List<String> ids = new ArrayList<>(); for (Article article : articles) { ids.add(article.getArticleId()); } return ids; } private List<ArticleViewModel> mapToViewModel(Pair<List<Article>, List<Vote>> articlesAndVotes) { final List<Article> articles = articlesAndVotes.first; final List<Vote> votes = articlesAndVotes.second; List<ArticleViewModel> viewModels = new ArrayList<>(); for (int i = 0; i < articles.size(); i++) { Article article = articles.get(i); viewModels.add(new ArticleViewModel(article, loadVote(votes, article.getArticleId()))); } return viewModels; } }