package de.ugoe.cs.util.console;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.logging.Level;

import de.ugoe.cs.util.console.listener.IErrorListener;
import de.ugoe.cs.util.console.listener.IExceptionListener;
import de.ugoe.cs.util.console.listener.IOutputListener;
import de.ugoe.cs.util.console.listener.ITraceListener;

/**
 * <p>
 * Implements a simple console observer that prints normal text to
 * {@code stdout}, errors to {@code stderr} and reads from {@code stdin}.
 * </p>
 * 
 * @author Steffen Herbold
 * @version 1.0
 */
public class TextConsole implements IOutputListener, IErrorListener,
		ITraceListener, IExceptionListener {

	/**
	 * <p>
	 * In the debug mode, trace messages will be printed.
	 * </p>
	 */
	private boolean debugMode = true;

	/**
	 * <p>
	 * Creates a new text console and automatically registers it as observer.
	 * </p>
	 */
	public TextConsole() {
		Console.getInstance().registerOutputListener(this);
		Console.getInstance().registerErrorListener(this);
		Console.getInstance().registerTraceListener(this);
		Console.getInstance().registerExceptionListener(this);
	}

	/**
	 * <p>
	 * Prints messages to {@code stdout}.
	 * </p>
	 * 
	 * @see ConsoleObserver#outputMsg(java.lang.String)
	 */
	public void outputMsg(String newMessage) {
		System.out.print(newMessage);
	}

	/**
	 * <p>
	 * Prints messages to {@code stderr}.
	 * </p>
	 * 
	 * @see ConsoleObserver#errorMsg(String)
	 */
	@Override
	public void errorMsg(String errMessage) {
		System.err.print(errMessage);
	}

	/**
	 * <p>
	 * Prints the stacktrace of an exception to {@code stderr}.
	 * </p>
	 * 
	 * @see ConsoleObserver#logException(Exception)
	 */
	@Override
	public void logException(Exception e) {
		System.err.println(e.getMessage());
	}

	/**
	 * <p>
	 * Prints messages to {@code stdout}. These messages are only printed, if
	 * the console is run in debug mode.
	 * </p>
	 */
	@Override
	public void traceMsg(String traceMessage, Level level) {
		if (debugMode) {
			System.out.print("[" + level.toString() + "] " + traceMessage);
		}
	}

	/**
	 * <p>
	 * Starts a new TextConsole. If the text console is started, it can be used
	 * not only to print message, but also to execute commands by reading
	 * {@code stdin}.
	 * </p>
	 * 
	 * @param debugMode
	 *            true, if the application is to run in debug mode, i.e. trace
	 *            messages will be printed
	 */
	public void run(boolean debugMode) {
		this.debugMode = debugMode;
		CommandExecuter exec = CommandExecuter.getInstance();
		while (true) {
			System.out.print("> ");
			String command = getCommand().trim();
			if (!command.equals("")) {
				exec.exec(command);
			}
		}
	}

	/**
	 * <p>
	 * Reads a new command from {@code stdin}.
	 * </p>
	 * 
	 * @return a string with a command
	 */
	protected String getCommand() {
		byte[] buffer = new byte[1024];
		int bytesRead = 0;
		String command;
		try {
			bytesRead = System.in.read(buffer);
		} catch (IOException e) {

		}
		if (bytesRead == 0) {
			command = "";
		} else {
			command = new String(buffer, Charset.defaultCharset());
		}
		return command;
	}

	/**
	 * <p>
	 * Configures if the debug mode of the text console is enabled.
	 * </p>
	 * 
	 * @param debug
	 *            if true, debug mode is enabled.
	 */
	public void setDebug(boolean debug) {
		debugMode = debug;
	}

}
