// Path: library/src/main/java/com/siu/android/volleyball/exception/BallException.java
// public class BallException extends RuntimeException {
// 
//     public BallException() {
//     }
// 
//     public BallException(String detailMessage) {
//         super(detailMessage);
//     }
// 
//     public BallException(String detailMessage, Object... args) {
//         super(String.format(detailMessage, args));
//     }
// 
// 
// 
//     public BallException(String detailMessage, Throwable throwable) {
//         super(detailMessage, throwable);
//     }
// 
//     public BallException(Throwable throwable) {
//         super(throwable);
//     }
// }
// 
// Path: library/src/main/java/com/siu/android/volleyball/local/LocalRequestProcessor.java
// public interface LocalRequestProcessor<T> {
// 
//     public abstract T getLocalResponse();
// 
//     public abstract void saveLocalResponse(T response);
// 
// 
// }
// 
// Path: library/src/main/java/com/siu/android/volleyball/network/NetworkRequestProcessor.java
// public interface NetworkRequestProcessor<T> {
// 
//     public abstract BallResponse<T> parseNetworkResponse(NetworkResponse networkResponse);
// }
// 
// Path: library/src/main/java/com/siu/android/volleyball/response/ResponseListener.java
// public interface ResponseListener<T> {
// 
//     public void onIntermediateResponse(T response, BallResponse.ResponseSource responseSource);
// 
//     public void onFinalResponse(T response, BallResponse.ResponseSource responseSource);
// 
//     public void onFinalResponseIdenticalToIntermediate(BallResponse.ResponseSource responseSource);
// }


import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.VolleyLog;
import com.siu.android.volleyball.exception.BallException;
import com.siu.android.volleyball.local.LocalRequestProcessor;
import com.siu.android.volleyball.network.NetworkRequestProcessor;
import com.siu.android.volleyball.response.ResponseListener;
package com.siu.android.volleyball;



/**
 * Created by lukas on 8/29/13.
 */
public abstract class BallRequest<T> extends Request<T> {

    /* Private fields from Request class */
    protected static final long SLOW_REQUEST_THRESHOLD_MS = 3000;
    protected final BallMarkerLog mEventLog = BallMarkerLog.ENABLED ? new BallMarkerLog() : null;
    protected long mRequestBirthTime = 0;
    protected BallRequestQueue mRequestQueue;


    /* Additionnal logic from Ball */
    protected LocalRequestProcessor<T> mLocalRequestProcessor;
    protected NetworkRequestProcessor<T> mNetworkRequestProcessor;
    protected ResponseListener mResponseListener;

    /**
     * Error from final response, stored and used later if intermediate response is still to be delivered:
     * If intermediate response is delivered after with no response, deliver the final error
     */
    private VolleyError mFinalResponseError;

    protected boolean mFinalResponseDelivered = false;

    /**
     * Intermediate response of the request has been delivered.
     * <p/>
     * Several use cases:
     * - In the executor delivery to consider only the 1st intermediate request and ignore the 2nd one.
     * - REMOVED FOR NOW, NOT VOLATILE -- In the network dispatcher to return identical response in case of 304 not modified response
     * and if a valid intermediate response was returned. Must be volatile because it can apply between
     * local and network thread.
     */
    protected boolean mIntermediateResponseDelivered = false;

    /**
     * Request is finished and no more response should be delivered
     * Volatile because it is used to determine if a marker should be added to the log,
     * and value need to be synchronized between all worker threads
     */
    protected volatile boolean mFinished = false;

    private boolean mLocalIntermediateResponseDelivered = false;
    private boolean mCacheIntermediateResponseDelivered = false;
    private boolean mIntermediateResponseDeliveredWithSuccess = false;


    protected BallRequest(int method, String url, Response.ErrorListener errorListener) {
        super(method, url, errorListener);

        if (shouldProcessLocal()) {
            mLocalRequestProcessor = createLocalRequestProcessor();

            if (mLocalRequestProcessor == null) {
// Path: library/src/main/java/com/siu/android/volleyball/exception/BallException.java
// public class BallException extends RuntimeException {
// 
//     public BallException() {
//     }
// 
//     public BallException(String detailMessage) {
//         super(detailMessage);
//     }
// 
//     public BallException(String detailMessage, Object... args) {
//         super(String.format(detailMessage, args));
//     }
// 
// 
// 
//     public BallException(String detailMessage, Throwable throwable) {
//         super(detailMessage, throwable);
//     }
// 
//     public BallException(Throwable throwable) {
//         super(throwable);
//     }
// }
// 
// Path: library/src/main/java/com/siu/android/volleyball/local/LocalRequestProcessor.java
// public interface LocalRequestProcessor<T> {
// 
//     public abstract T getLocalResponse();
// 
//     public abstract void saveLocalResponse(T response);
// 
// 
// }
// 
// Path: library/src/main/java/com/siu/android/volleyball/network/NetworkRequestProcessor.java
// public interface NetworkRequestProcessor<T> {
// 
//     public abstract BallResponse<T> parseNetworkResponse(NetworkResponse networkResponse);
// }
// 
// Path: library/src/main/java/com/siu/android/volleyball/response/ResponseListener.java
// public interface ResponseListener<T> {
// 
//     public void onIntermediateResponse(T response, BallResponse.ResponseSource responseSource);
// 
//     public void onFinalResponse(T response, BallResponse.ResponseSource responseSource);
// 
//     public void onFinalResponseIdenticalToIntermediate(BallResponse.ResponseSource responseSource);
// }


// Path: library/src/main/java/com/siu/android/volleyball/BallRequest.java
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.VolleyLog;
import com.siu.android.volleyball.exception.BallException;
import com.siu.android.volleyball.local.LocalRequestProcessor;
import com.siu.android.volleyball.network.NetworkRequestProcessor;
import com.siu.android.volleyball.response.ResponseListener;

package com.siu.android.volleyball;



/**
 * Created by lukas on 8/29/13.
 */
public abstract class BallRequest<T> extends Request<T> {

    /* Private fields from Request class */
    protected static final long SLOW_REQUEST_THRESHOLD_MS = 3000;
    protected final BallMarkerLog mEventLog = BallMarkerLog.ENABLED ? new BallMarkerLog() : null;
    protected long mRequestBirthTime = 0;
    protected BallRequestQueue mRequestQueue;


    /* Additionnal logic from Ball */
    protected LocalRequestProcessor<T> mLocalRequestProcessor;
    protected NetworkRequestProcessor<T> mNetworkRequestProcessor;
    protected ResponseListener mResponseListener;

    /**
     * Error from final response, stored and used later if intermediate response is still to be delivered:
     * If intermediate response is delivered after with no response, deliver the final error
     */
    private VolleyError mFinalResponseError;

    protected boolean mFinalResponseDelivered = false;

    /**
     * Intermediate response of the request has been delivered.
     * <p/>
     * Several use cases:
     * - In the executor delivery to consider only the 1st intermediate request and ignore the 2nd one.
     * - REMOVED FOR NOW, NOT VOLATILE -- In the network dispatcher to return identical response in case of 304 not modified response
     * and if a valid intermediate response was returned. Must be volatile because it can apply between
     * local and network thread.
     */
    protected boolean mIntermediateResponseDelivered = false;

    /**
     * Request is finished and no more response should be delivered
     * Volatile because it is used to determine if a marker should be added to the log,
     * and value need to be synchronized between all worker threads
     */
    protected volatile boolean mFinished = false;

    private boolean mLocalIntermediateResponseDelivered = false;
    private boolean mCacheIntermediateResponseDelivered = false;
    private boolean mIntermediateResponseDeliveredWithSuccess = false;


    protected BallRequest(int method, String url, Response.ErrorListener errorListener) {
        super(method, url, errorListener);

        if (shouldProcessLocal()) {
            mLocalRequestProcessor = createLocalRequestProcessor();

            if (mLocalRequestProcessor == null) {
                throw new BallException("Request should process local but local request processor is not provided");