package org.jboss.resteasy.client.jaxrs;

import java.security.KeyStore;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.core.Configuration;

import org.jboss.resteasy.spi.ResteasyProviderFactory;

/**
 * Abstraction for creating Clients.  Allows SSL configuration.  Uses Apache Http Client under
 * the covers.  If used with other ClientHttpEngines though, all configuration options are ignored.
 *
 * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
 * @version $Revision: 1 $
 */
public abstract class ResteasyClientBuilder extends ClientBuilder
{
   public enum HostnameVerificationPolicy {
      /**
       * Hostname verification is not done on the server's certificate
       */
      ANY,
      /**
       * Allows wildcards in subdomain names i.e. *.foo.com
       */
      WILDCARD,
      /**
       * CN must match hostname connecting to
       */
      STRICT
   }

   /**
    * Client properties to enable proxy. Proxy host property name (string).
    */
   public static final String PROPERTY_PROXY_HOST = "org.jboss.resteasy.jaxrs.client.proxy.host";
   /**
    * Proxy port property name (integer).
    */
   public static final String PROPERTY_PROXY_PORT = "org.jboss.resteasy.jaxrs.client.proxy.port";
   /**
    * Proxy scheme property name (string).
    */
   public static final String PROPERTY_PROXY_SCHEME = "org.jboss.resteasy.jaxrs.client.proxy.scheme";
   /**
    * Changing the providerFactory will wipe clean any registered components or properties.
    *
    * @param providerFactory provider factory
    * @return an updated client builder instance
    */
   public abstract ResteasyClientBuilder providerFactory(ResteasyProviderFactory providerFactory);

   public abstract ResteasyProviderFactory getProviderFactory();

   /**
    * If there is a connection pool, set the time to live in the pool.
    *
    * @param ttl time to live
    * @param unit the time unit of the ttl argument
    * @return an updated client builder instance
    */
   public abstract ResteasyClientBuilder connectionTTL(long ttl, TimeUnit unit);

   public abstract long getConnectionTTL(TimeUnit unit);

   /**
    * If connection pooling enabled, how many connections to pool per url?
    *
    * @param maxPooledPerRoute max pool size per url
    * @return an updated client builder instance
    */
   public abstract ResteasyClientBuilder maxPooledPerRoute(int maxPooledPerRoute);

   public abstract int getMaxPooledPerRoute();

   /**
    * If connection pooling is enabled, how long will we wait to get a connection?
    * @param timeout the timeout
    * @param unit the units the timeout is in
    * @return an updated client builder instance
    */
   public abstract ResteasyClientBuilder connectionCheckoutTimeout(long timeout, TimeUnit unit);

   public abstract long getConnectionCheckoutTimeout(TimeUnit unit);

   /**
    * Number of connections allowed to pool.
    *
    * @param connectionPoolSize connection pool size
    * @return an updated client builder instance
    */
   public abstract ResteasyClientBuilder connectionPoolSize(int connectionPoolSize);

   public abstract int getConnectionPoolSize();

   /**
    * Response stream is wrapped in a BufferedInputStream.  Default is 8192.  Value of 0 will not wrap it.
    * Value of -1 will use a SelfExpandingBufferedInputStream.
    *
    * @param size response buffer size
    * @return an updated client builder instance
    */
   public abstract ResteasyClientBuilder responseBufferSize(int size);

   public abstract int getResponseBufferSize();

   /**
    * Disable trust management and hostname verification.  <i>NOTE</i> this is a security
    * hole, so only set this option if you cannot or do not want to verify the identity of the
    * host you are communicating with.
    * @return an updated client builder instance
    */
   public abstract ResteasyClientBuilder disableTrustManager();

   public abstract boolean isTrustManagerDisabled();

   /**
    * When the user is not using a TrustManager (see disableTrustManager) and
    * does not define an SSLContext object but they want all defined trustStores
    * to use the TrustSelfSignedCertificates trust strategy set this value to true.
    *
    * @param b A value of true assigns trust strategy TrustSelfSignedCertificates
    *          to the trustStores.  A value of false assigns a null to the trust
    *          strategy. The default value is true in order to maintain backward
    *          compatibility.
    */
   public abstract void setIsTrustSelfSignedCertificates(boolean b);
   public abstract boolean isTrustSelfSignedCertificates();
   /**
    * SSL policy used to verify hostnames
    *
    * @param policy SSL policy
    * @return an updated client builder instance
    */
   public abstract ResteasyClientBuilder hostnameVerification(HostnameVerificationPolicy policy);

   public abstract HostnameVerificationPolicy getHostnameVerification();

   /**
    * Negates all ssl and connection specific configuration
    *
    * @param httpEngine http engine
    * @return an updated client builder instance
    */
   public abstract ResteasyClientBuilder httpEngine(ClientHttpEngine httpEngine);

   public abstract ClientHttpEngine getHttpEngine();

   public abstract ResteasyClientBuilder useAsyncHttpEngine();

   public abstract boolean isUseAsyncHttpEngine();

   /**
    * Adds a TLS/SSL SNI Host Name for authentication.
    *
    * @param sniHostNames host names
    * @return an updated client builder instance
    */
   public abstract ResteasyClientBuilder sniHostNames(String... sniHostNames);

   public abstract List<String> getSniHostNames();

   /**
    * Specify a default proxy.  Default port and schema will be used.
    *
    * @param hostname host name
    * @return an updated client builder instance
    */
   public abstract ResteasyClientBuilder defaultProxy(String hostname);

   public abstract String getDefaultProxyHostname();

   public abstract int getDefaultProxyPort();

   public abstract String getDefaultProxyScheme();

   /**
    * Specify a default proxy host and port.  Default schema will be used.
    *
    * @param hostname host name
    * @param port port
    * @return an updated client builder instance
    */
   public abstract ResteasyClientBuilder defaultProxy(String hostname, int port);

   /**
    * Specify default proxy.
    *
    * @param hostname host name
    * @param port port
    * @param scheme scheme
    * @return an updated client builder instance
    */
   public abstract ResteasyClientBuilder defaultProxy(String hostname, int port, String scheme);

   /**
    * Enable state (cookie) management.
    *
    * @return the updated client builder instance
    */
   public abstract ResteasyClientBuilder enableCookieManagement();

   public abstract boolean isCookieManagementEnabled();

   public abstract SSLContext getSSLContext();

   public abstract KeyStore getKeyStore();

   public abstract String getKeyStorePassword();

   public abstract KeyStore getTrustStore();

   public abstract HostnameVerifier getHostnameVerifier();

   public abstract long getReadTimeout(TimeUnit unit);

   public abstract long getConnectionTimeout(TimeUnit unit);

   /**
    * boolean, notify apache to disable its automatic retries.
    */
   public abstract ResteasyClientBuilder disableAutomaticRetries();
   public abstract boolean isDisableAutomaticRetries();

   public abstract ResteasyClientBuilder executorService(ExecutorService executorService, boolean cleanupExecutor);

   @Override
   public abstract ResteasyClient build();

   @Override
   public abstract ResteasyClientBuilder withConfig(Configuration config);

   @Override
   public abstract ResteasyClientBuilder sslContext(SSLContext sslContext);

   @Override
   public abstract ResteasyClientBuilder keyStore(KeyStore keyStore, char[] password);

   @Override
   public abstract ResteasyClientBuilder keyStore(KeyStore keyStore, String password);

   @Override
   public abstract ResteasyClientBuilder trustStore(KeyStore trustStore);

   @Override
   public abstract ResteasyClientBuilder hostnameVerifier(HostnameVerifier verifier);

   @Override
   public abstract ResteasyClientBuilder executorService(ExecutorService executorService);

   @Override
   public abstract ResteasyClientBuilder scheduledExecutorService(ScheduledExecutorService scheduledExecutorService);

   @Override
   public abstract ResteasyClientBuilder connectTimeout(long timeout, TimeUnit unit);

   @Override
   public abstract ResteasyClientBuilder readTimeout(long timeout, TimeUnit unit);

   /**
    * Follow redirects added for MicroProfile-rest-client but can be used by
    * tradition clients as well.
    * @param followRedirects
    * @return
    */
   public abstract ResteasyClientBuilder setFollowRedirects(boolean followRedirects);

   public abstract boolean isFollowRedirects();
}
