class VMCommandLine {

	@SuppressWarnings({"checkstyle:cyclomaticcomplexity", "npathcomplexity"})
	public static void splitOptionsAndParameters(String... optionDefinitions) {
		if (analyzed) {
			return;
		}

		final List<String> params = new ArrayList<>();
		final SortedMap<String, List<Object>> options = new TreeMap<>();
		String opt;

		// Analyze definitions
		final Map<String, OptionType> defs = new TreeMap<>();
		for (final String def : optionDefinitions) {
			if (def.endsWith("!")) { //$NON-NLS-1$
				opt = def.substring(0, def.length() - 1);
				defs.put(opt, OptionType.FLAG);
				registerOptionValue(options, opt, Boolean.FALSE, OptionType.FLAG);
			} else if (def.endsWith("+")) { //$NON-NLS-1$
				opt = def.substring(0, def.length() - 1);
				defs.put(opt, OptionType.AUTO_INCREMENTED);
				registerOptionValue(options, opt, Long.valueOf(0), OptionType.AUTO_INCREMENTED);
			} else if (def.endsWith("=b")) { //$NON-NLS-1$
				opt = def.substring(0, def.length() - 2);
				defs.put(opt, OptionType.MANDATORY_BOOLEAN);
			} else if (def.endsWith(":b")) { //$NON-NLS-1$
				opt = def.substring(0, def.length() - 2);
				defs.put(opt, OptionType.OPTIONAL_BOOLEAN);
			} else if (def.endsWith("=f")) { //$NON-NLS-1$
				opt = def.substring(0, def.length() - 2);
				defs.put(opt, OptionType.MANDATORY_FLOAT);
			} else if (def.endsWith(":f")) { //$NON-NLS-1$
				opt = def.substring(0, def.length() - 2);
				defs.put(opt, OptionType.OPTIONAL_FLOAT);
			} else if (def.endsWith("=i")) { //$NON-NLS-1$
				opt = def.substring(0, def.length() - 2);
				defs.put(opt, OptionType.MANDATORY_INTEGER);
			} else if (def.endsWith(":i")) { //$NON-NLS-1$
				opt = def.substring(0, def.length() - 2);
				defs.put(opt, OptionType.OPTIONAL_INTEGER);
			} else if (def.endsWith("=s")) { //$NON-NLS-1$
				opt = def.substring(0, def.length() - 2);
				defs.put(opt, OptionType.MANDATORY_STRING);
			} else if (def.endsWith(":s")) { //$NON-NLS-1$
				opt = def.substring(0, def.length() - 2);
				defs.put(opt, OptionType.OPTIONAL_STRING);
			} else {
				defs.put(def, OptionType.SIMPLE);
			}
		}

		int idx;
		String base;
		String nbase;
		String val;
		OptionType type;
		OptionType waitingValue = null;
		String valueOptionName = null;
		boolean allParameters = false;
		boolean success;

		for (final String param : commandLineParameters) {
			if (allParameters) {
				params.add(param);
				continue;
			}

			if (waitingValue != null && waitingValue.isMandatory()) {
				// Expect a value as the next parameter
				success = registerOptionValue(options, valueOptionName, param, waitingValue);
				waitingValue = null;
				valueOptionName = null;
				if (success) {
					continue;
				}
			}

			if ("--".equals(param)) { //$NON-NLS-1$
				if (waitingValue != null) {
					registerOptionValue(options, valueOptionName, null, waitingValue);
					waitingValue = null;
					valueOptionName = null;
				}
				allParameters = true;
				continue;
			} else if ((File.separatorChar != '/') && (param.startsWith("/"))) { //$NON-NLS-1$
				opt = param.substring(1);
			} else if (param.startsWith("--")) { //$NON-NLS-1$
				opt = param.substring(2);
			} else if (param.startsWith("-")) { //$NON-NLS-1$
				opt = param.substring(1);
			} else if (waitingValue != null) {
				success = registerOptionValue(options, valueOptionName, param, waitingValue);
				waitingValue = null;
				valueOptionName = null;
				if (!success) {
					params.add(param);
				}
				continue;
			} else {
				params.add(param);
				continue;
			}

			if (waitingValue != null) {
				success = registerOptionValue(options, valueOptionName, param, waitingValue);
				waitingValue = null;
				valueOptionName = null;
				if (success) {
					continue;
				}
			}

			idx = opt.indexOf('=');
			if (idx > 0) {
				base = opt.substring(0, idx);
				val = opt.substring(idx + 1);
			} else {
				base = opt;
				val = null;
			}

			nbase = null;
			type = defs.get(base);
			if (type == null && base.toLowerCase().startsWith("no")) { //$NON-NLS-1$
				nbase = base.substring(2);
				type = defs.get(nbase);
			}
			if (type != null) {
				switch (type) {
				case FLAG:
					if (nbase == null) {
						registerOptionValue(options, base, Boolean.TRUE, type);
					} else {
						registerOptionValue(options, nbase, Boolean.FALSE, type);
					}
					break;
				case MANDATORY_FLOAT:
				case MANDATORY_BOOLEAN:
				case MANDATORY_INTEGER:
				case MANDATORY_STRING:
				case OPTIONAL_FLOAT:
				case OPTIONAL_BOOLEAN:
				case OPTIONAL_INTEGER:
				case OPTIONAL_STRING:
					if (val != null) {
						registerOptionValue(options, base, val, type);
					} else {
						waitingValue = type;
						valueOptionName = base;
					}
					break;
					//$CASES-OMITTED$
				default:
					registerOptionValue(options, base, val, type);
				}
			} else {
				// Not a recognized option, assuming simple
				registerOptionValue(options, base, val, OptionType.SIMPLE);
			}
		}

		if (waitingValue != null && waitingValue.isMandatory()) {
			throw new IllegalStateException(Locale.getString("E2", valueOptionName)); //$NON-NLS-1$
		}

		commandLineParameters = new String[params.size()];
		params.toArray(commandLineParameters);
		params.clear();

		commandLineOptions = options;

		analyzed = true;
	}

	public  VMCommandLine(Class<?> classToLaunch, String... parameters);
	public  VMCommandLine(String classToLaunch, String... parameters);
	public  VMCommandLine(Class<?> classToLaunch, String[] optionDefinitions, String... parameters);
	public  VMCommandLine(String classToLaunch, String[] optionDefinitions, String... parameters);
	public  VMCommandLine();

}