package common.log;

import java.io.PrintWriter;
import java.io.StringWriter;

import io.netty.util.internal.logging.AbstractInternalLogger;
import io.netty.util.internal.logging.FormattingTuple;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import io.netty.util.internal.logging.MessageFormatter;

public class NettyLogger extends AbstractInternalLogger {
	public static void init() {
		InternalLoggerFactory.setDefaultFactory(new InternalLoggerFactory() {
			protected InternalLogger newInstance(String name) {
				return new NettyLogger(name);
			}
		});
	}
	
	private NettyLogger(String name) {
		super(name);
	}

	public boolean isTraceEnabled() {
		return Log.getLevel().ordinal() >= LogLevel.TRACE.ordinal();
	}

	public void trace(String msg) {
		this.log(LogLevel.TRACE, msg, null);
	}

	public void trace(String format, Object arg) {
		FormattingTuple ft = MessageFormatter.format(format, arg);
		this.log(LogLevel.TRACE, ft.getMessage(), ft.getThrowable());
	}

	public void trace(String format, Object argA, Object argB) {
		FormattingTuple ft = MessageFormatter.format(format, argA, argB);
		this.log(LogLevel.TRACE, ft.getMessage(), ft.getThrowable());
	}

	public void trace(String format, Object... argArray) {
		FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
		this.log(LogLevel.TRACE, ft.getMessage(), ft.getThrowable());
	}

	public void trace(String msg, Throwable t) {
		this.log(LogLevel.TRACE, msg, t);
	}

	public boolean isDebugEnabled() {
		return Log.getLevel().ordinal() >= LogLevel.DEBUG.ordinal();
	}

	public void debug(String msg) {
		this.log(LogLevel.DEBUG, msg, null);
	}

	public void debug(String format, Object arg) {
		FormattingTuple ft = MessageFormatter.format(format, arg);
		this.log(LogLevel.DEBUG, ft.getMessage(), ft.getThrowable());
	}

	public void debug(String format, Object argA, Object argB) {
		FormattingTuple ft = MessageFormatter.format(format, argA, argB);
		this.log(LogLevel.DEBUG, ft.getMessage(), ft.getThrowable());
	}

	public void debug(String format, Object... argArray) {
		FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
		this.log(LogLevel.DEBUG, ft.getMessage(), ft.getThrowable());
	}

	public void debug(String msg, Throwable t) {
		this.log(LogLevel.DEBUG, msg, t);
	}

	public boolean isInfoEnabled() {
		return Log.getLevel().ordinal() >= LogLevel.INFO.ordinal();
	}

	public void info(String msg) {
		this.log(LogLevel.INFO, msg, null);
	}

	public void info(String format, Object arg) {
		FormattingTuple ft = MessageFormatter.format(format, arg);
		this.log(LogLevel.INFO, ft.getMessage(), ft.getThrowable());
	}

	public void info(String format, Object argA, Object argB) {
		FormattingTuple ft = MessageFormatter.format(format, argA, argB);
		this.log(LogLevel.INFO, ft.getMessage(), ft.getThrowable());
	}

	public void info(String format, Object... argArray) {
		FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
		this.log(LogLevel.INFO, ft.getMessage(), ft.getThrowable());
	}

	public void info(String msg, Throwable t) {
		this.log(LogLevel.INFO, msg, t);
	}

	public boolean isWarnEnabled() {
		return Log.getLevel().ordinal() >= LogLevel.WARN.ordinal();
	}

	public void warn(String msg) {
		this.log(LogLevel.WARN, msg, null);
	}

	public void warn(String format, Object arg) {
		FormattingTuple ft = MessageFormatter.format(format, arg);
		this.log(LogLevel.WARN, ft.getMessage(), ft.getThrowable());
	}

	public void warn(String format, Object argA, Object argB) {
		FormattingTuple ft = MessageFormatter.format(format, argA, argB);
		this.log(LogLevel.WARN, ft.getMessage(), ft.getThrowable());
	}

	public void warn(String format, Object... argArray) {
		FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
		this.log(LogLevel.WARN, ft.getMessage(), ft.getThrowable());
	}

	public void warn(String msg, Throwable t) {
		this.log(LogLevel.WARN, msg, t);
	}

	public boolean isErrorEnabled() {
		return Log.getLevel().ordinal() >= LogLevel.ERROR.ordinal();
	}

	public void error(String msg) {
		this.log(LogLevel.ERROR, msg, null);
	}

	public void error(String format, Object arg) {
		FormattingTuple ft = MessageFormatter.format(format, arg);
		this.log(LogLevel.ERROR, ft.getMessage(), ft.getThrowable());
	}

	public void error(String format, Object argA, Object argB) {
		FormattingTuple ft = MessageFormatter.format(format, argA, argB);
		this.log(LogLevel.ERROR, ft.getMessage(), ft.getThrowable());
	}

	public void error(String format, Object... arguments) {
		FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);
		this.log(LogLevel.ERROR, ft.getMessage(), ft.getThrowable());
	}

	public void error(String msg, Throwable t) {
		this.log(LogLevel.ERROR, msg, t);
	}

	private void log(LogLevel level, String msg, Throwable t) {
		Log.NETTY.log(level, msg);
		if(t != null) {
			StringWriter sw = new StringWriter();
			PrintWriter st = new PrintWriter(sw);
			t.printStackTrace(st);
			sw.flush();
			Log.NETTY.log(level, sw.toString().trim().replace('\t', ' '));
		}
	}
}
