//   Copyright 2012 Georg-August-Universität Göttingen, Germany
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

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>Defines the trace level used by this console.</p>
	 */
	private Level traceLevel;
	
	/**
         * <p>
         * Creates a new text console and automatically registers it as observer. The trace level is {@link Level#WARNING}.
         * </p>
	 */
	public TextConsole() {
	    this(Level.WARNING);
	}

	/**
	 * <p>
	 * Creates a new text console and automatically registers it as observer.
	 * </p>
	 * @param traceLevel trace level used by this text console
	 */
	public TextConsole(Level traceLevel) {
		Console.getInstance().registerOutputListener(this);
		Console.getInstance().registerErrorListener(this);
		Console.getInstance().registerTraceListener(this);
		Console.getInstance().registerExceptionListener(this);
		this.traceLevel = traceLevel;
	}

	/**
	 * <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 (level.intValue()>=traceLevel.intValue()) {
			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>
	 */
	public void run() {
		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;
	}

}
