import java.util.Stack;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

/*
 * vim: set tabstop=4:
 *
 * this sucker uses standard java elements to transform a relative path or url
 * into an absolute one
 *
 */

class AbsUrl {

	public static void main(String[] args) throws Exception {
	/*
	 * tests the output of absoluteUrl
	 */

		String[][] paths = {
			// { from, to, expected result }
			{"/file.ext", "/", "/"},
			{"/dir1/file.ext", "..", "/"},
			{"/dir1/file.ext", "/file2.ext", "/file2.ext"},
			{"/dir1/dir2/file.ext", "..", "/dir1"},
			{"/dir1/dir2/file.ext", "../file2.ext", "/dir1/file2.ext"},
			{"/dir1/file.ext", "file2.ext", "/dir1/file2.ext"},
			{"/dir1/", "..", "/"},
			{"/dir1", "..", "/"},
			{"/dir1/", "./../", "/"},
			{"/dir1", "dir2/../", "/dir1"},
			{"/dir1/", "dir2/../", "/dir1"},
			{"/dir1/file.ext", "dir2", "/dir1/dir2"}
		};

		String from, to, expected, answer;

		for (int i = 0; i < paths.length; i++){
			from = paths[i][0]; to = paths[i][1]; expected = paths[i][2];
			System.out.print(i + ": " + from + " + " + to + " = \"" + expected + "\"... ");
			answer = absoluteUrl(from, to);
			if (answer.equals(expected) == false)
				System.out.print("NO (" + answer + ")\n");
			else
				System.out.print("OK\n");

		}

	}

	public static String absoluteUrl(String from, String to) throws Exception {
	/*
	 * returns the absolute path of the two combined, or null should the path be illegal
	 * NOTES:
	 * "from" should be a canonical, absolute path that starts with /
	 * "to" can be a relative or absolute path from "from"
	 */

		String URL_SEP = "/";
		Stack st = new Stack();
		String[] froms;
		String[] tos = to.split(URL_SEP);
		StringBuffer sb = new StringBuffer();
		String filename = null;
		int i;

		// if the "to" path is absolute, discard entire "from" path
		if (to.startsWith(URL_SEP) == false){

			// try to discern whether "from" ends in a file or directory
			if (from.endsWith(URL_SEP) == false){	// else assume dir
				Pattern pat = Pattern.compile("(([^/]+)\\.([a-z]{3,4}))$");
				Matcher matcher = pat.matcher(from);
				// does "from" end with something that looks like a filename?
				if (matcher.find())					
					filename = matcher.group(0);
			}

			// push parts of path onto stack
			froms = from.split(URL_SEP);
			for (i = 0; i < froms.length; i++)
				if (froms[i].length() > 0)
					st.push(new String(froms[i]));

		}

		// iterate over the "to" path
		for (i = 0; i < tos.length; i++){
			// if filename, ditch it before adding path
			if (st.size() > 0 && i == 0 && filename != null) 
				st.pop();

			if (tos[i].length() == 0){		// double slashes
				// do nothing
			} else if (tos[i].equals(".")){	// refers to self
				// do nothing
			} else if (tos[i].equals("..")){// go back one
				if (st.size() == 0){
 					// stack is empty... illegal path!
					return null;
				} else {
					st.pop();
				}
			} else {
				// add path
				st.push(new String(tos[i]));
			}
		}

		// return a single "/" if we end up with nothing
		if (st.size() == 0)
			return URL_SEP;

		while (st.size() > 0)
			sb.insert(0, URL_SEP + st.pop().toString());

		return sb.toString();

	}

}


