package reqs;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by maksing on 14/6/15.
 * Wrap a Request instance. Every Session instance is unique in a Reqs object.
 */
public class RequestSession {
    private final Request request;
    private Reqs reqs;
    private Reqs subReqs;
    private final int id;

    private AtomicInteger currentRetryCount = new AtomicInteger(0);

    private volatile boolean isDone = false;

    /**
     * Constructor of the session
     * @param id a generated new id for the request session
     * @param reqs the current Reqs instance
     * @param request the request to be called in this session
     * @see Request
     */
    public RequestSession(int id, Reqs reqs, Request request) {
        this.reqs = reqs;
        this.request = request;
        this.id = id;
    }

    /**
     * return the request session id
     * @return the request session id
     */
    public int getId() {
        return id;
    }

    /**
     * Mark this request session as done
     * @param data the responded data
     */
    public synchronized void done(Object data) {
        if (!isDone) {
            isDone = true;
            reqs.requestDone(this, data);
        } else {
            throw new IllegalStateException("the session is done already!");
        }
    }

    /**
     * Mark this request session as failure, the flow will be interrupted and won't continue.
     * @param data the error response data
     */
    public synchronized void fail(Object data) {
        if (!isDone) {
            isDone = true;
            reqs.requestFailed(this, data);
        } else {
            throw new IllegalStateException("the session is done already!");
        }
    }

    /**
     * try to do the request again. be careful not to block the app by keep calling this function.
     */
    public void retry(Object errorData) {
        if (request.getMaxRetryCount() == 0) {
            call();
        } else if (currentRetryCount.get() < request.getMaxRetryCount()) {
            fail(errorData);
        }
    }

    public synchronized void failNoRetry(Object data) {
        currentRetryCount.set(request.getMaxRetryCount());
        fail(data);
    }

    synchronized void resumeNext() {
        request.onNext(this, reqs.getResponseById(id));
    }

    void resumeSubReqs() {
        if (subReqs != null) {
            subReqs.resume();
        }
    }

    void pauseSubReqs() {
        if (subReqs != null && request.pausable) {
            subReqs.pause();
        }
    }

    void cancelSubReqs() {
        if (subReqs != null) {
            subReqs.cancel();
        }
    }

    public Request getRequest() {
        return request;
    }

    void next(final Response response) {
        request.onNext(this, response);
    }

    synchronized void call() {
        request.onCall(this);
    }

    public Reqs getReqs() {
        return reqs;
    }

    public int getRetryCount() {
        return currentRetryCount.get();
    }

    /**
     * set new retry count
     * @param currentRetryCount
     */
    public void setCurrentRetryCount(int currentRetryCount) {
        this.currentRetryCount.set(currentRetryCount);
    }

    void currentRetryCountAddOne() {
        this.currentRetryCount.getAndAdd(1);
    }

    public <T> T getLastStepData(Class<T> c) {
        return reqs.getLastStepData(c);
    }

    public <T> List<T> getLastStepDataList(Class<T> c) {
        return reqs.getLastStepDataList(c);
    }

    public Reqs getLastStepReqs() {
        return reqs.getLastStepData(Reqs.class);
    }

    void setSubReqs(Reqs subReqs) {
        this.subReqs = subReqs;
    }
}

@@ -1467,16 +1467,104 @@
 continue
+ when%0A     * the max retry count is 0, but it will retry again if max retry count is %3E 0
 .%0A     *
@@ -2015,24 +2015,51 @@
 rrorData) %7B%0A
+        if (!isDone) %7B%0A    
         if (
@@ -2105,16 +2105,20 @@
         
+    
 call();%0A
@@ -2121,24 +2121,28 @@
 ();%0A        
+   
+ 
 %7D else if (c
@@ -2204,24 +2204,28 @@
             
+    
 fail(errorDa
@@ -2225,24 +2225,38 @@
 errorData);%0A
+            %7D%0A
         %7D%0A  
@@ -2394,32 +2394,251 @@
 l(data);%0A    %7D%0A%0A
+    public boolean isLastRetry() %7B%0A        if (request.getMaxRetryCount() %3E 0) %7B%0A            return currentRetryCount.get() %3E= request.getMaxRetryCount() - 1;%0A        %7D else %7B%0A            return false;%0A        %7D%0A    %7D%0A%0A
     synchronized

update retry function.