package com.filestack;

import com.filestack.errors.InternalException;
import com.filestack.errors.InvalidParameterException;
import com.filestack.errors.PolicySignatureException;
import com.filestack.errors.ResourceNotFoundException;
import com.filestack.errors.ValidationException;
import com.filestack.transforms.ImageTransform;
import com.filestack.util.FsService;
import com.filestack.util.Upload;
import com.filestack.util.Util;
import io.reactivex.Flowable;
import java.io.IOException;

/** Uploads new files. */
public class FilestackClient {
  private String apiKey;
  private Security security;
  private FsService fsService;

  /**
   * Constructs a client without security.
   *
   * @param apiKey account key from the dev portal
   */
  public FilestackClient(String apiKey) {
    this(apiKey, null);
  }

  /**
   * Constructs a client with security.
   *
   * @param apiKey   account key from the dev portal
   * @param security configured security object
   */
  public FilestackClient(String apiKey, Security security) {
    this(apiKey, security, null);
  }

  /**
   * Constructs a client using custom {@link FsService}. For internal use.
   *
   * @param apiKey    account key from the dev portal
   * @param security  configured security object
   * @param fsService service to use for API calls, overrides default singleton
   */
  public FilestackClient(String apiKey, Security security, FsService fsService) {
    this.apiKey = apiKey;
    this.security = security;
    this.fsService = fsService != null ? fsService : new FsService();
  }

  /**
   * Uploads local file using default storage options.
   *
   * @see #upload(String, boolean, StorageOptions)
   */
  public FileLink upload(String path, boolean intelligent)
      throws ValidationException, IOException, PolicySignatureException,
      InvalidParameterException, InternalException {
    return upload(path, intelligent, null);
  }

  /**
   * Uploads local file.
   *
   * @param path        path to the file, can be local or absolute
   * @param options     storage options, https://www.filestack.com/docs/rest-api/store
   * @param intelligent intelligent ingestion, setting to true to will decrease failures in very
   *                    poor network conditions at the expense of upload speed
   * @return new {@link FileLink} referencing file
   * @throws ValidationException       if the pathname doesn't exist or isn't a regular file
   * @throws IOException               if request fails because of network or other IO issue
   * @throws PolicySignatureException  if security is missing or invalid
   * @throws InvalidParameterException if a request parameter is missing or invalid
   * @throws InternalException         if unexpected error occurs
   */
  public FileLink upload(String path, boolean intelligent, StorageOptions options)
      throws ValidationException, IOException, PolicySignatureException,
             InvalidParameterException, InternalException {

    try {
      return uploadAsync(path, intelligent, options).blockingLast().getData();
    } catch (RuntimeException e) {
      try {
        Util.castExceptionAndThrow(e.getCause());
      } catch (ResourceNotFoundException ee) {
        // Shouldn't get a 404 so if we do, indicate an unexpected error
        throw new InternalException(ee);
      }
    }

    return null;
  }

  /**
   * Asynchronously uploads local file using default storage options.
   *
   * @see #upload(String, boolean, StorageOptions)
   * @see #uploadAsync(String, boolean, StorageOptions)
   */
  public Flowable<Progress<FileLink>> uploadAsync(String path, boolean intelligent) {
    return uploadAsync(path, intelligent, null);
  }

  /**
   * Asynchronously uploads local file. A stream of {@link Progress} objects are emitted by the
   * returned {@link Flowable}. The final {@link Progress} object will return a new
   * {@link FileLink} from {@link Progress#getData()}. The upload is not done until
   * {@link Progress#getData()} returns non-null.
   *
   * @see #upload(String, boolean, StorageOptions)
   */
  public Flowable<Progress<FileLink>> uploadAsync(String path, boolean intelligent,
                                                  StorageOptions options) {

    if (options == null) {
      options = new StorageOptions();
    }

    if (!options.hasContentType()) {
      String contentType = guessContentType(path);
      options = options.newBuilder().contentType(contentType).build();
    }

    Upload upload = new Upload(path, intelligent, options, this, fsService);
    return upload.runAsync();
  }

  /**
   * Creates an {@link ImageTransform} object for this file. A transformation call isn't made
   * directly by this method.
   *
   * @return {@link ImageTransform ImageTransform} instance configured for this file
   */
  public ImageTransform imageTransform(String url) {
    return new ImageTransform(this, url);
  }

  protected static String guessContentType(String path) {
    return "application/octet-stream";
  }

  public String getApiKey() {
    return apiKey;
  }

  public Security getSecurity() {
    return security;
  }

  public FsService getFsService() {
    return fsService;
  }
}

@@ -21,268 +21,8 @@
 k;%0A%0A
-import com.filestack.errors.InternalException;%0Aimport com.filestack.errors.InvalidParameterException;%0Aimport com.filestack.errors.PolicySignatureException;%0Aimport com.filestack.errors.ResourceNotFoundException;%0Aimport com.filestack.errors.ValidationException;%0A
 impo
@@ -140,40 +140,8 @@
 ad;%0A
-import com.filestack.util.Util;%0A
 impo
@@ -1447,30 +1447,24 @@
 lligent)
-%0A     
  throws 
 Validati
@@ -1459,109 +1459,10 @@
 ows 
-ValidationException, IOException, PolicySignatureException,%0A      InvalidParameterException, Internal
+IO
 Exce
@@ -1952,403 +1952,136 @@
 ows 
-ValidationException       if the pathname doesn't exist or isn't a regular file%0A   * @throws IOException               if request fails because of network or other IO issue%0A   * @throws PolicySignatureException  if security is missing or invalid%0A   * @throws InvalidParameterException if a request parameter is missing or invalid%0A   * @throws InternalException         if unexpected error occurs
+HttpResponseException on error response from backend%0A   * @throws IOException           on error reading file or network failure
 %0A   
@@ -2183,116 +2183,10 @@
 ows 
-ValidationException, IOException, PolicySignatureException,%0A             InvalidParameterException, Internal
+IO
 Exce
@@ -2329,255 +2329,46 @@
    t
-ry %7B%0A        Util.castExceptionAndThrow(e.getCause());%0A      %7D catch (ResourceNotFoundException ee) %7B%0A        // Shouldn't get a 404 so if we do, indicate an unexpected error%0A        throw new InternalException(ee
+hrow (IOException) e.getCause(
 );%0A    
-  %7D%0A    %7D%0A%0A    return null;
+%7D
 %0A  %7D

Update FilestackClient for simplified exceptions