class StringResolver {

	public static String substVars(String val, Map props1, Map props2, List<String> propsToHide) throws IllegalArgumentException {

		StringBuffer sbuf = new StringBuffer();

		int i = 0;
		int j, k;

		while (true) {
			j = val.indexOf(DELIM_START, i);
			if (j == -1) {
				// no more variables
				if (i == 0) { // this is a simple string
					return val;
				} else { // add the tail string which contains no variables and return the result.
					sbuf.append(val.substring(i, val.length()));
					return sbuf.toString();
				}
			} else {
				sbuf.append(val.substring(i, j));
				k = indexOfDelimStop(val, j);
				if (k == -1) {
					throw new IllegalArgumentException('[' + val + "] has no closing brace. Opening brace at position [" + j + "]");
				} else {
					String expression = val.substring(j, k + DELIM_STOP_LEN);
					j += DELIM_START_LEN;
					String key = val.substring(j, k);
					if (key.contains(DELIM_START)) {
						key = substVars(key, props1, props2);
					}
					// first try in System properties
					String replacement = getSystemProperty(key, null);
					// then try props parameter
					if (replacement == null && props1 != null) {
						if (props1 instanceof Properties) {
							replacement = ((Properties) props1).getProperty(key);
						} else {
							Object replacementSource = props1.get(key);
							if (replacementSource != null) {
								replacement = replacementSource.toString();
							}
						}
					}
					if (replacement == null && props2 != null) {
						if (props2 instanceof Properties) {
							replacement = ((Properties) props2).getProperty(key);
						} else {
							Object replacementSource = props2.get(key);
							if (replacementSource != null) {
								replacement = replacementSource.toString();
							}
						}
					}

					if (replacement != null) {
						if (propsToHide != null && propsToHide.contains(key)) {
							replacement = Misc.hide(replacement);
						}
						// Do variable substitution on the replacement string
						// such that we can solve "Hello ${x1}" as "Hello p2"
						// the where the properties are
						// x1=${x2}
						// x2=p2
						if (!replacement.equals(expression)) {
							String recursiveReplacement = substVars(replacement, props1, props2);
							sbuf.append(recursiveReplacement);
						} else {
							sbuf.append(replacement);
						}
					}
					i = k + DELIM_STOP_LEN;
				}
			}
		}
	}

	public  StringResolver();

}