package com.box.androidsdk.content.requests;

import com.box.androidsdk.content.BoxException;
import com.box.androidsdk.content.models.BoxFile;
import com.box.androidsdk.content.models.BoxIterator;
import com.box.androidsdk.content.models.BoxIteratorBoxEntity;
import com.box.androidsdk.content.models.BoxIteratorItems;
import com.box.androidsdk.content.models.BoxObject;

import java.net.HttpURLConnection;

/**
 * A request handler that is designed to handle retry logic for a CommitUploadSession to give server
 * time to process all the parts.
 */

public class MultiputResponseHandler extends BoxRequest.BoxRequestHandler<BoxRequestsFile.CommitUploadSession> {

        protected static final int DEFAULT_NUM_RETRIES = 2;
        protected static final int DEFAULT_MAX_WAIT_MILLIS = 90 * 1000;

        protected int mNumAcceptedRetries = 0;
        protected int mRetryAfterMillis = 1000;

    public MultiputResponseHandler(BoxRequestsFile.CommitUploadSession request) {
        super(request);
    }


    @Override
    public <T extends BoxObject> T onResponse(Class<T> clazz, BoxHttpResponse response) throws IllegalAccessException, InstantiationException, BoxException {
            if (response.getResponseCode() == HttpURLConnection.HTTP_ACCEPTED) {
                try {
                    // First attempt to use Retry-After header, all failures will eventually fall back to exponential backoff
                    if (mNumAcceptedRetries < DEFAULT_NUM_RETRIES) {
                        mNumAcceptedRetries++;
                        mRetryAfterMillis = getRetryAfterFromResponse(response, 1);
                    } else if (mRetryAfterMillis < DEFAULT_MAX_WAIT_MILLIS) {
                        // Exponential back off with some randomness to avoid traffic spikes to server
                        mRetryAfterMillis *= (1.5 + Math.random());
                    } else {
                        // Give up after the maximum retry time is exceeded.
                        throw new BoxException.MaxAttemptsExceeded("Max wait time exceeded.", mNumAcceptedRetries);
                    }
                    Thread.sleep(mRetryAfterMillis);
                    return (T) mRequest.send();
                } catch (InterruptedException e) {
                    throw new BoxException(e.getMessage(), response);
                }
            } else {
                BoxIterator list = super.onResponse(BoxIteratorBoxEntity.class, response);
                return (T)list.get(0);
            }
        }
    }