package com.filestack.util;

import retrofit2.Response;

import java.io.IOException;

public abstract class RetryNetworkFunc<T> {
    private final int maxNetworkRetries;
    private final int maxServerRetries;
    private final int delayBase;

    private int networkRetries;
    private int serverRetries;

    public RetryNetworkFunc(int maxNetworkRetries, int maxServerRetries, int delayBase) {
        this.maxNetworkRetries = maxNetworkRetries;
        this.maxServerRetries = maxServerRetries;
        this.delayBase = delayBase;
    }

    public T call() throws IOException {
        Response response = run();
        return process(response);
    }

    Response run() throws IOException {
        Response response;

        try {
            response = work();
        } catch (IOException e) {
            response = retryNetwork();
        }

        if (response.code() != 200)
            response = retryServer(response.code());

        return response;
    }

    abstract Response work() throws IOException;

    Response retryNetwork() throws IOException {
        if (networkRetries >= maxNetworkRetries)
            throw new IOException("Upload failed: Network unusable");

        if (delayBase > 0)
            try {
                Thread.sleep((long) Math.pow(delayBase, networkRetries) * 1000);
            } catch (InterruptedException e) {
                networkRetries++;
            }

        networkRetries++;
        return run();
    }

    Response retryServer(int code)  throws IOException {
        if (code == 206 || code == 400 || code == 403 || serverRetries >= maxServerRetries)
            throw new IOException("Upload failed: " + code);

        if (delayBase > 0)
            try {
                Thread.sleep((long) Math.pow(delayBase, serverRetries) * 1000);
            } catch (InterruptedException e) {
                serverRetries++;
            }

        serverRetries++;
        return run();
    }

    @SuppressWarnings("unchecked")
    T process(Response response) {
        return (T) response.body();
    }

    public int getNetworkRetries() {
        return networkRetries;
    }

    public int getServerRetries() {
        return serverRetries;
    }
}

@@ -33,57 +33,169 @@
 ort 
-retrofit2.Response;%0A%0Aimport java.io.IOException;%0A
+java.io.IOException;%0Aimport retrofit2.Response;%0A%0A/**%0A * Abstract class to generalize retry logic of a network call.%0A *%0A * @param %3CT%3E type of object to return%0A */
 %0Apub
@@ -414,16 +414,483 @@
 tries;%0A%0A
+    /**%0A     * Constructs an instance following the given settings.%0A     * The network call is made in %7B@link #work()%7D.%0A     * Override %7B@link #process(Response)%7D to customize parsing the response.%0A     *%0A     * @param maxNetworkRetries times to retry after a network failure%0A     * @param maxServerRetries times to retry after an error response from the server%0A     * @param delayBase base value for exponential backoff, delay (seconds) == base %5E retryCount%0A     */%0A
     publ
@@ -1465,16 +1465,18 @@
  != 200)
+ %7B
 %0A       
@@ -1520,16 +1520,26 @@
 code());
+%0A        %7D
 %0A%0A      
@@ -1703,32 +1703,34 @@
 xNetworkRetries)
+ %7B
 %0A            thr
@@ -1783,16 +1783,26 @@
 sable%22);
+%0A        %7D
 %0A%0A      
@@ -1813,32 +1813,34 @@
  (delayBase %3E 0)
+ %7B
 %0A            try
@@ -2009,32 +2009,42 @@
 +;%0A            %7D
+%0A        %7D
 %0A%0A        networ
@@ -2232,16 +2232,18 @@
 Retries)
+ %7B
 %0A       
@@ -2295,16 +2295,26 @@
 + code);
+%0A        %7D
 %0A%0A      
@@ -2333,16 +2333,18 @@
 ase %3E 0)
+ %7B
 %0A       
@@ -2519,32 +2519,42 @@
 +;%0A            %7D
+%0A        %7D
 %0A%0A        server

Fix linter warnings for RetryNetworkFunc