package org.knowm.xchange;

import org.knowm.xchange.exceptions.ExchangeException;
import org.knowm.xchange.utils.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>
 * Factory to provide the following to {@link Exchange}:
 * </p>
 * <ul>
 * <li>Manages the creation of specific Exchange implementations using runtime dependencies</li>
 * </ul>
 */
public enum ExchangeFactory {

  INSTANCE;

  // flags
  private final Logger log = LoggerFactory.getLogger(ExchangeFactory.class);

  /**
   * Constructor
   */
  private ExchangeFactory() {

  }

  /**
   * Create an Exchange object.
   * <p>
   * The factory is parameterised with the name of the exchange implementation class. This must be a class extending
   * {@link org.knowm.xchange.Exchange}.
   * </p>
   * 
   * @param exchangeClassName the fully-qualified class name of the exchange
   * @return a new exchange instance configured with the default {@link org.knowm.xchange.ExchangeSpecification}
   */
  public Exchange createExchange(String exchangeClassName) {

    Assert.notNull(exchangeClassName, "exchangeClassName cannot be null");

    log.debug("Creating default exchange from class name");

    // Attempt to create an instance of the exchange provider
    try {

      // Attempt to locate the exchange provider on the classpath
      Class exchangeProviderClass = Class.forName(exchangeClassName);

      // Test that the class implements Exchange
      if (Exchange.class.isAssignableFrom(exchangeProviderClass)) {
        // Instantiate through the default constructor and use the default exchange specification
        Exchange exchange = (Exchange) exchangeProviderClass.newInstance();
        exchange.applySpecification(exchange.getDefaultExchangeSpecification());
        return exchange;
      } else {
        throw new ExchangeException("Class '" + exchangeClassName + "' does not implement Exchange");
      }
    } catch (ClassNotFoundException e) {
      throw new ExchangeException("Problem creating Exchange (class not found)", e);
    } catch (InstantiationException e) {
      throw new ExchangeException("Problem creating Exchange (instantiation)", e);
    } catch (IllegalAccessException e) {
      throw new ExchangeException("Problem creating Exchange (illegal access)", e);
    }

    // Cannot be here due to exceptions

  }

  public Exchange createExchange(ExchangeSpecification exchangeSpecification) {

    Assert.notNull(exchangeSpecification, "exchangeSpecfication cannot be null");

    log.debug("Creating exchange from specification");

    String exchangeClassName = exchangeSpecification.getExchangeClassName();

    // Attempt to create an instance of the exchange provider
    try {

      // Attempt to locate the exchange provider on the classpath
      Class exchangeProviderClass = Class.forName(exchangeClassName);

      // Test that the class implements Exchange
      if (Exchange.class.isAssignableFrom(exchangeProviderClass)) {
        // Instantiate through the default constructor
        Exchange exchange = (Exchange) exchangeProviderClass.newInstance();
        exchange.applySpecification(exchangeSpecification);
        return exchange;
      } else {
        throw new ExchangeException("Class '" + exchangeClassName + "' does not implement Exchange");
      }
    } catch (ClassNotFoundException e) {
      throw new ExchangeException("Problem starting exchange provider (class not found)", e);
    } catch (InstantiationException e) {
      throw new ExchangeException("Problem starting exchange provider (instantiation)", e);
    } catch (IllegalAccessException e) {
      throw new ExchangeException("Problem starting exchange provider (illegal access)", e);
    }

    // Cannot be here due to exceptions

  }

}

@@ -601,17 +601,54 @@
 e object
-.
+ without default ExchangeSpecification
 %0A   * %3Cp
@@ -1051,16 +1051,36 @@
 Exchange
+WithoutSpecification
 (String 
@@ -1743,89 +1743,8 @@
 ();%0A
-        exchange.applySpecification(exchange.getDefaultExchangeSpecification());%0A
     
@@ -2263,32 +2263,32 @@
 s)%22, e);%0A    %7D%0A%0A
-
     // Cannot be
@@ -2317,16 +2317,849 @@
 s%0A%0A  %7D%0A%0A
+  /**%0A   * Create an Exchange object with default ExchangeSpecification%0A   * %3Cp%3E%0A   * The factory is parameterised with the name of the exchange implementation class. This must be a class extending%0A   * %7B@link org.knowm.xchange.Exchange%7D.%0A   * %3C/p%3E%0A   * %0A   * @param exchangeClassName the fully-qualified class name of the exchange%0A   * @return a new exchange instance configured with the default %7B@link org.knowm.xchange.ExchangeSpecification%7D%0A   */%0A  public Exchange createExchange(String exchangeClassName) %7B%0A%0A    Assert.notNull(exchangeClassName, %22exchangeClassName cannot be null%22);%0A%0A    log.debug(%22Creating default exchange from class name%22);%0A%0A    Exchange exchange = createExchangeWithoutSpecification(exchangeClassName);%0A    exchange.applySpecification(exchange.getDefaultExchangeSpecification());%0A    return exchange;%0A%0A  %7D%0A%0A
   public

allow creating of Exchange from String without applying default config