/*******************************************************************************
 * Copyright (c) 2015 MITRE
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License, Version 2.0 which
 * accompanies this distribution and is available at
 *    http://www.apache.org/licenses/LICENSE-2.0.txt
 ******************************************************************************/

package org.locationtech.spatial4j;

import com.carrotsearch.randomizedtesting.rules.TestRuleAdapter;
import org.slf4j.helpers.MessageFormatter;

import java.util.ArrayList;
import java.util.List;

/**
 * A utility logger for tests in which log statements are logged following
 * test failure only.  Add this to a JUnit based test class with a {@link org.junit.Rule}
 * annotation.
 */
public class TestLog extends TestRuleAdapter {

  //TODO does this need to be threadsafe (such as via thread-local state)?
  private static ArrayList<LogEntry> logStack = new ArrayList<>();
  private static final int MAX_LOGS = 1000;

  public static final TestLog instance = new TestLog();

  private TestLog() {}

  @Override
  protected void before() throws Throwable {
    logStack.clear();
  }

  @Override
  protected void afterAlways(List<Throwable> errors) throws Throwable {
    if (!errors.isEmpty())
      logThenClear();
  }

  private void logThenClear() {
    for (LogEntry entry : logStack) {
      System.out.println(MessageFormatter.arrayFormat(entry.msg, entry.args).getMessage());
    }
    logStack.clear();
  }

  public static void clear() {
    logStack.clear();
  }

  /**
   * Enqueues a log message with substitution arguments ala SLF4J (i.e. {} syntax).
   * If the test fails then it'll be logged then, otherwise it'll be forgotten.
   */
  public static void log(String msg, Object... args) {
    if (logStack.size() > MAX_LOGS) {
      throw new RuntimeException("Too many log statements: "+logStack.size() + " > "+MAX_LOGS);
    }
    LogEntry entry = new LogEntry();
    entry.msg = msg;
    entry.args = args;
    logStack.add(entry);
  }

  private static class LogEntry { String msg; Object[] args; }
}
