import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.SimpleAttributeSet;

import org.apache.log4j.Layout;
import org.apache.log4j.WriterAppender;
import org.apache.log4j.helpers.LogLog;

/**
 * @author ADolgarev
 * Log4j Appender for TextPane
 * 
 * Initialization of this appender
 * in log4j.properties:
 * log4j.appender.textPaneAppender=o2.TextPaneAppender
 * log4j.appender.textPaneAppender.layout=<I>layout</I>..
 * in GUI class:
 * Logger log = Logger.getLogger(<I>class</I>);
 * ((TextPaneAppender) log.getAppender("textPaneAppender")).getTextPaneOutStream().setTextPane(<I>JTextPane</I>);
 */
public class TextPaneAppender extends WriterAppender {
	private TextPaneOutStream textPaneOutStream = null;

	/**
	 * @author ADolgarev
	 * OutputStream that writes messages to the document of JTextPane
	 */
	public static class TextPaneOutStream extends OutputStream {
		private JTextPane textPane = null;
		private StringBuffer buf = new StringBuffer();

		Timer timer;

		public TextPaneOutStream() {
			super();

			timer = new Timer();
			TimerTask flush = new TimerTask() {
				
				public void run() {
					
					synchronized (buf) {
						if (textPane == null || buf.length() == 0)
							return;
					}
					
					try {
						Document document = textPane.getDocument();

						synchronized (buf) {
							document.insertString(document.getLength(), buf.toString(), new SimpleAttributeSet());
							buf = new StringBuffer();
						}
						textPane.setCaretPosition(document.getLength());
					} catch (BadLocationException e) {
						LogLog.warn(e.getMessage());
					}
				}
			};
			
			timer.schedule(flush, 0, 200);
		}

		public JTextPane getTextPane() {
			return textPane;
		}

		public void setTextPane(JTextPane textPane) {
			this.textPane = textPane;
		}

		public void close() {
		}

		public void flush() {
			/*try {
				Document document = textPane.getDocument();
				document.insertString(document.getLength(), buf.toString(), new SimpleAttributeSet());
				buf = new StringBuffer();
				textPane.setCaretPosition(document.getLength());
			} catch (BadLocationException e) {
				LogLog.warn(e.getMessage());
			}*/
		}

		public void write(byte b[]) throws IOException {
			write(new String(b));
		}

		public void write(byte b[], int off, int len) throws IOException {
			write(new String(b).substring(off, off+len));
		}

		public void write(int b) throws IOException {
			write(String.valueOf(b));
		}
		
		public void write(String str) {

			synchronized (buf) {
				buf.append(str);
			}
		}
	}

	public TextPaneOutStream getTextPaneOutStream() {
		if (textPaneOutStream == null)
			textPaneOutStream = new TextPaneOutStream();
		return textPaneOutStream;
	}

	public TextPaneAppender() {
		super();
		setWriter(createWriter(getTextPaneOutStream()));
		super.activateOptions();
	}

	public TextPaneAppender(Layout layout) {
		super();
		setLayout(layout);
		setWriter(createWriter(getTextPaneOutStream()));
		super.activateOptions();
	}
}
