package de.ugoe.cs.util.console;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * Helper class to parse command strings and create parameters.
 * </p>
 * 
 * @author Steffen Herbold
 * @version 1.0
 */
public class CommandParser {

	/**
	 * <p>
	 * Name of the command.
	 * </p>
	 */
	private String commandName;

	/**
	 * <p>
	 * Parameters of the command as a {@link List}. The parameters can either be
	 * {@link String} or {@link String} arrays.
	 * </p>
	 */
	private List<Object> parameters;

	/**
	 * <p>
	 * Creates a new CommandParser.
	 * </p>
	 */
	public CommandParser() {
		commandName = "";
		parameters = new ArrayList<Object>();
	}

	/**
	 * <p>
	 * Returns the name of the command.
	 * </p>
	 * 
	 * @return name of the command
	 */
	public String getCommandName() {
		return commandName;
	}

	/**
	 * <p>
	 * Returns the {@link List} of parameters
	 * </p>
	 * 
	 * @return {@link List} of parameters that were parsed.
	 */
	public List<Object> getParameters() {
		return parameters;
	}

	/**
	 * <p>
	 * Parses a command after the following EBNF (mixed with natural language):
	 * </p>
	 * <code>
	 * &lt;command&gt; :=
	 * &lt;commandname&gt;&lt;whitespace&gt;{&lt;parameter&gt;}<br>
	 * &lt;commandname&gt; := String without whitespaces. Has to be a valid Java
	 * class name<br>
	 * &lt;parameter&gt; := &lt;string&gt;|&lt;stringarray&gt;<br>
	 * &lt;string&gt; :=
	 * &lt;stringwithoutwhitespaces&gt;|&lt;stringwithwhitespaces&gt;
	 * &lt;stringwithoutwhitespaces&gt; := a string without whitespaces<br>
	 * &lt;stringwithoutwhitespaces&gt; := a string, that can have whitespaces,
	 * but must be in double quotes<br>
	 * &lt;stringarray&gt; :=
	 * "["&lt;string&gt;{&lt;whitespace&gt;&lt;string&gt;"]"
	 * </code>
	 * 
	 * @param command
	 *            the command as a string
	 */
	public void parse(String command) {
		if (command == null || command.equals("")) {
			return;
		}
		String[] splitResult = command.split(" ");
		commandName = splitResult[0];
		char[] commandChars = command.substring(commandName.length())
				.toCharArray();
		boolean startParameter = true;
		boolean isArray = false;
		boolean startArrayparameter = false;
		boolean isString = false;
		int bufferPos = 0;
		char[] buffer = new char[1024];
		boolean quote = false;
		List<String> arrayBuffer = null;
		for (int i = 0; i < commandChars.length; i++) {
			if (i < commandChars.length && startParameter
					&& commandChars[i] == '[') {
				isArray = true;
				startArrayparameter = true;
				arrayBuffer = new ArrayList<String>();
				startParameter = false;
				i++; // skip [
			}
			if (i < commandChars.length && startParameter
					&& commandChars[i] == '\'') {
				isString = true;
				quote = true;
				startParameter = false;
				i++; // skip '
			}
			if (i < commandChars.length && startParameter
					&& !Character.isWhitespace(commandChars[i])) {
				isString = true;
				startParameter = false;
			}
			if (isArray) {
				if (i < commandChars.length && commandChars[i] == ']') {
					if (bufferPos > 0) {
						buffer[bufferPos] = '\0';
						arrayBuffer.add((new String(buffer)).trim());
					}
					parameters.add(arrayBuffer.toArray(new String[0]));
					isArray = false;
					isString = false;
					bufferPos = 0;
					buffer = new char[128];
					startArrayparameter = false;
					startParameter = true;
					i++; // skip ]
				}
				if (i < commandChars.length && startArrayparameter
						&& !Character.isWhitespace(commandChars[i])) {
					buffer = new char[128];
					bufferPos = 0;
					quote = commandChars[i] == '\'';
					if (quote) {
						i++; // skip '
					}
					startArrayparameter = false;
				}
				if (i < commandChars.length && quote && !startArrayparameter && commandChars[i] == '\'') {
					// end of parameter with '
					i++; // skip '
					startArrayparameter = true;
					buffer[bufferPos] = '\0';
					arrayBuffer.add((new String(buffer)).trim());
				}
				if (i < commandChars.length && !quote && !startArrayparameter
						&& Character.isWhitespace(commandChars[i])) {
					startArrayparameter = true;
					buffer[bufferPos] = '\0';
					arrayBuffer.add((new String(buffer)).trim());
				}
				if (i < commandChars.length && !startArrayparameter
						&& !startParameter) {
					buffer[bufferPos] = commandChars[i];
					bufferPos++;
				}
			}
			if (isString) {
				if ((quote && commandChars[i] == '\'')
						|| (!quote && Character.isWhitespace(commandChars[i]))) {
					// end of parameter with '
					if (quote) {
						i++; // skip '
					}
					if (bufferPos > 0) {
						buffer[bufferPos] = '\0';
					}
					parameters.add((new String(buffer).trim()));
					isArray = false;
					isString = false;
					bufferPos = 0;
					buffer = new char[128];
					startArrayparameter = false;
					startParameter = true;
				}
				if (!startParameter) {
					buffer[bufferPos] = commandChars[i];
					bufferPos++;
				}
			}
		}
		if (bufferPos > 0) {
			if (isArray) {
				//arrayBuffer.add((new String(buffer)).trim());
				parameters.add(arrayBuffer.toArray(new String[0]));
			}
			if (isString) {
				parameters.add((new String(buffer)).trim());
			}
		}
	}
}
