/**
 * 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.core;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.concurrent.ExecutorService;

import org.junit.Test;

import ch.qos.logback.core.spi.LifeCycle;

public class ContextBaseTest {

  private InstrumentedLifeCycleManager lifeCycleManager =
      new InstrumentedLifeCycleManager();
  
  private InstrumentedContextBase context = 
      new InstrumentedContextBase(lifeCycleManager);

  @Test
  public void renameDefault() {
    context.setName(CoreConstants.DEFAULT_CONTEXT_NAME);
    context.setName("hello");
  }


  @Test
  public void idempotentNameTest() {
    context.setName("hello");
    context.setName("hello");
  }

  @Test
  public void renameTest() {
    context.setName("hello");
    try {
      context.setName("x");
      fail("renaming is not allowed");
    } catch (IllegalStateException ise) {
    }
  }

  @Test
  public void resetTest() {
    context.setName("hello");
    context.putProperty("keyA", "valA");
    context.putObject("keyA", "valA");
    assertEquals("valA", context.getProperty("keyA"));
    assertEquals("valA", context.getObject("keyA"));
    MockLifeCycleComponent component = new MockLifeCycleComponent();
    context.register(component);
    assertSame(component, lifeCycleManager.getLastComponent());
    context.reset();
    assertNull(context.getProperty("keyA"));
    assertNull(context.getObject("keyA"));
    assertTrue(lifeCycleManager.isReset());
  }

  @Test
  public void contextNameProperty() {
    assertNull(context.getProperty(CoreConstants.CONTEXT_NAME_KEY));
    String HELLO = "hello";
    context.setName(HELLO);
    assertEquals(HELLO, context.getProperty(CoreConstants.CONTEXT_NAME_KEY));
    // good to have a raw reference to the "CONTEXT_NAME" as most clients would
    // not go through CoreConstants
    assertEquals(HELLO, context.getProperty("CONTEXT_NAME"));
  }

  @Test
  public void executorServiceInitializationAndReset() throws Exception {
    // should create the executor service on the first call
    ExecutorService executorService = context.getExecutorService();
    assertNotNull(executorService);
    assertSame(context.lastExecutorService, executorService);
    // calling again (without reset) should return the existing executor service
    context.lastExecutorService = null;
    assertSame(executorService, context.getExecutorService());
    assertNull(context.lastExecutorService);
    // after a reset, the executor service should be shut down...
    context.reset();
    assertTrue(executorService.isTerminated());
    // ... and a subsequent request should create a new one
    ExecutorService nextExecutorService = context.getExecutorService();
    assertNotNull(executorService);
    assertNotSame(executorService, nextExecutorService);
  }
  
  private static class InstrumentedContextBase extends ContextBase {
  
    private final LifeCycleManager lifeCycleManager;
    private ExecutorService lastExecutorService;
    
    public InstrumentedContextBase(LifeCycleManager lifeCycleManager) {
      this.lifeCycleManager = lifeCycleManager;
    }
  
    @Override
    protected LifeCycleManager getLifeCycleManager() {
      return lifeCycleManager;
    }

    @Override
    protected ExecutorService newExecutorService() {
      lastExecutorService = super.newExecutorService();
      return lastExecutorService;
    }
    
  }

  private static class InstrumentedLifeCycleManager extends LifeCycleManager {
    
    private LifeCycle lastComponent;
    private boolean reset;
    
    @Override
    public void register(LifeCycle component) {
      lastComponent = component;
      super.register(component);
    }
    
    @Override
    public void reset() {
      reset = true;
      super.reset();
    }

    public LifeCycle getLastComponent() {
      return lastComponent;
    }

    public boolean isReset() {
      return reset;
    }
    
  }

}
