package mobi.monaca.framework;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import mobi.monaca.framework.util.MyLog;
import org.json.JSONObject;
/**
* URI that contains queryData as ArrayList and has script inserted html getter.
* also able to convert query containing uri into noQueryURI
*/
public class MonacaURI {
public static final String URL_ENCODE = "UTF-8";
private static final String TAG = MonacaURI.class.getSimpleName();
private URI originalUri;
private ArrayList<QueryParam> queryParamsArrayList;
private boolean hasUnusedFragment;
public MonacaURI(String url) {
try {
this.originalUri = new URI(url);
this.parseQuery();
hasUnusedFragment = (originalUri.getFragment() != null);
} catch (URISyntaxException e) {
MyLog.e(TAG, "URISyntacException! : " + url);
e.printStackTrace();
}
}
/**
* this is for processing fragment in push transition.
* Not checks whether there is a fragment. only unused fragment is checked
* @return
*/
public boolean hasUnusedFragment() {
return hasUnusedFragment;
}
/**
* getFragment and set this fragment USED.
* this is for processing fragment in push transition
* @return
*/
public String popFragment() {
if (hasUnusedFragment) {
hasUnusedFragment = false;
return originalUri.getFragment();
} else {
return null;
}
}
public static String buildUrlWithQuery(String baseUrl, JSONObject queryJson) {
if (queryJson == null || (queryJson != null && queryJson.length() == 0)) {
return baseUrl;
}
Iterator<?> iterator = queryJson.keys();
String newUrl = new String(baseUrl);
String key;
try {
if (new URI(baseUrl).getQuery() != null) {
// if already baseUrl has queryParams,url building starts with &
newUrl += "&";
} else {
newUrl += "?";
}
} catch (URISyntaxException e) {
return baseUrl;
}
while (iterator.hasNext()) {
key = (String)iterator.next();
try {
if (key != null && queryJson.isNull(key)) {
newUrl += URLEncoder.encode(key, URL_ENCODE).replace(".", "%2e") + "&";
} else if (key != null ) {
//URLEncoder.encode does not encode dot, so replace manually (String#replace(".", "%2e"))
newUrl += URLEncoder.encode(key, URL_ENCODE).replace(".", "%2e") + "="
+ URLEncoder.encode(queryJson.optString(key), URL_ENCODE).replace(".", "%2e") + "&";
}
} catch (UnsupportedEncodingException e) {
MyLog.e(TAG, e.getMessage());
}
}
// remove last &
newUrl = trimLastChar(newUrl);
return newUrl;
}
public String getOriginalUrl() {
return originalUri.toString();
}
public String getUrlWithoutOptions() {
if (originalUri.getRawQuery() == null && originalUri.getFragment() == null) {
return getOriginalUrl();
}else {
String url =originalUri.toString().replaceFirst("(#" + originalUri.getFragment() + ")$", "");
url = url.toString().replace("?" + originalUri.getRawQuery(), "");
return url;
}
}
public boolean hasQueryParams() {
return queryParamsArrayList != null && !queryParamsArrayList.isEmpty();
}
public static String trimLastChar(String target) {
StringBuffer sb = new StringBuffer(target);
sb.deleteCharAt(target.length() - 1);
target = sb.toString();
return target;
}
public static String removeSpecialChar(String target) {
String result;
result = target.replace("\\","\\\\").replace("\"", "\\\\\"").replace("\'", "\\\\\'").replace("/", "\\/").replace("}", "\\}");
MyLog.d(TAG, target);
MyLog.d(TAG, result);
return result;
}
public String getQueryParamsContainingHtml(String baseHtml) {
String paramsString;
paramsString = "<script type=\"text/javascript\">"
+ "window.monaca = window.monaca || {};"
+ "monaca.queryParams = monaca.queryParams || {";
for (QueryParam q : this.queryParamsArrayList) {
String script;
if (q.hasValue()) {
script = "\"" + removeSpecialChar(q.getDecodedKey()) + "\":" + "\"" + removeSpecialChar(q.getDecodedValue()) + "\",";
} else {
script = "\"" + removeSpecialChar(q.getDecodedKey()) + "\":" + "null,";
}
paramsString += script;
}
paramsString = trimLastChar(paramsString);
paramsString += "};</script>";
String targetHtml = new String(baseHtml);
Pattern pattern = Pattern.compile("<head.*?>", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(targetHtml);
if (matcher.find()) {
return matcher.replaceFirst(matcher.group() + paramsString);
}else {
return paramsString + targetHtml;
}
}
public void parseQuery() {
if (originalUri.getRawQuery() != null) {
String[] params = originalUri.getRawQuery().split("&");
queryParamsArrayList = new ArrayList<QueryParam>();
for (int i = 0; i < params.length; i++) {
QueryParam p = new QueryParam(params[i]);
if (!p.isEmpty()) {
queryParamsArrayList.add(p);
}
}
} else {
//MyLog.d(TAG, "noQuery");
queryParamsArrayList = null;
}
}
public class QueryParam {
private String key;
private String value;
public QueryParam(String baseParam) {
String[] keyAndValue = baseParam.split("=");
if (keyAndValue == null || keyAndValue.length < 2) {
this.key = baseParam;
this.value = null;
if (key.equals("")) {
key = null;
}
} else {
this.key = keyAndValue[0];
this.value = keyAndValue[1];
}
}
public boolean hasValue() {
return (value != null);
}
public boolean isEmpty() {
return (key == null && value == null);
}
public String getDecodedKey() {
try {
return URLDecoder.decode(key, MonacaURI.URL_ENCODE);
} catch (UnsupportedEncodingException e) {
return key;
}
}
public String getDecodedValue() {
try {
return URLDecoder.decode(value, MonacaURI.URL_ENCODE);
} catch (UnsupportedEncodingException e) {
return value;
}
}
}
}