package ro.isdc.wro.model.resource.support;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ro.isdc.wro.WroRuntimeException;
import ro.isdc.wro.model.group.Inject;
import ro.isdc.wro.model.group.processor.Injector;


/**
 * Abstracts the configurable creation of the strategies. Responsible for configuration of a single strategy. If no
 * configured strategy is found, a default one is used.
 *
 * @author Alex Objelean
 * @created 17 Jun 2012
 * @since 1.4.7
 */
public abstract class AbstractConfigurableSingleStrategy<S, P>
    extends AbstractConfigurableStrategySupport<S, P> {
  private static final Logger LOG = LoggerFactory.getLogger(AbstractConfigurableSingleStrategy.class);
  @Inject
  private Injector injector;
  private S configuredStrategy;

  /**
   * The reeturned object will be injected (if injector is available) and will be cached, meaning that only the first
   * invocation of this method will instantiate a fresh strategy and any subsequent invocation will return the same
   * object.
   *
   * @return the strategy S whose alias is found configured in the properties. This method will never return null. If no
   *         alias is defined the default strategy will be returned. If an invalid alias is provided - a runtime
   *         exception will be thrown.
   */
  public final S getConfiguredStrategy() {
    if (configuredStrategy == null) {
      final String alias = getConfiguredValue();
      configuredStrategy = getDefaultStrategy();
      if (!StringUtils.isEmpty(alias)) {
        LOG.debug("configured alias: {}", alias);
        configuredStrategy = getStrategyForAlias(alias);
        if (configuredStrategy == null) {
          throw new WroRuntimeException("Invalid strategy alias provided: <" + alias + ">. Available aliases are: "
              + getAvailableAliases());
        }
      }
      // inject only when injector is available.
      if (injector != null) {
        injector.inject(configuredStrategy);
      }
      LOG.debug("using strategy: {}", configuredStrategy);
    }
    return configuredStrategy;
  }

  /**
   * @return the default strategy implementation to use when no key is configured is provided.
   */
  protected abstract S getDefaultStrategy();
}
