package com.leavjenn.hews.ui.search;
import android.os.Bundle;
import android.support.annotation.NonNull;
import com.leavjenn.hews.Constants;
import com.leavjenn.hews.R;
import com.leavjenn.hews.misc.Utils;
import com.leavjenn.hews.ui.BasePresenter;
import com.leavjenn.hews.misc.SharedPrefsContract;
import com.leavjenn.hews.misc.UtilsContract;
import com.leavjenn.hews.model.Comment;
import com.leavjenn.hews.model.HNItem;
import com.leavjenn.hews.model.Post;
import com.leavjenn.hews.data.remote.DataManager;
import org.parceler.Parcels;
import java.util.ArrayList;
import java.util.List;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Action1;
import rx.schedulers.Schedulers;
import rx.subscriptions.CompositeSubscription;
public class SearchPresenter extends BasePresenter {
public static final String TAG = "SearchPresenter";
private static final String KEY_KEYWORD = "key_keyword";
private static final String KEY_TIME_RANGE = "key_time_range";
private static final String KEY_SORT_METHOD = "key_sort_method";
private static final String KEY_POST_ID_LIST = "key_post_id_list";
private static final String KEY_LOADED_POSTS = "key_loaded_posts";
private static final String KEY_LOADED_TIME = "key_loaded_time";
private static final String KEY_LOADING_STATE = "key_loading_state";
private static final String KEY_SEARCH_RESULT_TOTAL_PAGE = "key_search_result_total_page";
private SearchView mSearchView;
private DataManager mDataManager;
private SharedPrefsContract mPrefsManager;
private UtilsContract mUtils;
private String mKeyword;
private String mDateRange;
private boolean mIsSortByDate;
private List<Long> mPostIdList;
private ArrayList<Post> mCachedPostList;
private int mLoadingState;
private Observable<Post> mPostObservable;
private CompositeSubscription mCompositeSubscription;
private int mLoadedTime;
private int mSearchResultTotalPages;
private boolean mShowPostSummary;
public SearchPresenter(@NonNull SearchView searchView) {
mSearchView = searchView;
mCompositeSubscription = new CompositeSubscription();
mPostIdList = new ArrayList<>();
mCachedPostList = new ArrayList<>();
}
public SearchPresenter(@NonNull SearchView searchView, @NonNull DataManager dataManager,
@NonNull SharedPrefsContract prefsManager, @NonNull UtilsContract utils) {
this(searchView);
mDataManager = dataManager;
mPrefsManager = prefsManager;
mCompositeSubscription = new CompositeSubscription();
mUtils = utils;
}
public void setView(SearchView searchView) {
mSearchView = searchView;
}
public void setDataManager(DataManager dataManager) {
mDataManager = dataManager;
}
public void setPrefsManager(SharedPrefsContract sharedPrefsContract) {
mPrefsManager = sharedPrefsContract;
}
public void setUtils(UtilsContract utils) {
mUtils = utils;
}
@Override
public void setup() {
if (mPostIdList.isEmpty()) {
mSearchView.showInfoLog("search setup", "empty post id list");
refresh();
} else {
mSearchView.showInfoLog("search setup", "restore posts: " + getCachedPosts().size());
mSearchView.restoreCachedPosts(getCachedPosts());
if (mCachedPostList.isEmpty() // post ID list is fetched, but post list is not yet
|| mLoadingState == Constants.LOADING_IN_PROGRESS) {
mSearchView.showInfoLog("search setup", "reload");
reload();
updateLoadingState(Constants.LOADING_IN_PROGRESS);
}
}
}
@Override
public void restoreState(Bundle savedInstanceState) {
if (savedInstanceState == null) {
return;
}
mKeyword = savedInstanceState.getString(KEY_KEYWORD);
mDateRange = savedInstanceState.getString(KEY_TIME_RANGE);
mIsSortByDate = savedInstanceState.getBoolean(KEY_SORT_METHOD);
mPostIdList = Parcels.unwrap(savedInstanceState.getParcelable(KEY_POST_ID_LIST));
mCachedPostList = Parcels.unwrap(savedInstanceState.getParcelable(KEY_LOADED_POSTS));
mSearchResultTotalPages = savedInstanceState.getInt(KEY_SEARCH_RESULT_TOTAL_PAGE);
mLoadedTime = savedInstanceState.getInt(KEY_LOADED_TIME);
mLoadingState = savedInstanceState.getInt(KEY_LOADING_STATE);
}
@Override
public void saveState(Bundle outState) {
outState.putString(KEY_KEYWORD, mKeyword);
outState.putString(KEY_TIME_RANGE, mDateRange);
outState.putBoolean(KEY_SORT_METHOD, mIsSortByDate);
outState.putParcelable(KEY_LOADED_POSTS, Parcels.wrap(mCachedPostList));
outState.putParcelable(KEY_POST_ID_LIST, Parcels.wrap(mPostIdList));
outState.putInt(KEY_SEARCH_RESULT_TOTAL_PAGE, mSearchResultTotalPages);
outState.putInt(KEY_LOADED_TIME, mLoadedTime);
outState.putInt(KEY_LOADING_STATE, mLoadingState);
}
@Override
public void destroy() {
// if (mCompositeSubscription.hasSubscriptions()) {
mCompositeSubscription.clear();
// }
mSearchView.showInfoLog(TAG, "destroy");
mSearchView = null;
mDataManager = null;
mPrefsManager = null;
mUtils = null;
}
@Override
public void unsubscribe() {
mCompositeSubscription.clear();
}
public void refresh() {
if (mKeyword != null && mDateRange != null) {
refresh(mKeyword, mDateRange, mIsSortByDate);
} else {
mSearchView.hideSwipeRefresh();
//TODO show prompt
}
}
public void refresh(String dateRange) {
refresh(mKeyword, dateRange, mIsSortByDate);
}
public void refresh(boolean isSortByDate) {
refresh(mKeyword, mDateRange, isSortByDate);
}
public void refresh(String keyword, String dateRange, boolean isSortByDate) {
if (!mUtils.isOnline()) {
mSearchView.hideSwipeRefresh();
mSearchView.showOfflineSnackBar();
return;
}
mKeyword = keyword;
mDateRange = dateRange;
mIsSortByDate = isSortByDate;
mLoadedTime = 1;
mPostIdList.clear();
mCachedPostList.clear();
mCompositeSubscription.clear();
mSearchView.showSwipeRefresh();
mSearchView.hideOfflineSnackBar();
mSearchView.resetAdapter();
updateLoadingState(Constants.LOADING_IDLE);
loadPostIdListBySearch(keyword, dateRange, 0, isSortByDate);
}
public void loadPostIdListBySearch(String keyword, String dateRange, int page, boolean isSortByDate) {
mCompositeSubscription.add(
mDataManager.getSearchResult(keyword, "created_at_i>" + dateRange.substring(0, 10)
+ "," + "created_at_i<" + dateRange.substring(10), page, isSortByDate)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<HNItem.SearchResult>() {
@Override
public void call(HNItem.SearchResult searchResult) {
if (searchResult.getHits().length == 0) {
mSearchView.hideSwipeRefresh();
mSearchView.updatePrompt(R.string.no_search_result_prompt);
updateLoadingState(Constants.LOADING_PROMPT_NO_CONTENT);
return;
}
List<Long> list = new ArrayList<>();
mSearchResultTotalPages = searchResult.getNbPages();
for (int i = 0; i < searchResult.getHits().length; i++) {
list.add(searchResult.getHits()[i].getObjectID());
}
mPostIdList.clear();
mPostIdList.addAll(list);
loadPosts(list, true);
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
mSearchView.hideSwipeRefresh();
mSearchView.showErrorLog("loadPostIdListBySearch", throwable.toString());
}
}));
}
void loadPosts(List<Long> list, boolean updateObservable) {
if (updateObservable || mPostObservable == null) {
mPostObservable = mDataManager.getPosts(list).cache();
}
mCompositeSubscription.add(mPostObservable
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Post>() {
@Override
public void onCompleted() {
updateLoadingState(Constants.LOADING_IDLE);
updateCachedPostList();
mSearchView.showInfoLog("loadPosts - completed", "cached: " + mCachedPostList.size());
}
@Override
public void onError(Throwable throwable) {
mSearchView.hideSwipeRefresh();
updateLoadingState(Constants.LOADING_ERROR);
mSearchView.showErrorLog("loadPosts", throwable.toString());
}
@Override
public void onNext(Post post) {
mSearchView.hideSwipeRefresh();
if (post != null) {
post.setIndex(mSearchView.getLastPostIndex());
Utils.setupPostUrl(post);
post.setRead(mPrefsManager.isPostRead(post.getId()));
mSearchView.showPost(post);
if (mLoadingState != Constants.LOADING_IN_PROGRESS) {
updateLoadingState(Constants.LOADING_IN_PROGRESS);
}
if (mShowPostSummary && post.getKids() != null) {
loadSummary(post);
}
}
}
}));
}
void loadSummary(final Post post) {
mCompositeSubscription.add(mDataManager.getSummary(post.getKids())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Action1<Comment>() {
@Override
public void call(Comment comment) {
if (comment != null) {
post.setSummary(mUtils.convertHtmlToString(
comment.getText().replace("<p>", "<br /><br />").replace("\n", "<br />")));
mSearchView.showSummary(post.getIndex());
} else {
post.setSummary(null);
}
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
mSearchView.showErrorLog("loadSummary: " + String.valueOf(post.getId()),
throwable.toString());
}
})
);
}
public String getKeyword() {
return mKeyword;
}
public void setKeyword(String keyword) {
mKeyword = keyword;
}
public String getDateRange() {
return mDateRange;
}
public void setDateRange(String dateRange) {
mDateRange = dateRange;
}
public boolean isSortByDate() {
return mIsSortByDate;
}
public void setSortByDate(boolean isSortByDate) {
mIsSortByDate = isSortByDate;
}
private void updateLoadingState(int loadingState) {
mLoadingState = loadingState;
mSearchView.updateListFooter(mLoadingState);
}
public void updateCachedPostList() {
mCachedPostList.clear();
mCachedPostList.addAll(mSearchView.getAllPostList());
}
public List<Post> getCachedPosts() {
return mCachedPostList;
}
public void loadMore() {
if (mLoadingState != Constants.LOADING_IDLE) {
return;
}
if (mLoadedTime < mSearchResultTotalPages) {
mSearchView.showInfoLog("loadMore",
String.valueOf(mSearchResultTotalPages) + "/" + String.valueOf(mLoadedTime));
updateLoadingState(Constants.LOADING_IN_PROGRESS);
loadPostIdListBySearch(mKeyword, mDateRange, mLoadedTime++, mIsSortByDate);
} else {
mSearchView.showLongToast(R.string.no_more_posts_prompt);
updateLoadingState(Constants.LOADING_FINISH);
}
}
private void reload() {
if (mLoadedTime < mSearchResultTotalPages) {
mSearchView.showInfoLog("reload search",
String.valueOf(mLoadedTime) + "/" + String.valueOf(mSearchResultTotalPages));
loadPosts(mPostIdList, false);
} else {
mSearchView.showLongToast(R.string.no_more_posts_prompt);
updateLoadingState(Constants.LOADING_FINISH);
}
}
public void setShowPostSummaryPref() {
mShowPostSummary = mPrefsManager.isShowPostSummary();
}
}