/*
 * Java
 *
 * Copyright 2018-2021 MicroEJ Corp. All rights reserved.
 * This library is provided in source code for use, modification and test, subject to license terms.
 * Any modification of the source code will break MicroEJ Corp. warranties on the whole library.
 */
package ej.util.message.basic;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

import ej.util.message.MessageBuilder;

/**
 * A basic message builder creates the messages following this pattern: <code>[category]:[LEVEL]=[id]</code> followed by
 * the arguments (if any) separated by spaces, then the full stack trace of a throwable (if any).
 */
public class BasicMessageBuilder implements MessageBuilder {

	/**
	 * An instance of BasicMessageBuilder.
	 */
	public static final BasicMessageBuilder INSTANCE = new BasicMessageBuilder();

	@Override
	public String buildMessage(char level, String category, int id) {
		StringBuilder messageBuilder = new StringBuilder();
		appendMessageInternal(messageBuilder, level, category, id);
		return messageBuilder.toString();
	}

	@Override
	public String buildMessage(char level, String category, int id, Object... arguments) {
		StringBuilder messageBuilder = new StringBuilder();
		appendMessageInternal(messageBuilder, level, category, id);
		appendArgumentsInternal(messageBuilder, arguments);
		return messageBuilder.toString();
	}

	@Override
	public String buildMessage(char level, String category, int id, Throwable t) {
		StringBuilder messageBuilder = new StringBuilder();
		appendMessageInternal(messageBuilder, level, category, id);
		appendThrowableInternal(messageBuilder, t);
		return messageBuilder.toString();
	}

	@Override
	public String buildMessage(char level, String category, int id, Throwable t, Object... arguments) {
		StringBuilder messageBuilder = new StringBuilder();
		appendMessageInternal(messageBuilder, level, category, id);
		appendArgumentsInternal(messageBuilder, arguments);
		appendThrowableInternal(messageBuilder, t);
		return messageBuilder.toString();
	}

	private StringBuilder appendMessageInternal(final StringBuilder messageBuilder, char level, String category,
			int id) {
		return messageBuilder.append(category).append(':').append(level).append('=').append(id);
	}

	private StringBuilder appendThrowableInternal(final StringBuilder messageBuilder, Throwable t) {
		messageBuilder.append('\n');
		ByteArrayOutputStream stream = new ByteArrayOutputStream();
		t.printStackTrace(new PrintStream(stream));
		messageBuilder.append(new String(stream.toByteArray()));
		return messageBuilder;
	}

	private StringBuilder appendArgumentsInternal(final StringBuilder messageBuilder, Object... arguments) {
		for (Object argument : arguments) {
			messageBuilder.append(' ').append(argument);
		}
		return messageBuilder;
	}
}
