/**
 * Logback: the reliable, generic, fast and flexible logging framework.
 * Copyright (C) 1999-2013, QOS.ch. All rights reserved.
 *
 * This program and the accompanying materials are dual-licensed under
 * either the terms of the Eclipse Public License v1.0 as published by
 * the Eclipse Foundation
 *
 *   or (per the licensee's choosing)
 *
 * under the terms of the GNU Lesser General Public License version 2.1
 * as published by the Free Software Foundation.
 */
package ch.qos.logback.classic.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import ch.qos.logback.classic.ClassicConstants;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.selector.ContextJNDISelector;
import ch.qos.logback.classic.selector.ContextSelector;
import ch.qos.logback.classic.selector.DefaultContextSelector;
import ch.qos.logback.core.util.Loader;
import ch.qos.logback.core.util.OptionHelper;

/**
 * Holds the context selector for use in the current environment.
 * 
 * @author Ceki G&uuml;lc&uuml;
 * @since 0.9.19
 */
public class ContextSelectorStaticBinder {

  static ContextSelectorStaticBinder singleton = new ContextSelectorStaticBinder();

  ContextSelector contextSelector;
  Object key;
  
  public static ContextSelectorStaticBinder getSingleton() {
    return singleton;
  }

  /**
   * FOR INTERNAL USE. This method is intended for use by  StaticLoggerBinder.
   *  
   * @param defaultLoggerContext
   * @throws ClassNotFoundException
   * @throws NoSuchMethodException
   * @throws InstantiationException
   * @throws IllegalAccessException
   * @throws InvocationTargetException
   */
  public void init(LoggerContext defaultLoggerContext, Object key) throws ClassNotFoundException,
      NoSuchMethodException, InstantiationException, IllegalAccessException,
      InvocationTargetException  {
    if(this.key == null) {
      this.key = key;
    } else if (this.key != key) {
      throw new IllegalAccessException("Only certain classes can access this method.");
    }
    
    
    String contextSelectorStr = OptionHelper
        .getSystemProperty(ClassicConstants.LOGBACK_CONTEXT_SELECTOR);
    if (contextSelectorStr == null) {
      contextSelector = new DefaultContextSelector(defaultLoggerContext);
    } else if (contextSelectorStr.equals("JNDI")) {
      // if jndi is specified, let's use the appropriate class
      contextSelector = new ContextJNDISelector(defaultLoggerContext);
    } else {
      contextSelector = dynamicalContextSelector(defaultLoggerContext,
          contextSelectorStr);
    }
  }
  
  /**
   * Instantiate the context selector class designated by the user. The selector
   * must have a constructor taking a LoggerContext instance as an argument.
   * 
   * @param defaultLoggerContext
   * @param contextSelectorStr
   * @return an instance of the designated context selector class
   * @throws ClassNotFoundException
   * @throws SecurityException
   * @throws NoSuchMethodException
   * @throws IllegalArgumentException
   * @throws InstantiationException
   * @throws IllegalAccessException
   * @throws InvocationTargetException
   */
  static ContextSelector dynamicalContextSelector(
      LoggerContext defaultLoggerContext, String contextSelectorStr)
      throws ClassNotFoundException, SecurityException, NoSuchMethodException,
      IllegalArgumentException, InstantiationException, IllegalAccessException,
      InvocationTargetException {
    Class<?> contextSelectorClass = Loader.loadClass(contextSelectorStr);
    Constructor cons = contextSelectorClass
        .getConstructor(new Class[] { LoggerContext.class });
    return (ContextSelector) cons.newInstance(defaultLoggerContext);
  }
  
  public ContextSelector getContextSelector() {
    return contextSelector;
  }

}
