// Path: app/src/main/java/com/example/offline/domain/services/SyncCommentRxBus.java
// public class SyncCommentRxBus {
// 
//     private static SyncCommentRxBus instance;
//     private final PublishRelay<SyncCommentResponse> relay;
// 
//     public static synchronized SyncCommentRxBus getInstance() {
//         if (instance == null) {
//             instance = new SyncCommentRxBus();
//         }
//         return instance;
//     }
// 
//     private SyncCommentRxBus() {
//         relay = PublishRelay.create();
//     }
// 
//     public void post(SyncResponseEventType eventType, Comment comment) {
//         relay.accept(new SyncCommentResponse(eventType, comment));
//     }
// 
//     public Observable<SyncCommentResponse> toObservable() {
//         return relay;
//     }
// }
// 
// Path: app/src/main/java/com/example/offline/domain/services/SyncResponseEventType.java
// public enum SyncResponseEventType {
//     SUCCESS,
//     FAILED
// }
// 
// Path: app/src/main/java/com/example/offline/model/Comment.java
// @Entity
// public class Comment implements Serializable {
// 
//     @PrimaryKey(autoGenerate = true)
//     private long id;
// 
//     @ColumnInfo(name = "photo_id")
//     private long photoId;
// 
//     @SerializedName("body")
//     @ColumnInfo(name = "comment_text")
//     private String commentText;
// 
//     @ColumnInfo(name = "timestamp")
//     private long timestamp;
// 
//     @ColumnInfo(name = "sync_pending")
//     private boolean syncPending;
// 
//     public long getId() {
//         return id;
//     }
// 
//     public long getPhotoId() {
//         return photoId;
//     }
// 
//     public String getCommentText() {
//         return commentText;
//     }
// 
//     public long getTimestamp() {
//         return timestamp;
//     }
// 
//     public boolean isSyncPending() {
//         return syncPending;
//     }
// 
//     @Ignore
//     public Comment(long photoId, String commentText) {
//         this.photoId = photoId;
//         this.commentText = commentText;
//         this.timestamp = System.currentTimeMillis();
//         this.syncPending = true;
//     }
// 
//     public Comment(long id, long photoId, String commentText, long timestamp, boolean syncPending) {
//         this.id = id;
//         this.photoId = photoId;
//         this.commentText = commentText;
//         this.timestamp = timestamp;
//         this.syncPending = syncPending;
//     }
// 
//     @Override
//     public String toString() {
//         return String.format("Comment id: %s, text: %s, syncPending: %s", id, commentText, syncPending);
//     }
// }
// 
// Path: app/src/main/java/com/example/offline/model/CommentUtils.java
// public class CommentUtils {
//     public static Comment clone(Comment from, boolean syncPending) {
//         return new Comment(from.getId(), from.getPhotoId(), from.getCommentText(),
//                 from.getTimestamp(), syncPending);
//     }
// 
//     public static Comment clone(Comment from, long id) {
//         return new Comment(id, from.getPhotoId(), from.getCommentText(),
//                 from.getTimestamp(), from.isSyncPending());
//     }
// }
// 
// Path: app/src/main/java/com/example/offline/domain/services/networking/RemoteCommentService.java
// public final class RemoteCommentService {
// 
//     private static RemoteCommentService instance;
// 
//     private final Retrofit retrofit;
// 
//     public RemoteCommentService() {
// 
//         HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
//         loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
// 
//         OkHttpClient httpClient = new OkHttpClient.Builder()
//                 .addInterceptor(loggingInterceptor)
//                 .build();
// 
//         Gson gson = new GsonBuilder()
//                 .excludeFieldsWithoutExposeAnnotation()
//                 .create();
// 
//         retrofit = new Retrofit.Builder()
//                 .client(httpClient)
//                 .baseUrl(BuildConfig.API_BASE_URL)
//                 .addConverterFactory(GsonConverterFactory.create(gson))
//                 .build();
//     }
// 
//     public static synchronized RemoteCommentService getInstance() {
//         if (instance == null) {
//             instance = new RemoteCommentService();
//         }
//         return instance;
//     }
// 
//     public void addComment(Comment comment) throws IOException, RemoteException {
//         RemoteCommentEndpoint service = retrofit.create(RemoteCommentEndpoint.class);
// 
//         // Remote call can be executed synchronously since the job calling it is already backgrounded.
//         Response<Comment> response = service.addComment(comment).execute();
// 
//         if (response == null || !response.isSuccessful() || response.errorBody() != null) {
//             throw new RemoteException(response);
//         }
// 
//         Timber.d("successful remote response: " + response.body());
//     }
// }
// 
// Path: app/src/main/java/com/example/offline/domain/services/networking/RemoteException.java
// public class RemoteException extends Exception {
// 
//     private final Response response;
// 
//     public RemoteException(Response response) {
//         this.response = response;
//     }
// 
//     public Response getResponse() {
//         return response;
//     }
// }


import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.birbit.android.jobqueue.Job;
import com.birbit.android.jobqueue.Params;
import com.birbit.android.jobqueue.RetryConstraint;
import com.example.offline.domain.services.SyncCommentRxBus;
import com.example.offline.domain.services.SyncResponseEventType;
import com.example.offline.model.Comment;
import com.example.offline.model.CommentUtils;
import com.example.offline.domain.services.networking.RemoteCommentService;
import com.example.offline.domain.services.networking.RemoteException;
import timber.log.Timber;
package com.example.offline.domain.services.jobs;




public class SyncCommentJob extends Job {

    private static final String TAG = SyncCommentJob.class.getCanonicalName();
    private final Comment comment;

    public SyncCommentJob(Comment comment) {
        super(new Params(JobPriority.MID)
                .requireNetwork()
                .groupBy(TAG)
                .persist());
        this.comment = comment;
    }

    @Override
    public void onAdded() {
        Timber.d("Executing onAdded() for comment " + comment);
    }

    @Override
    public void onRun() throws Throwable {
// Path: app/src/main/java/com/example/offline/domain/services/SyncCommentRxBus.java
// public class SyncCommentRxBus {
// 
//     private static SyncCommentRxBus instance;
//     private final PublishRelay<SyncCommentResponse> relay;
// 
//     public static synchronized SyncCommentRxBus getInstance() {
//         if (instance == null) {
//             instance = new SyncCommentRxBus();
//         }
//         return instance;
//     }
// 
//     private SyncCommentRxBus() {
//         relay = PublishRelay.create();
//     }
// 
//     public void post(SyncResponseEventType eventType, Comment comment) {
//         relay.accept(new SyncCommentResponse(eventType, comment));
//     }
// 
//     public Observable<SyncCommentResponse> toObservable() {
//         return relay;
//     }
// }
// 
// Path: app/src/main/java/com/example/offline/domain/services/SyncResponseEventType.java
// public enum SyncResponseEventType {
//     SUCCESS,
//     FAILED
// }
// 
// Path: app/src/main/java/com/example/offline/model/Comment.java
// @Entity
// public class Comment implements Serializable {
// 
//     @PrimaryKey(autoGenerate = true)
//     private long id;
// 
//     @ColumnInfo(name = "photo_id")
//     private long photoId;
// 
//     @SerializedName("body")
//     @ColumnInfo(name = "comment_text")
//     private String commentText;
// 
//     @ColumnInfo(name = "timestamp")
//     private long timestamp;
// 
//     @ColumnInfo(name = "sync_pending")
//     private boolean syncPending;
// 
//     public long getId() {
//         return id;
//     }
// 
//     public long getPhotoId() {
//         return photoId;
//     }
// 
//     public String getCommentText() {
//         return commentText;
//     }
// 
//     public long getTimestamp() {
//         return timestamp;
//     }
// 
//     public boolean isSyncPending() {
//         return syncPending;
//     }
// 
//     @Ignore
//     public Comment(long photoId, String commentText) {
//         this.photoId = photoId;
//         this.commentText = commentText;
//         this.timestamp = System.currentTimeMillis();
//         this.syncPending = true;
//     }
// 
//     public Comment(long id, long photoId, String commentText, long timestamp, boolean syncPending) {
//         this.id = id;
//         this.photoId = photoId;
//         this.commentText = commentText;
//         this.timestamp = timestamp;
//         this.syncPending = syncPending;
//     }
// 
//     @Override
//     public String toString() {
//         return String.format("Comment id: %s, text: %s, syncPending: %s", id, commentText, syncPending);
//     }
// }
// 
// Path: app/src/main/java/com/example/offline/model/CommentUtils.java
// public class CommentUtils {
//     public static Comment clone(Comment from, boolean syncPending) {
//         return new Comment(from.getId(), from.getPhotoId(), from.getCommentText(),
//                 from.getTimestamp(), syncPending);
//     }
// 
//     public static Comment clone(Comment from, long id) {
//         return new Comment(id, from.getPhotoId(), from.getCommentText(),
//                 from.getTimestamp(), from.isSyncPending());
//     }
// }
// 
// Path: app/src/main/java/com/example/offline/domain/services/networking/RemoteCommentService.java
// public final class RemoteCommentService {
// 
//     private static RemoteCommentService instance;
// 
//     private final Retrofit retrofit;
// 
//     public RemoteCommentService() {
// 
//         HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
//         loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
// 
//         OkHttpClient httpClient = new OkHttpClient.Builder()
//                 .addInterceptor(loggingInterceptor)
//                 .build();
// 
//         Gson gson = new GsonBuilder()
//                 .excludeFieldsWithoutExposeAnnotation()
//                 .create();
// 
//         retrofit = new Retrofit.Builder()
//                 .client(httpClient)
//                 .baseUrl(BuildConfig.API_BASE_URL)
//                 .addConverterFactory(GsonConverterFactory.create(gson))
//                 .build();
//     }
// 
//     public static synchronized RemoteCommentService getInstance() {
//         if (instance == null) {
//             instance = new RemoteCommentService();
//         }
//         return instance;
//     }
// 
//     public void addComment(Comment comment) throws IOException, RemoteException {
//         RemoteCommentEndpoint service = retrofit.create(RemoteCommentEndpoint.class);
// 
//         // Remote call can be executed synchronously since the job calling it is already backgrounded.
//         Response<Comment> response = service.addComment(comment).execute();
// 
//         if (response == null || !response.isSuccessful() || response.errorBody() != null) {
//             throw new RemoteException(response);
//         }
// 
//         Timber.d("successful remote response: " + response.body());
//     }
// }
// 
// Path: app/src/main/java/com/example/offline/domain/services/networking/RemoteException.java
// public class RemoteException extends Exception {
// 
//     private final Response response;
// 
//     public RemoteException(Response response) {
//         this.response = response;
//     }
// 
//     public Response getResponse() {
//         return response;
//     }
// }


// Path: app/src/main/java/com/example/offline/domain/services/jobs/SyncCommentJob.java
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import com.birbit.android.jobqueue.Job;
import com.birbit.android.jobqueue.Params;
import com.birbit.android.jobqueue.RetryConstraint;
import com.example.offline.domain.services.SyncCommentRxBus;
import com.example.offline.domain.services.SyncResponseEventType;
import com.example.offline.model.Comment;
import com.example.offline.model.CommentUtils;
import com.example.offline.domain.services.networking.RemoteCommentService;
import com.example.offline.domain.services.networking.RemoteException;
import timber.log.Timber;

package com.example.offline.domain.services.jobs;




public class SyncCommentJob extends Job {

    private static final String TAG = SyncCommentJob.class.getCanonicalName();
    private final Comment comment;

    public SyncCommentJob(Comment comment) {
        super(new Params(JobPriority.MID)
                .requireNetwork()
                .groupBy(TAG)
                .persist());
        this.comment = comment;
    }

    @Override
    public void onAdded() {
        Timber.d("Executing onAdded() for comment " + comment);
    }

    @Override
    public void onRun() throws Throwable {
        Timber.d("Executing onRun() for comment " + comment);