package de.intarsys.tools.logging;

import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;

import de.intarsys.tools.event.AttributeChangedEvent;
import de.intarsys.tools.event.Event;
import de.intarsys.tools.event.EventDispatcher;
import de.intarsys.tools.event.EventType;
import de.intarsys.tools.event.INotificationListener;
import de.intarsys.tools.event.INotificationSupport;

public class MemoryLogHandler extends Handler implements INotificationSupport {

	private final static int DEFAULT_SIZE = 1000;

	private int size;

	private String id;

	private LogRecord buffer[];

	private int start, count;

	private EventDispatcher dispatcher = new EventDispatcher(this);

	public MemoryLogHandler() {
		init();
	}

	public MemoryLogHandler(String id, int size) {
		if (size <= 0) {
			throw new IllegalArgumentException();
		}
		this.size = size;
		this.id = id;
		init();
	}

	public void addNotificationListener(EventType type,
			INotificationListener listener) {
		dispatcher.addNotificationListener(type, listener);
	}

	public synchronized void clear() {
		buffer = new LogRecord[size];
		start = 0;
		count = 0;
		triggerChanged(null, null, null);
	}

	@Override
	public void close() throws SecurityException {
		buffer = null;
		setLevel(Level.OFF);
	}

	@Override
	public void flush() {
	}

	public String getId() {
		return id;
	}

	synchronized public LogRecord[] getLogRecords() {
		LogRecord[] result = new LogRecord[count];
		System.arraycopy(buffer, start, result, 0, count);
		return result;
	}

	synchronized public int getSize() {
		return size;
	}

	public String getString() {
		StringBuilder sb = new StringBuilder();
		LogRecord[] records = getLogRecords();
		for (int i = 0; i < records.length; i++) {
			LogRecord record = records[i];
			try {
				sb.append(getFormatter().format(record));
			} catch (Exception ex) {
				// 
			}
		}
		return sb.toString();
	}

	private void init() {
		setFormatter(new SimpleFormatter());
		size = DEFAULT_SIZE;
		buffer = new LogRecord[size];
		start = 0;
		count = 0;
	}

	@Override
	public synchronized void publish(LogRecord record) {
		if (!isLoggable(record)) {
			return;
		}
		int ix = (start + count) % buffer.length;
		buffer[ix] = record;
		if (count < buffer.length) {
			count++;
		} else {
			start++;
		}
		triggerChanged(null, null, record);
	}

	public void removeNotificationListener(EventType type,
			INotificationListener listener) {
		dispatcher.removeNotificationListener(type, listener);
	}

	public void setId(String id) {
		this.id = id;
	}

	synchronized public void setSize(int size) {
		// todo...
		this.size = size;
	}

	protected void triggerChanged(Object attribute, Object oldValue,
			Object newValue) {
		Event event = new AttributeChangedEvent(this, attribute, oldValue,
				newValue);
		triggerEvent(event);
	}

	protected void triggerEvent(Event event) {
		try {
			dispatcher.triggerEvent(event);
		} catch (RuntimeException e) {
			// ignore
		}
	}

}
