package com.sk89q.mapquery;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import net.minidev.json.JSONValue;
import net.minidev.json.parser.ParseException;
/**
* Fast way to access {@link Map}s.
*/
public class MapQuery {
private static final String DELIMETER = "(?<!\\\\)\\.";
private static final Pattern ARRAY_SYNTAX = Pattern.compile("^([0-9]+)$");
private final Map<Object, Object> root;
public MapQuery() {
this(new HashMap<Object, Object>());
}
public MapQuery(Map<Object, Object> root) {
this.root = root;
}
public Object get(PathSegment... parts) {
Object parent = root;
for (int i = 0; i < parts.length; i++) {
Object v = parts[i].next(parent);
if (parts.length == i + 1) {
return v;
}
parent = v;
}
return null;
}
public PathSegment[] parsePath(String path) {
List<PathSegment> segments = new ArrayList<PathSegment>();
for (String token : path.split(DELIMETER)) {
token = token.replaceAll("\\\\", "");
Matcher m;
// Array access
m = ARRAY_SYNTAX.matcher(token);
if (m.matches()) {
segments.add(new ListAccessor(Integer.parseInt(m.group(1))));
} else {
segments.add(new MapAccessor(token));
}
}
PathSegment[] segmentsArr = new PathSegment[segments.size()];
segments.toArray(segmentsArr);
return segmentsArr;
}
public boolean containsPath(String path) {
return get(parsePath(path)) != null;
}
public Object get(String path) {
return get(parsePath(path));
}
public <T> T getOf(String path, Class<T> type) {
Object v = get(path);
if (v == null) {
return null;
}
if (type.isAssignableFrom(v.getClass())) {
return (T) v;
} else {
return null;
}
}
public String getString(String path) {
return getOf(path, String.class);
}
public Integer getInt(String path) {
return getOf(path, Integer.class);
}
public Long getLong(String path) {
return getOf(path, Long.class);
}
public Float getFloat(String path) {
return getOf(path, Float.class);
}
public Double getDouble(String path) {
return getOf(path, Double.class);
}
public MapQuery wrapMapQuery(String path) {
Map v = getOf(path, Map.class);
if (v == null) {
return new MapQuery();
}
return new MapQuery(v);
}
public static MapQuery fromJson(String data) throws IOException {
try {
Object value = JSONValue.parseWithException(data);
if (value instanceof Map) {
return new MapQuery((Map<Object, Object>) value);
} else {
throw new IOException("Provided JSON data is not an JSON object");
}
} catch (ParseException e) {
throw new IOException("Failed to JSON data", e);
}
}
public static MapQuery fromJsonApi(String data, String errorPath) throws IOException {
MapQuery query = fromJson(data);
Object errorString = query.get(errorPath);
if (errorString != null) {
throw new IOException("API provided an error: " + String.valueOf(errorString));
}
return query;
}
}