/*
 * Copyright 2012 Metamarkets Group Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.metamx.emitter.core;

/**
 */

import com.fasterxml.jackson.databind.ObjectMapper;
import com.metamx.common.lifecycle.LifecycleStart;
import com.metamx.common.lifecycle.LifecycleStop;
import com.metamx.common.logger.Logger;

import java.io.IOException;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 */
public class LoggingEmitter implements Emitter
{
  private final Logger log;
  private final Level level;
  private final ObjectMapper jsonMapper;

  private final AtomicBoolean started = new AtomicBoolean(false);

  public LoggingEmitter(LoggingEmitterConfig config, ObjectMapper jsonMapper)
  {
    this(new Logger(config.getLoggerClass()), Level.toLevel(config.getLogLevel()), jsonMapper);
  }

  public LoggingEmitter(Logger log, Level level, ObjectMapper jsonMapper)
  {
    this.log = log;
    this.level = level;
    this.jsonMapper = jsonMapper;
  }

  @Override
  @LifecycleStart
  public void start()
  {
    final boolean alreadyStarted = started.getAndSet(true);
    if (!alreadyStarted) {
      final String message = "Start: started [%s]";
      switch (level) {
        case TRACE:
          if (log.isTraceEnabled()) {
            log.trace(message, started.get());
          }
          break;
        case DEBUG:
          if (log.isDebugEnabled()) {
            log.debug(message, started.get());
          }
          break;
        case INFO:
          if (log.isInfoEnabled()) {
            log.info(message, started.get());
          }
          break;
        case WARN:
          log.warn(message, started.get());
          break;
        case ERROR:
          log.error(message, started.get());
          break;
      }
    }
  }

  @Override
  public void emit(Event event)
  {
    synchronized (started) {
      if (!started.get()) {
        throw new RejectedExecutionException("Service not started.");
      }
    }
    try {
      final String message = "Event [%s]";
      switch (level) {
        case TRACE:
          if (log.isTraceEnabled()) {
            log.trace(message, jsonMapper.writeValueAsString(event));
          }
          break;
        case DEBUG:
          if (log.isDebugEnabled()) {
            log.debug(message, jsonMapper.writeValueAsString(event));
          }
          break;
        case INFO:
          if (log.isInfoEnabled()) {
            log.info(message, jsonMapper.writeValueAsString(event));
          }
          break;
        case WARN:
          log.warn(message, jsonMapper.writeValueAsString(event));
          break;
        case ERROR:
          log.error(message, jsonMapper.writeValueAsString(event));
          break;
      }
    } catch (Exception e) {
      log.warn("Failed to generate json", e);
    }
  }

  @Override
  public void flush() throws IOException
  {

  }

  @Override
  @LifecycleStop
  public void close() throws IOException
  {
    final boolean wasStarted = started.getAndSet(false);
    if (wasStarted) {
      final String message = "Close: started [%s]";
      switch (level) {
        case TRACE:
          if (log.isTraceEnabled()) {
            log.trace(message, started.get());
          }
          break;
        case DEBUG:
          if (log.isDebugEnabled()) {
            log.debug(message, started.get());
          }
          break;
        case INFO:
          if (log.isInfoEnabled()) {
            log.info(message, started.get());
          }
          break;
        case WARN:
          log.warn(message, started.get());
          break;
        case ERROR:
          log.error(message, started.get());
          break;
      }
    }
  }

  public enum Level {
    TRACE,
    DEBUG,
    INFO,
    WARN,
    ERROR;

    public static Level toLevel(String name)
    {
      return Level.valueOf(name.toUpperCase());
    }
  }
}

@@ -3329,16 +3329,19 @@
 og.warn(
+e, 
 %22Failed 
@@ -3357,19 +3357,16 @@
 te json%22
-, e
 );%0A    %7D

Fix LoggingEmitter json failure message