class URISignatureHandler {

	public static String generateCompleteURI(String uriSignature,
			Map<String, String> specifiedParameters, boolean escapeParameters)
			throws URISignatureParsingException,
			URIGenerationFromSignatureException {
		StringBuilder completeURI = new StringBuilder(uriSignature);

		// no need to make any checks on the uriSignature - it is
		// already handled by extractPlaceholdersWithPositions() --
		// if something goes wrong a runtime exception will be thrown
		// during placeholder extraction
		LinkedHashMap<String, Integer> placeholdersWithPositions = extractPlaceholdersWithPositions(uriSignature);

		// check that the URI signature contains some placeholders
		if (placeholdersWithPositions.keySet().size() > 0) {
			Map<String, String> parameters;
			// some work will actually have to be done to replace placeholders
			// with real values;
			// check that the parameter map contains some values
			if (specifiedParameters == null || specifiedParameters.isEmpty()) {
				parameters = Collections.emptyMap();
			} else {
				parameters = specifiedParameters;
			}

			// the 'placeholders' linked list is guaranteed to be in the order
			// of occurrence of placeholders in the URI signature;
			// this will allow to traverse the URI signature and replace the
			// placeholders in the reverse order --
			// this way it is possible to use the indices of placeholders that
			// were already found during their extraction to
			// improve performance
			LinkedList<String> placeholders = new LinkedList<String>(
					placeholdersWithPositions.keySet());
			Collections.reverse(placeholders);
			Iterator<String> placeholdersIterator = placeholders.iterator();

			while (placeholdersIterator.hasNext()) {
				String placeholder = placeholdersIterator.next();
				int placeholderStartPos = placeholdersWithPositions
						.get(placeholder) - 1;
				int placeholderEndPos = placeholderStartPos
						+ placeholder.length() + 2;
				if (parameters.containsKey(placeholder)) {
					if (escapeParameters) {
						completeURI.replace(placeholderStartPos,
								placeholderEndPos, urlEncodeQuery(parameters
										.get(placeholder)));
					} else {
						completeURI.replace(placeholderStartPos,
								placeholderEndPos, parameters.get(placeholder));
					}
				} else {
					int qnPos = completeURI.lastIndexOf("?", placeholderStartPos);
 					int ampPos = completeURI.lastIndexOf("&", placeholderStartPos);
 					int slashPos = completeURI.lastIndexOf("/", placeholderStartPos);
 					int startParamPos = Math.max(qnPos, ampPos);
					if (startParamPos > -1 && startParamPos > slashPos) {
 						// We found an optional parameter, so delete all of it
 						if (qnPos > ampPos) {
 							// It might be the first or only parameter so delete carefully
 							if (placeholderEndPos >= (completeURI.length() - 1)) {
 								// No parameters
 								completeURI.replace(startParamPos, placeholderEndPos, "");
 							} else {
 								// Remove the & from the following parameter, not the ? that starts
 								completeURI.replace(startParamPos + 1, placeholderEndPos + 1, "");
 							}
						} else {
 							// Just delete the optional parameter in total
							completeURI.replace(startParamPos, placeholderEndPos, "");
 						}
 					} else {
 						throw new URIGenerationFromSignatureException(
 								"Parameter map does not contain a key/value for \""
 										+ placeholder + "\" mandatory placeholder");
 					}
				}
			}
		}
		/*
		 * else { NO PLACEHOLDERS, SO NOTHING TO REPLACE WITH REAL VALUES - JUST
		 * RETURN THE ORIGINAL 'uriSignature' }
		 */

		return (completeURI.toString());
	}

}