package io.myweb;
import android.content.Context;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import io.myweb.http.*;
import java.io.IOException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class Endpoint {
public static class Info {
private final Method method;
private final String uri;
private final Class implementingClass;
public Info(Method method, String uri, Class implementingClass) {
this.method = method;
this.uri = uri;
this.implementingClass = implementingClass;
}
public Method getMethod() {
return method;
}
public String getUri() {
return uri;
}
public Class getImplementingClass() {
return implementingClass;
}
}
private WebContext webContext;
public Endpoint(WebContext context) {
webContext = context;
}
public WebContext getWebContext() {
return webContext;
}
public String produces() {
return null;
}
public abstract Response invoke(String uri, Request request) throws HttpException, IOException;
protected String getServiceName() { // overriden in subclasses
return null;
}
protected Object getServiceObject() { // overriden in subclasses
return null;
}
protected Context getContext() {
return webContext.getContext();
}
protected abstract Pattern getPattern();
protected Matcher matcher(String uri) {
return getPattern().matcher(uri);
}
public boolean match(Method method, String uri) {
String urlNoQueryParams = urlNoQueryParams(uri);
Matcher m = matcher(urlNoQueryParams);
boolean matched = httpMethod().equals(method) && m.matches();
if (matched) {
Log.d("Endpoint", "matched path " + httpMethod() + " " + originalPath() + " (pattern: " + getPattern() + ") request: " + method + " " + uri);
// } else {
// Log.d("Endpoint", "not matched path " + httpMethod() + " " + originalPath() + " (pattern: " + getPattern() + ") request: " + method + " " + uri);
}
return matched;
}
protected abstract String originalPath();
protected abstract Method httpMethod();
protected ActualParam[] actualParams(String uri, Request request, FormalParam[] formalParams, Map<String, String> defaultQueryParams, Map<String, Integer> groupMap, Context ctx) throws HttpException {
String urlNoQueryParams = urlNoQueryParams(uri);
Map<String, String> paramsMap = request.getParameterMap();
Matcher m = matcher(urlNoQueryParams);
ActualParam[] actualParams = new ActualParam[formalParams.length];
if (m.matches()) {
for (FormalParam fp : formalParams) {
int fpId = fp.getId();
Class<?> fpClazz;
try {
fpClazz = classForName(fp.getTypeName());
} catch (ClassNotFoundException e) {
throw new HttpServiceUnavailableException(e.getMessage(), e);
}
String fpName = fp.getName();
if (fpName.equals(getServiceName())) {
actualParams[fpId] = new ActualParam(fpClazz, getServiceObject());
} else if (groupMap.containsKey(fpName)) {
int urlGroupIdx = groupMap.get(fpName);
String val = m.group(urlGroupIdx);
Object convertedVal = convert(val, fp.getTypeName());
actualParams[fpId] = new ActualParam(fpClazz, convertedVal);
} else if (Context.class.equals(fpClazz)) {
actualParams[fpId] = new ActualParam(Context.class, ctx);
} else if (Cookies.class.equals(fpClazz)){
actualParams[fpId] = new ActualParam(Cookies.class, request.getCookies());
} else if (Cookie.class.equals(fpClazz)) {
Cookie cookie = request.getCookies().getCookie(fpName);
actualParams[fpId] = new ActualParam(Cookie.class, cookie);
} else if (Headers.class.equals(fpClazz)) {
actualParams[fpId] = new ActualParam(Headers.class, request.getHeaders());
} else if (Request.class.equals(fpClazz)) {
actualParams[fpId] = new ActualParam(Request.class, request);
} else if (paramsMap.containsKey(fpName)) {
String val = paramsMap.get(fpName);
Object convertedVal = convert(val, fp.getTypeName());
actualParams[fpId] = new ActualParam(fpClazz, convertedVal);
} else if (defaultQueryParams.containsKey(fpName)) {
String val = defaultQueryParams.get(fpName);
Object convertedVal = convert(val, fp.getTypeName());
actualParams[fpId] = new ActualParam(fpClazz, convertedVal);
}
}
} else {
throw new HttpServiceUnavailableException("couldn't match URI: '" + uri + "' with pattern '" + getPattern() + "' (BTW, this shouldn't happen...)");
}
return actualParams;
}
protected String urlNoQueryParams(String url) {
int i = url.indexOf("?");
String result;
if (i == -1) {
result = url;
} else {
result = url.substring(0, i);
}
return result;
}
public static Object convert(String val, String typeName) {
if(!String.class.getName().equals(typeName)) {
try {
Object obj = new JSONTokener(val).nextValue();
if(obj.equals(JSONObject.NULL)) return null;
if(classForName(typeName).isAssignableFrom(obj.getClass())) return obj;
} catch (JSONException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
return val;
}
public static Class<?> classForName(String typeName) throws ClassNotFoundException {
if ("int".equals(typeName)) return Integer.class;
if ("long".equals(typeName)) return Long.class;
if ("float".equals(typeName)) return Float.class;
if ("double".equals(typeName)) return Double.class;
if ("boolean".equals(typeName)) return Boolean.class;
return Class.forName(typeName);
}
}