@Accessors(prefix = "m")
public class Photo {

    @Getter
    @Setter
    private int mId;

    @Getter
    @Setter
    private String mTitle;

    @Getter
    @Setter
    private String mUrl;

    @Getter
    @Setter
    private String mThumbnailUrl;
} @Accessors(prefix = "m")
public class PhotoStatistics {

    @Setter
    @Getter
    private Photo mLastOpenedPhoto;

    @Setter
    @Getter
    private int mOpenedPhotosCount;
} @Accessors(prefix = "m") public class GetPhotoStatistics extends UseCase<PhotoStatistics> {

  @Inject PhotoStatisticsEntityDataSource mPhotoStatisticsEntityDataSource;
  @Inject GetPhotoDetails mGetPhotoDetailsUseCase;

  @Inject public GetPhotoStatistics(@Named(RxModule.COMPUTATION) Scheduler executionScheduler,
      @Named(RxModule.MAIN_THREAD) Scheduler observingScheduler) {
    super(executionScheduler, observingScheduler);
  }

  @Override protected Observable<PhotoStatistics> call() {
    return mPhotoStatisticsEntityDataSource.readStatistics().
        switchMap(photoStatisticsEntity -> {
          mGetPhotoDetailsUseCase.setPhotoId(photoStatisticsEntity.getLastOpenedPhotoId());
          return mGetPhotoDetailsUseCase.call().map(photo -> {
            PhotoStatistics merged = new PhotoStatistics();

            merged.setLastOpenedPhoto(photo);
            merged.setOpenedPhotosCount(photoStatisticsEntity.getOpenedPhotosCount());

            return merged;
          });
        });
  }
} public class GetPhotosList extends UseCase<List<Photo>> {

  private PhotoEntityDataSource mPhotoEntityDataSource;
  private final PhotoEntityToPhoto mPhotoTransformer;

  @Inject public GetPhotosList(@Named(RxModule.COMPUTATION) Scheduler executionScheduler,
      @Named(RxModule.MAIN_THREAD) Scheduler observingScheduler,
      PhotoEntityDataSource photoEntityDataSource) {
    super(executionScheduler, observingScheduler);
    mPhotoTransformer = new PhotoEntityToPhoto();
    mPhotoEntityDataSource = photoEntityDataSource;
  }

  @Override protected Observable<List<Photo>> call() {
    return mPhotoEntityDataSource.photos().map(mPhotoTransformer::transform);
  }
} @Accessors(prefix = "m")
public class SavePhotoStatistics extends UseCase<Void> {
    private final PhotoStatisticsToPhotoStatisticsEntity mPhotoStatisticsToPhotoStatisticsEntityTransformer;

    @Setter
    private PhotoStatistics mPhotoStatistics;

    @Inject PhotoStatisticsEntityDataSource mPhotoStatisticsEntityDataSource;

    @Inject public SavePhotoStatistics(@Named(RxModule.COMPUTATION) Scheduler executionScheduler,
        @Named(RxModule.MAIN_THREAD) Scheduler observingScheduler) {
        super(executionScheduler, observingScheduler);
        mPhotoStatisticsToPhotoStatisticsEntityTransformer =
            new PhotoStatisticsToPhotoStatisticsEntity();
    }

    @Override
    protected Observable<Void> call() {
        PhotoStatisticsEntity photoStatisticsEntity = mPhotoStatisticsToPhotoStatisticsEntityTransformer.transform(mPhotoStatistics);
        return mPhotoStatisticsEntityDataSource.updateStatistics(photoStatisticsEntity).map(photoStatisticsEntity1 -> null);
    }
} @Accessors(prefix = "m") public class SearchByTitle extends UseCase<List<Photo>> {

  @Setter private String mSearchedTitle;
  private PhotoEntityDataSource mPhotoEntityDataSource;
  private final PhotoEntityToPhoto photoTransformer;

  @Inject public SearchByTitle(@Named(RxModule.COMPUTATION) Scheduler executionScheduler,
      @Named(RxModule.MAIN_THREAD) Scheduler observingScheduler,
      PhotoEntityDataSource photoEntityDataSource) {
    super(executionScheduler, observingScheduler);
    mPhotoEntityDataSource = photoEntityDataSource;
    photoTransformer = new PhotoEntityToPhoto();
  }

  @Override protected Observable<List<Photo>> call() {
    return this.mPhotoEntityDataSource.searchPhotosByTitle(mSearchedTitle)
        .map(photoTransformer::transform);
  }
} public class SimpleSubscriber<T> extends rx.Subscriber<T> {
    @Override
    public void onCompleted() {
        // no-op by default.
    }

    @Override
    public void onError(Throwable e) {
        // no-op by default.
    }

    @Override
    public void onNext(T t) {
        // no-op by default.
    }
} public class PhotoToPhotoModel extends BaseLayerDataTransformer<Photo, PhotoModel> {
    @Override
    public PhotoModel transform(Photo from) {
        PhotoModel transformed = new PhotoModel();

        transformed.setId(from.getId());
        transformed.setTitle(from.getTitle());
        transformed.setUrl(from.getUrl());
        transformed.setThumbnailUrl(from.getThumbnailUrl());

        return transformed;
    }
} public class PhotoStatisticsModelToPhotoStatistics extends BaseLayerDataTransformer<PhotoStatisticsModel, PhotoStatistics> {

    private PhotoModelToPhoto mPhotoModelToPhotoTransformer;

    public PhotoStatisticsModelToPhotoStatistics() {
        mPhotoModelToPhotoTransformer = new PhotoModelToPhoto();
    }

    @Override
    public PhotoStatistics transform(PhotoStatisticsModel from) {
        PhotoStatistics transformed = new PhotoStatistics();

        PhotoModel lastOpenedPhotoModel = from.getLastOpenedPhotoModel();

        if (lastOpenedPhotoModel != null) {
            transformed.setLastOpenedPhoto(mPhotoModelToPhotoTransformer.transform(lastOpenedPhotoModel));
            transformed.setOpenedPhotosCount(from.getOpenedPhotosCount());
        }

        return transformed;
    }
} public class PhotoStatisticsToPhotoStatisticsModel extends BaseLayerDataTransformer<PhotoStatistics, PhotoStatisticsModel> {

    private PhotoToPhotoModel mPhotoToPhotoModelTransformer;

    public PhotoStatisticsToPhotoStatisticsModel() {
        mPhotoToPhotoModelTransformer = new PhotoToPhotoModel();
    }

    @Override
    public PhotoStatisticsModel transform(PhotoStatistics from) {
        PhotoStatisticsModel transformed = new PhotoStatisticsModel();

        transformed.setOpenedPhotosCount(from.getOpenedPhotosCount());

        Photo lastOpenedPhoto = from.getLastOpenedPhoto();
        if (lastOpenedPhoto != null) {
            transformed.setLastOpenedPhotoModel(mPhotoToPhotoModelTransformer.transform(lastOpenedPhoto));
        }

        return transformed;
    }
} @Accessors(prefix = "m")
public class PhotoModel {

    @Getter
    @Setter
    private int mId;

    @Getter
    @Setter
    private String mTitle;

    @Getter
    @Setter
    private String mUrl;

    @Getter
    @Setter
    private String mThumbnailUrl;
} @Accessors(prefix = "m")
public class PhotoStatisticsModel {

    @Setter
    @Getter
    private PhotoModel mLastOpenedPhotoModel;

    @Setter
    @Getter
    private int mOpenedPhotosCount;

    public void incOpenedPhotosCount() {
        mOpenedPhotosCount++;
    }
} public interface PhotoListView extends LoadDataView {
    /**
     * Render a photo list in the UI.
     *
     * @param photoModelCollection The collection of {@link PhotoModel} that will be shown.
     */
    void renderPhotoList(Collection<PhotoModel> photoModelCollection);

    /**
     * View a {@link PhotoModel} profile/details.
     *
     * @param photoModel The photo that will be shown.
     */
    void viewPhoto(PhotoModel photoModel);


    /**
     * View a {@link PhotoStatisticsModel} profile/details.
     *
     * @param photoStatisticsModel The PhotoStatisticsModel that will be shown.
     */
    void renderPhotoStatisticsModel(PhotoStatisticsModel photoStatisticsModel);

    /**
     * Highlights text entries in list items.
     *
     * @param textToHighlight text to highlight.
     */
    void highlightTextInList(String textToHighlight);
}
import android.support.annotation.NonNull;
import com.photoviewer.domain.Photo;
import com.photoviewer.domain.PhotoStatistics;
import com.photoviewer.domain.usecases.GetPhotoStatistics;
import com.photoviewer.domain.usecases.GetPhotosList;
import com.photoviewer.domain.usecases.SavePhotoStatistics;
import com.photoviewer.domain.usecases.SearchByTitle;
import com.photoviewer.domain.usecases.SimpleSubscriber;
import com.photoviewer.presentation.mapper.photo.PhotoToPhotoModel;
import com.photoviewer.presentation.mapper.photostatistics.PhotoStatisticsModelToPhotoStatistics;
import com.photoviewer.presentation.mapper.photostatistics.PhotoStatisticsToPhotoStatisticsModel;
import com.photoviewer.presentation.model.PhotoModel;
import com.photoviewer.presentation.model.PhotoStatisticsModel;
import com.photoviewer.presentation.view.PhotoListView;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.inject.Inject;
package com.photoviewer.presentation.presenter;




/**
 * {@link Presenter} that controls communication between views and models of the presentation
 * layer.
 */
public class PhotoListPresenter extends SimplePresenter {

    private PhotoStatisticsModel mPhotoStatisticsModel;

    private PhotoListView mViewList;

    //Use cases
    private final GetPhotosList mGetPhotoListUseCase;
    private final SearchByTitle mSearchByTitleUseCase;
    private final GetPhotoStatistics mGetPhotoStatisticsUseCase;
    private final SavePhotoStatistics mSavePhotoStatisticsUseCase;

    //Transformers
    private PhotoToPhotoModel mPhotoModelTransformer;
    private PhotoStatisticsToPhotoStatisticsModel mPhotoStatisticsToPhotoStatisticsModelTransformer;
    private PhotoStatisticsModelToPhotoStatistics mPhotoStatisticsModelToPhotoStatisticsTransformer;

    private AlphabetPhotoModelTitleComparator mModelTitleComparator = new AlphabetPhotoModelTitleComparator(true);
    private String mSearchedTitle;

    @Inject
    public PhotoListPresenter(GetPhotosList getPhotoListUseCase,
                              SearchByTitle searchByTitleUseCase,
                              GetPhotoStatistics getPhotoStatistics,
                              SavePhotoStatistics savePhotoStatistics) {

        mGetPhotoListUseCase = getPhotoListUseCase;
        mSearchByTitleUseCase = searchByTitleUseCase;
        mGetPhotoStatisticsUseCase = getPhotoStatistics;
        mSavePhotoStatisticsUseCase = savePhotoStatistics;

        createTransformers();
    }

    private void createTransformers() {
        mPhotoModelTransformer = new PhotoToPhotoModel();
        mPhotoStatisticsModelToPhotoStatisticsTransformer = new PhotoStatisticsModelToPhotoStatistics();
        mPhotoStatisticsToPhotoStatisticsModelTransformer = new PhotoStatisticsToPhotoStatisticsModel();
    }

    public void setView(@NonNull PhotoListView view) {
        mViewList = view;
    }

    @Override public void destroy() {
        mGetPhotoListUseCase.unsubscribe();
    }

    /**
     * Initializes the presenter by start retrieving the photo list.
     */
    public void initialize() {
        loadPhotoList();
        loadPhotoStatistics();
    }

    private void loadPhotoStatistics() {
        mGetPhotoStatisticsUseCase.execute(new PhotoStatisticsSubscriber());
    }

    public void sort(boolean ascending) {
        mModelTitleComparator = new AlphabetPhotoModelTitleComparator(ascending);

        if(mSearchedTitle == null || mSearchedTitle.isEmpty()) {
            loadPhotoList();
            mViewList.highlightTextInList(null);
        } else {
            searchByTitle(mSearchedTitle);
        }
    }

    public void searchByTitle(String title) {
        mSearchedTitle = title;

        if (title == null || title.isEmpty()) {
            loadPhotoList();
        } else {
            showViewLoading();
            mSearchByTitleUseCase.setSearchedTitle(title);
            mSearchByTitleUseCase.execute(new PhotoListSubscriber());
        }

        mViewList.highlightTextInList(title);
    }

    public void onPhotoClicked(PhotoModel photoModel) {
        mViewList.viewPhoto(photoModel);
        updatePhotoStatisticsModel(photoModel);
    }

    private void updatePhotoStatisticsModel(PhotoModel photoModel) {
        mPhotoStatisticsModel.incOpenedPhotosCount();
        mPhotoStatisticsModel.setLastOpenedPhotoModel(photoModel);

        PhotoStatistics photoStatistics = mPhotoStatisticsModelToPhotoStatisticsTransformer.transform(mPhotoStatisticsModel);
        mSavePhotoStatisticsUseCase.setPhotoStatistics(photoStatistics);
        mSavePhotoStatisticsUseCase.execute(new SimpleSubscriber<>());

        mViewList.renderPhotoStatisticsModel(mPhotoStatisticsModel);
    }

    /**
     * Loads all photos.
     */
    public void loadPhotoList() {
        hideViewRetry();
        showViewLoading();
        getPhotoList();
    }

    private void showViewLoading() {
        mViewList.showLoading();
    }

    private void hideViewLoading() {
        mViewList.hideLoading();
    }

    private void showViewRetry() {
        mViewList.showRetry();
    }

    private void hideViewRetry() {
        mViewList.hideRetry();
    }

    private void showErrorMessage() {
        //TODO implement
        String errorMessage = "Error happened";
        mViewList.showError(errorMessage);
    }

    private void showPhotoStatisticsInView(PhotoStatistics photoStatistics) {
        mPhotoStatisticsModel = mPhotoStatisticsToPhotoStatisticsModelTransformer.transform(photoStatistics);
        mViewList.renderPhotoStatisticsModel(mPhotoStatisticsModel);
    }

    private void showPhotoListInView(List<Photo> photoList) {