public class DeletedEntity {
} public class FeedChangedInfoEntity {
    private EventType type;
    private String previousChildKey;
    private String key;
    private FeedEntity feedEntity;

    public FeedChangedInfoEntity(EventType type, String previousChildKey, String key, FeedEntity feedEntity) {
        this.type = type;
        this.previousChildKey = previousChildKey;
        this.key = key;
        this.feedEntity = feedEntity;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public EventType getType() {
        return type;
    }

    public void setType(EventType type) {
        this.type = type;
    }

    public String getPreviousChildKey() {
        return previousChildKey;
    }

    public void setPreviousChildKey(String previousChildKey) {
        this.previousChildKey = previousChildKey;
    }

    public FeedEntity getFeedEntity() {
        return feedEntity;
    }

    public void setFeedEntity(FeedEntity feedEntity) {
        this.feedEntity = feedEntity;
    }
} @IgnoreExtraProperties
public class FeedEntity {

    private String title;
    private String body;
    private String image;
    private String key;
    private int index;


    public Map<String, Object> toMap() {
        HashMap<String, Object> result = new HashMap<>();
        result.put("title", title);
        result.put("image", image);
        result.put("body", body);

        return result;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }


    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }
} public class WrittenEntity {
    private String key;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }
} @Singleton
public class FeedEntityDataMapper {


    @Inject
    public FeedEntityDataMapper(){

    }

    public Feed transform(FeedEntity entity){
        Feed feed = new Feed();

        feed.setImage(entity.getImage());
        feed.setBody(entity.getBody());
        feed.setTitle(entity.getTitle());
        feed.setIndex(entity.getIndex());
        feed.setKey(entity.getKey());

        return feed;
    }


    public FeedChangedInfo transform(FeedChangedInfoEntity entity){
        FeedChangedInfo result = new FeedChangedInfo();
        result.setPreviousChildKey(entity.getPreviousChildKey());
        result.setFeed(transform(entity.getFeedEntity()));
        result.setKey(entity.getKey());

        switch (entity.getType()){
            case Added:
                result.setType(FeedChangedInfo.EventType.Added);
                break;
            case Changed:
                result.setType(FeedChangedInfo.EventType.Changed);
                break;
            case Moved:
                result.setType(FeedChangedInfo.EventType.Moved);
                break;

            case Removed:
                result.setType(FeedChangedInfo.EventType.Removed);
                break;
        }

        return result;
    }

    public Written transform(WrittenEntity entity){
        Written result = new Written();
        // maybe add data later
        return result;
    }


    public Deleted transform(DeletedEntity entity){
        Deleted result = new Deleted();
        // maybe add data later
        return result;
    }



    public FeedEntity transform(Feed feed){
        FeedEntity entity = new FeedEntity();

        entity.setTitle(feed.getTitle());
        entity.setImage(feed.getImage());
        entity.setBody(feed.getBody());
        return entity;
    }

} @Singleton
public class FeedDataSourceFactory {
    private final Context context;
    private final FeedCache cache;

    FeedDataSourceCloud feedDataSourceCloud;

    @Inject
    public FeedDataSourceFactory(@NonNull Context context, @NonNull FeedCache cache) {
        this.context = context.getApplicationContext();
        this.cache = cache;
    }


    public FeedDataSource create() {
        if (OSUtil.isNetworkAvailable(context)) {
            return createCloudDataSource();
        } else {
            return createDiskDataSource();
        }

    }

    public FeedDataSource createDiskDataSource() {
        return new FeedDataSourceDisk(cache);
    }

    public FeedDataSource createCloudDataSource() {
        if(feedDataSourceCloud == null) {
            DatabaseReference databse = FirebaseDatabase.getInstance().getReference();
            Firebase fireBase = new FirebaseImpl(databse);
            feedDataSourceCloud = new FeedDataSourceCloud(fireBase);
        }

        return feedDataSourceCloud;
    }


} public class Deleted {
} public class Feed {
    private String title;
    private String body;
    private String image;
    private String key;
    private int index;

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }

    public String getImage() {
        return image;
    }

    public void setImage(String image) {
        this.image = image;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }
} public class FeedChangedInfo {
    public enum EventType { Added, Changed, Removed, Moved }

    private EventType type;
    private String previousChildKey;
    private String key;
    private Feed feed;

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public EventType getType() {
        return type;
    }

    public void setType(EventType type) {
        this.type = type;
    }

    public String getPreviousChildKey() {
        return previousChildKey;
    }

    public void setPreviousChildKey(String previousChildKey) {
        this.previousChildKey = previousChildKey;
    }

    public Feed getFeed() {
        return feed;
    }

    public void setFeed(Feed feed) {
        this.feed = feed;
    }
} public class Written {
} public interface FeedRepository {

    public Observable<FeedChangedInfo> registerFeedChangedEvent();

    public Observable<Written> writeFeed(Feed feed);

    public Observable<Deleted> deleteFeed(String key);

}
import com.mike.feed.data.entity.DeletedEntity;
import com.mike.feed.data.entity.FeedChangedInfoEntity;
import com.mike.feed.data.entity.FeedEntity;
import com.mike.feed.data.entity.WrittenEntity;
import com.mike.feed.data.entity.mapper.FeedEntityDataMapper;
import com.mike.feed.data.repository.datasource.FeedDataSourceFactory;
import com.mike.feed.domain.Deleted;
import com.mike.feed.domain.Feed;
import com.mike.feed.domain.FeedChangedInfo;
import com.mike.feed.domain.Written;
import com.mike.feed.domain.repository.FeedRepository;
import javax.inject.Inject;
import javax.inject.Singleton;
import rx.Observable;
import rx.functions.Func1;
import timber.log.Timber;
package com.mike.feed.data.repository;




/**
 * Created by MinhNguyen on 8/24/16.
 */

@Singleton
public class FeedDataRepository implements FeedRepository {


    private final FeedDataSourceFactory factory;
    private final FeedEntityDataMapper mapper;

    @Inject
    public FeedDataRepository(FeedDataSourceFactory factory, FeedEntityDataMapper mapper) {
        this.factory = factory;
        this.mapper = mapper;
    }


    @Override
    public Observable<FeedChangedInfo> registerFeedChangedEvent() {
        Timber.v(String.format("registerFeedChangedEvent : %s", Thread.currentThread().getName()));
        return factory.createCloudDataSource().registerFeedChangedEvent().map(new Func1<FeedChangedInfoEntity, FeedChangedInfo>() {
            @Override
            public FeedChangedInfo call(FeedChangedInfoEntity entity) {
                Timber.v(String.format("mapping : %s", Thread.currentThread().getName()));
                return mapper.transform(entity);
            }
        });
    }

    @Override
    public Observable<Written> writeFeed(Feed feed) {
        return factory.createCloudDataSource().writeFeed(mapper.transform(feed)).map(new Func1<WrittenEntity, Written>() {