// Path: src/main/java/com/treasuredata/client/model/TDApiErrorMessage.java
// public class TDApiErrorMessage
// {
//     private final String error;
//     private final String text;
//     private final String severity;
//     private final Map<String, Object> details;
// 
//     public TDApiErrorMessage(
//             String error,
//             String text,
//             String severity)
//     {
//         this(error, text, severity, ImmutableMap.<String, Object>of());
//     }
// 
//     @JsonCreator
//     public TDApiErrorMessage(
//             @JsonProperty("error") String error,
//             @JsonProperty("text") String text,
//             @JsonProperty("severity") String severity,
//             @JsonProperty("details") Map<String, Object> details)
//     {
//         this.error = error;
//         this.text = text;
//         this.severity = severity;
//         this.details = details;
//     }
// 
//     public String getError()
//     {
//         return error;
//     }
// 
//     public String getText()
//     {
//         return text;
//     }
// 
//     public String getSeverity()
//     {
//         return severity;
//     }
// 
//     public Map<String, Object> getDetails()
//     {
//         return details;
//     }
// 
//     @Override
//     public String toString()
//     {
//         return String.format("[%s] %s", severity, text);
//     }
// }
// 
// Path: src/main/java/com/treasuredata/client/TDClientHttpTooManyRequestsException.java
// public static final int TOO_MANY_REQUESTS_429 = 429;
// 
// Path: src/main/java/com/treasuredata/client/TDHttpRequestHandler.java
// static class ResponseContext
// {
//     public final TDApiRequest apiRequest;
//     public final Response response;
// 
//     public ResponseContext(TDApiRequest apiRequest, Response response)
//     {
//         this.apiRequest = apiRequest;
//         this.response = response;
//     }
// }


import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.treasuredata.client.model.TDApiErrorMessage;
import okhttp3.Response;
import okhttp3.internal.http2.StreamResetException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLKeyException;
import javax.net.ssl.SSLPeerUnverifiedException;
import java.io.EOFException;
import java.io.IOException;
import java.net.BindException;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.net.PortUnreachableException;
import java.net.ProtocolException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static com.google.common.net.HttpHeaders.RETRY_AFTER;
import static com.treasuredata.client.TDClientException.ErrorType.CLIENT_ERROR;
import static com.treasuredata.client.TDClientException.ErrorType.INVALID_INPUT;
import static com.treasuredata.client.TDClientException.ErrorType.INVALID_JSON_RESPONSE;
import static com.treasuredata.client.TDClientException.ErrorType.PROXY_AUTHENTICATION_FAILURE;
import static com.treasuredata.client.TDClientException.ErrorType.SERVER_ERROR;
import static com.treasuredata.client.TDClientException.ErrorType.UNEXPECTED_RESPONSE_CODE;
import static com.treasuredata.client.TDClientHttpTooManyRequestsException.TOO_MANY_REQUESTS_429;
import static com.treasuredata.client.TDHttpRequestHandler.ResponseContext;
        Map<String, Object> details = errorResponse.getDetails();
        if (details == null) {
            return null;
        }
        Object conflictsWith = details.get("conflicts_with");
        if (conflictsWith == null) {
            return null;
        }
        return String.valueOf(conflictsWith);
    }

    @VisibleForTesting
    public static Optional<TDApiErrorMessage> extractErrorResponse(Response response)
    {
        Optional<String> content = Optional.absent();
        try {
            try {
                content = Optional.of(response.body().string());
            }
            catch (SocketTimeoutException e) {
                // http status was error or not found but failed to get body content
                // handler by status will process further
                return Optional.of(new TDApiErrorMessage(e.getClass().getSimpleName(), e.getMessage(), "error"));
            }
            catch (IOException e) {
                throw new TDClientException(INVALID_JSON_RESPONSE, e);
            }

            if (content.isPresent() && content.get().length() > 0 && content.get().charAt(0) == '{') {
                // Error message from TD API
// Path: src/main/java/com/treasuredata/client/model/TDApiErrorMessage.java
// public class TDApiErrorMessage
// {
//     private final String error;
//     private final String text;
//     private final String severity;
//     private final Map<String, Object> details;
// 
//     public TDApiErrorMessage(
//             String error,
//             String text,
//             String severity)
//     {
//         this(error, text, severity, ImmutableMap.<String, Object>of());
//     }
// 
//     @JsonCreator
//     public TDApiErrorMessage(
//             @JsonProperty("error") String error,
//             @JsonProperty("text") String text,
//             @JsonProperty("severity") String severity,
//             @JsonProperty("details") Map<String, Object> details)
//     {
//         this.error = error;
//         this.text = text;
//         this.severity = severity;
//         this.details = details;
//     }
// 
//     public String getError()
//     {
//         return error;
//     }
// 
//     public String getText()
//     {
//         return text;
//     }
// 
//     public String getSeverity()
//     {
//         return severity;
//     }
// 
//     public Map<String, Object> getDetails()
//     {
//         return details;
//     }
// 
//     @Override
//     public String toString()
//     {
//         return String.format("[%s] %s", severity, text);
//     }
// }
// 
// Path: src/main/java/com/treasuredata/client/TDClientHttpTooManyRequestsException.java
// public static final int TOO_MANY_REQUESTS_429 = 429;
// 
// Path: src/main/java/com/treasuredata/client/TDHttpRequestHandler.java
// static class ResponseContext
// {
//     public final TDApiRequest apiRequest;
//     public final Response response;
// 
//     public ResponseContext(TDApiRequest apiRequest, Response response)
//     {
//         this.apiRequest = apiRequest;
//         this.response = response;
//     }
// }


// Path: src/main/java/com/treasuredata/client/TDRequestErrorHandler.java
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Optional;
import com.treasuredata.client.model.TDApiErrorMessage;
import okhttp3.Response;
import okhttp3.internal.http2.StreamResetException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLKeyException;
import javax.net.ssl.SSLPeerUnverifiedException;
import java.io.EOFException;
import java.io.IOException;
import java.net.BindException;
import java.net.ConnectException;
import java.net.NoRouteToHostException;
import java.net.PortUnreachableException;
import java.net.ProtocolException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import static com.google.common.net.HttpHeaders.RETRY_AFTER;
import static com.treasuredata.client.TDClientException.ErrorType.CLIENT_ERROR;
import static com.treasuredata.client.TDClientException.ErrorType.INVALID_INPUT;
import static com.treasuredata.client.TDClientException.ErrorType.INVALID_JSON_RESPONSE;
import static com.treasuredata.client.TDClientException.ErrorType.PROXY_AUTHENTICATION_FAILURE;
import static com.treasuredata.client.TDClientException.ErrorType.SERVER_ERROR;
import static com.treasuredata.client.TDClientException.ErrorType.UNEXPECTED_RESPONSE_CODE;
import static com.treasuredata.client.TDClientHttpTooManyRequestsException.TOO_MANY_REQUESTS_429;
import static com.treasuredata.client.TDHttpRequestHandler.ResponseContext;

        Map<String, Object> details = errorResponse.getDetails();
        if (details == null) {
            return null;
        }
        Object conflictsWith = details.get("conflicts_with");
        if (conflictsWith == null) {
            return null;
        }
        return String.valueOf(conflictsWith);
    }

    @VisibleForTesting
    public static Optional<TDApiErrorMessage> extractErrorResponse(Response response)
    {
        Optional<String> content = Optional.absent();
        try {
            try {
                content = Optional.of(response.body().string());
            }
            catch (SocketTimeoutException e) {
                // http status was error or not found but failed to get body content
                // handler by status will process further
                return Optional.of(new TDApiErrorMessage(e.getClass().getSimpleName(), e.getMessage(), "error"));
            }
            catch (IOException e) {
                throw new TDClientException(INVALID_JSON_RESPONSE, e);
            }

            if (content.isPresent() && content.get().length() > 0 && content.get().charAt(0) == '{') {
                // Error message from TD API
                return Optional.of(TDHttpClient.defaultObjectMapper.readValue(content.get(), TDApiErrorMessage.class));