package net.pdp7.v2f.core;

import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.google.common.net.UrlEscapers;

public class Router {

	public static final Pattern LIST_TABLE_PATTERN = Pattern.compile("^/([^/]*)/$");
	public static final Pattern DETAIL_TABLE_PATTERN = Pattern.compile("^/([^/]*)/([^/]*)/$");
	public static final Pattern FORM_INPUT_NAME_PATTERN = Pattern.compile("^([^/]*)/([^/]*)/([^/]*)$");

	protected final ListHandler listHandler;
	protected final DetailHandler detailHandler;

	public Router(ListHandler listHandler, DetailHandler detailHandler) {
		this.listHandler = listHandler;
		this.detailHandler = detailHandler;
	}

	protected Route findRoute(String pathInfo) throws RouteNotFoundException {
		Matcher tableMatcher = LIST_TABLE_PATTERN.matcher(pathInfo);
		if (tableMatcher.matches()) {
			return new ListTableRoute(tableMatcher.group(1));
		}
		Matcher detailMatcher = DETAIL_TABLE_PATTERN.matcher(pathInfo);
		if (detailMatcher.matches()) {
			return new DetailRoute(detailMatcher.group(1), detailMatcher.group(2));
		}
		throw new RouteNotFoundException("no route found for " + pathInfo);
	}

	public void route(HttpServletRequest request, HttpServletResponse response)
			throws RouteNotFoundException, IOException {
		findRoute(request.getPathInfo()).execute(request, response);
	}

	public String getDetailRoute(String table, String id) {
		return new DetailRoute(table, id).getPath();
	}
	
	public String getFormInputName(String table, String id, String column) {
		return table + "/" +UrlEscapers.urlFormParameterEscaper().escape(id) + "/" + column;
	}

	public static class FormInputName {
		public final String table;
		public final String id;
		public final String column;

		public FormInputName(String raw) {
			Matcher matcher = FORM_INPUT_NAME_PATTERN.matcher(raw);
			matcher.matches();
			table = matcher.group(1);
			id = matcher.group(2);
			column = matcher.group(3);
		}

		public static boolean booleanIsFormInputName(String raw) {
			return FORM_INPUT_NAME_PATTERN.matcher(raw).matches();
		}
	}
	
	protected abstract class Route {
		protected abstract void execute(HttpServletRequest request, HttpServletResponse response) throws IOException;
	}

	protected class ListTableRoute extends Route {
		public final String table;

		private ListTableRoute(String table) {
			this.table = table;
		}

		@Override
		protected void execute(HttpServletRequest request, HttpServletResponse response) throws IOException {
			listHandler.handle(table, request, response);
		}
	}

	protected class DetailRoute extends Route {
		public final String table;
		public final String id;

		protected DetailRoute(String table, String id) {
			this.table = table;
			this.id = id;
		}

		public String getPath() {
			return "/" + table + "/" + UrlEscapers.urlFormParameterEscaper().escape(id) + "/";
		}

		@Override
		protected void execute(HttpServletRequest request, HttpServletResponse response) throws IOException {
			detailHandler.handle(table, id, request, response);
		}
	}
	
	protected static class RouteNotFoundException extends RuntimeException {
		private RouteNotFoundException(String message) {
			super(message);
		}
	}
}

@@ -427,32 +427,39 @@
 pile(%22%5E/(%5B%5E/%5D*)/
+detail/
 (%5B%5E/%5D*)/$%22);%0A%09pu
@@ -2915,24 +2915,31 @@
 + table + %22/
+detail/
 %22 + UrlEscap

Move /table/id to /table/detail/id to make way for /table/new