package com.crossbow.volley;
import android.support.annotation.NonNull;
import com.android.volley.Request;
import com.android.volley.VolleyError;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.ByteArrayPool;
import java.io.File;
import java.util.LinkedList;
/**
*/
public abstract class FileRequest<T> implements Comparable<FileRequest>{
private MarkerLog markerLog = new MarkerLog();
private boolean canceled;
/**
* path to the file on disk
*/
private String filePath;
/**
* Error listener for errors
*/
private FileResponse.ErrorListener errorListener;
/**
* Request number, used by file queue
*/
private int sequence;
/**
* FileQueue the file queue that the request is a part of
*/
private FileQueue fileQueue;
/**
* ByteArrayPool the byte array pool used for reading and writing
*/
private ByteArrayPool byteArrayPool;
/**
* Tag used to cancel a request
*/
private Object tag;
/**
* DEFAULT_BUFFER_SIZE
*/
private static int DEFAULT_BUFFER_SIZE = 4096;
/**
* The Priority of the request. This is used to order the requests in the queue. Same {@link Request.Priority Priority}
*/
public Request.Priority getPriority() {
return Request.Priority.NORMAL;
}
public void setByteArrayPool(ByteArrayPool byteArrayPool) {
this.byteArrayPool = byteArrayPool;
}
/**
* Creates a new file request to the file path
*/
public FileRequest(String filePath, FileResponse.ErrorListener errorListener) {
if(filePath == null) {
throw new IllegalArgumentException("File Path cant be null");
}
this.errorListener = errorListener;
this.filePath = filePath;
}
public abstract FileResponse<T> doFileWork(File file) throws VolleyError;
public final void preformDelivery(FileResponse<T> response) {
deliverResult(response.data);
}
public final void preformError(VolleyError volleyError) {
deliverError(volleyError);
}
/**
* The path to the file for this request
* @return the file path
*/
public String getFilePath() {
return filePath;
}
protected void deliverError(VolleyError error) {
if(errorListener != null) {
errorListener.onErrorResponse(error);
}
}
/**
* Mark this request as canceled
*/
public void cancel() {
this.canceled = true;
}
protected void setFileQueue(FileQueue fileQueue) {
this.fileQueue = fileQueue;
}
/**
* @return true if a request is canceled
*/
public boolean isCanceled() {
return canceled;
}
/**
* @return the tag for this request
*/
public Object getTag() {
return tag;
}
/**
* Sets the tag for this request, Used to cancel requests already in flight
* @param tag the tag to set
*/
public void setTag(Object tag) {
this.tag = tag;
}
/**
* set the sequence number (Used for ordering)
* @param sequence the sequence number
*/
public void sequence(int sequence) {
this.sequence = sequence;
}
/**
* get the sequence number
*/
public int getSequence() {
return sequence;
}
public void mark(String message) {
markerLog.addMark(message);
}
@Override
public int compareTo(@NonNull FileRequest another) {
Request.Priority left = this.getPriority();
Request.Priority right = another.getPriority();
// High-priority requests are "lesser" so they are sorted to the front.
// Equal priorities are sorted by sequence number to provide FIFO ordering.
return left == right ?
getSequence() - another.getSequence() :
right.ordinal() - left.ordinal();
}
protected void finish() {
VolleyLog.d(getFilePath());
markerLog.log();
fileQueue.finishRequest(this);
}
protected abstract void deliverResult(T result);
private static class MarkerLog {
private LinkedList<Marker> markers = new LinkedList<>();
private static final Object LOCK = new Object();
public void log() {
synchronized (LOCK) {
long startTime = 0;
for (int i = 0; i < markers.size(); i++) {
Marker marker = markers.get(i);
if(i == 0) {
marker.log(0);
}
else {
double diff = (Math.abs(startTime - marker.time)) / 1000f;
marker.log(diff);
}
startTime = marker.time;
}
}
}
public void addMark(String message) {
Marker marker = new Marker(message);
synchronized (LOCK) {
markers.add(marker);
}
}
private static class Marker {
private long time;
private String msg;
public Marker(String msg) {
time = System.nanoTime() / 1000;
this.msg = msg;
}
public void log(double timeDiff) {
VolleyLog.d("(+%-4.3f)ms %s", timeDiff, msg);
}
}
}
}