package org.opensextant.xlayer;
import org.json.JSONException;
import org.json.JSONObject;
import org.opensextant.data.Geocoding;
import org.opensextant.data.Place;
import org.opensextant.extraction.TextMatch;
import org.opensextant.extractors.geo.PlaceCandidate;
import org.opensextant.extractors.xcoord.GeocoordMatch;
import org.opensextant.util.GeodeticUtility;
public class Transforms {
/**
* Convert JSON object for an annotation into a Xponents TextMatch instance.
* Parsing data from JSON/REST representations has very limited capability compared to
* using Java API for processing routines directly.
*
* @param data
* @return
* @throws JSONException
*/
public static TextMatch parseAnnotation(Object data) throws JSONException {
if (!(data instanceof JSONObject)) {
return null;
}
TextMatch m = null;
JSONObject a = (JSONObject) data;
String typ = a.getString("type");
switch (typ) {
case "place":
PlaceCandidate placeMatch = new PlaceCandidate();
Place geo = new Place();
placeMatch.setText(a.getString("text"));
Transforms.parseGeocoding(geo, a);
placeMatch.choose(geo);
m = placeMatch;
break;
case "coordinate":
GeocoordMatch coord = new GeocoordMatch();
Place coordLoc = new Place();
coord.setText(a.getString("text"));
Transforms.parseGeocoding(coordLoc, a);
coord.setLatLon(coordLoc);
coord.setMethod(coordLoc.getMethod());
/* TODO: GeocoordMatch needs to support setters for Geocoding here.
* missing reverse geo info
*
* cc, adm1
*
*/
m = coord;
break;
case "country":
PlaceCandidate countryMatch = new PlaceCandidate();
Place cc = new Place();
countryMatch.setText(a.getString("text"));
cc.setName(a.getString("text"));
cc.setCountryCode(a.getString("cc"));
countryMatch.isCountry = true;
countryMatch.choose(cc);
m = countryMatch;
break;
case "person":
m = new TextMatch();
m.setText(a.getString("text"));
break;
case "org":
m = new TextMatch();
m.setText(a.getString("text"));
break;
default:
throw new JSONException("Unknown Annotation");
}
m.setType(typ);
m.start = a.getInt("offset");
m.end = m.start + a.getInt("length");
return m;
}
/**
* Detect trivial 0,0 or 0.000, 0.000, etc. coordinates.
*
* @param y
* the y
* @param x
* the x
* @return true, if is valid non zero coordinate
*/
public static final boolean isValidNonZeroCoordinate(double y, double x) {
if (GeodeticUtility.validateCoordinate(y, x)) {
return (y != 0 && x != 0);
}
return false;
}
/**
* Given an existing JSON object, add geocoding metadata to it.
*
* @param geo
* @param node
* @throws JSONException
*/
public static final void createGeocoding(Geocoding geo, JSONObject node) throws JSONException {
if (geo.getCountryCode() != null) {
node.put("cc", geo.getCountryCode());
}
if (geo.getAdmin1() != null) {
node.put("adm1", geo.getAdmin1());
}
if (geo.getFeatureClass() != null) {
node.put("feat_class", geo.getFeatureClass());
node.put("feat_code", geo.getFeatureCode());
}
if (isValidNonZeroCoordinate(geo.getLatitude(), geo.getLongitude())) {
node.put("prec", geo.getPrecision());
node.put("lat", geo.getLatitude());
node.put("lon", geo.getLongitude());
}
if (geo.getMethod() != null) {
node.put("method", geo.getMethod());
}
if (geo.getAdminName() != null) {
node.put("adm1_name", geo.getAdminName());
}
}
/**
* Given a JSON object, parse fields relevant to the geocoding and populate that JSON data
*
* @param geo
* @param node
* @throws JSONException
*/
public static final void parseGeocoding(Place geo, JSONObject node) throws JSONException {
if (node.has("cc")) {
geo.setCountryCode(node.getString("cc"));
}
if (node.has("adm1")) {
geo.setAdmin1(node.getString("adm1"));
}
if (node.has("feat_class")) {
geo.setFeatureClass(node.getString("feat_class"));
}
if (node.has("feat_code")) {
geo.setFeatureCode(node.getString("feat_code"));
}
if (node.has("lat")) {
geo.setLatitude(node.getDouble("lat"));
geo.setLongitude(node.getDouble("lon"));
if (node.has("prec")) {
geo.setPrecision(node.getInt("prec"));
}
}
if (node.has("method")) {
geo.setMethod(node.getString("method"));
}
if (node.has("adm1_name")) {
geo.setAdminName("adm1_name");
}
}
}