package eu.dnetlib.functionality.modular.ui.utils;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;

import com.google.common.base.Joiner;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Queues;

public class LogUiAppender extends AppenderSkeleton {

	public static final int MAX_LOGS_IN_QUEUE = 2000;

	private final LinkedBlockingQueue<LogLine> logQueue = Queues.newLinkedBlockingQueue(MAX_LOGS_IN_QUEUE);

	private int count = 0;

	private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	@Override
	protected void append(final LoggingEvent event) {
		synchronized (logQueue) {
			if (logQueue.remainingCapacity() == 0) {
				logQueue.poll();
			}
			try {
				final String date = dateFormat.format(new Date(event.getTimeStamp()));

				final String[] arr = event.getThrowableStrRep();
				final String strace = arr != null && arr.length > 0 ? Joiner.on("\n").join(arr) : "";

				logQueue.put(new LogLine(count++, event.getLevel().toString(), event.getLoggerName(), date, event.getRenderedMessage(), strace));
			} catch (InterruptedException e) {
				throw new RuntimeException(e);
			}
		}
	}

	public List<LogLine> tail_N(final int n) throws Exception {
		synchronized (logQueue) {
			int qSize = logQueue.size();

			if (n <= 0 || qSize == 0) {
				return Lists.newArrayList();
			} else if (n < qSize) {
				return Lists.newArrayList(logQueue).subList(qSize - n, qSize);
			} else {
				return Lists.newArrayList(logQueue);
			}
		}
	}

	public List<LogLine> tail_continue(final int after) throws Exception {
		synchronized (logQueue) {
			return Lists.newArrayList(Iterables.filter(logQueue, new Predicate<LogLine>() {

				@Override
				public boolean apply(final LogLine ll) {
					return ll.getId() > after;
				}
			}));
		}
	}

	@Override
	public void close() {}

	@Override
	public boolean requiresLayout() {
		return false;
	}

}
